PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.2.8.4
Pods – Custom Content Types and Fields v3.2.8.4
2.7.31.4 2.8.23.5 2.9.19.5 3.0.10.5 3.1.4.3 3.2.8.4 3.3.9.2 2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / classes / PodsAdmin.php
pods / classes Last commit date
cli 2 days ago fields 2 days ago widgets 2 days ago Pods.php 2 days ago PodsAPI.php 2 days ago PodsAdmin.php 2 days ago PodsArray.php 2 days ago PodsComponent.php 2 days ago PodsComponents.php 2 days ago PodsData.php 2 days ago PodsField.php 2 days ago PodsForm.php 2 days ago PodsI18n.php 2 days ago PodsInit.php 2 days ago PodsMeta.php 2 days ago PodsMigrate.php 2 days ago PodsRESTFields.php 2 days ago PodsRESTHandlers.php 2 days ago PodsTermSplitting.php 2 days ago PodsUI.php 2 days ago PodsView.php 2 days ago
PodsAdmin.php
5048 lines
1 <?php
2
3 use Pods\Admin\Config\Pod as Config_Pod;
4 use Pods\Admin\Config\Group as Config_Group;
5 use Pods\Admin\Config\Field as Config_Field;
6 use Pods\Admin\Settings;
7 use Pods\Tools\Repair;
8 use Pods\Whatsit\Pod;
9
10 /**
11 * @package Pods
12 */
13 class PodsAdmin {
14
15 /**
16 * @var PodsAdmin
17 */
18 public static $instance = null;
19
20 /**
21 * Singleton handling for a basic pods_admin() request
22 *
23 * @return \PodsAdmin
24 *
25 * @since 2.3.5
26 */
27 public static function init() {
28
29 if ( ! is_object( self::$instance ) ) {
30 self::$instance = new PodsAdmin();
31 }
32
33 return self::$instance;
34 }
35
36 /**
37 * Setup and Handle Admin functionality
38 *
39 * @return \PodsAdmin
40 *
41 * @license http://www.gnu.org/licenses/gpl-2.0.html
42 * @since 2.0.0
43 */
44 public function __construct() {
45
46 // Scripts / Stylesheets
47 add_action( 'admin_enqueue_scripts', array( $this, 'admin_head' ), 20 );
48
49 // AJAX $_POST fix
50 add_action( 'admin_init', array( $this, 'admin_init' ), 9 );
51
52 // Menus
53 add_action( 'admin_menu', array( $this, 'admin_menu' ), 9 );
54
55 // AJAX for Admin
56 add_action( 'wp_ajax_pods_admin', [ $this, 'admin_ajax' ] );
57 add_action( 'wp_ajax_nopriv_pods_admin', array( $this, 'admin_ajax' ) );
58
59 // Add Media Bar button for Shortcode
60 add_action( 'media_buttons', array( $this, 'media_button' ), 12 );
61
62 // Add the Pods capabilities
63 add_filter( 'members_get_capabilities', array( $this, 'admin_capabilities' ) );
64
65 add_action( 'admin_head-media-upload-popup', array( $this, 'register_media_assets' ) );
66
67 // Add our debug to Site Info.
68 add_filter( 'debug_information', array( $this, 'add_debug_information' ) );
69
70 // Add our status tests.
71 add_filter( 'site_status_tests', [ $this, 'site_status_tests' ] );
72
73 $this->rest_admin();
74
75 }
76
77 /**
78 * Init the admin area
79 *
80 * @since 2.0.0
81 */
82 public function admin_init() {
83
84 // Fix for plugins that *don't do it right* so we don't cause issues for users
85 // @codingStandardsIgnoreLine
86 if ( defined( 'DOING_AJAX' ) && ! empty( $_POST ) ) {
87 $pods_admin_ajax_actions = array(
88 'pods_admin',
89 'pods_relationship',
90 'pods_upload',
91 'pods_admin_components',
92 );
93
94 /**
95 * Admin AJAX Callbacks
96 *
97 * @since unknown
98 *
99 * @param array $pods_admin_ajax_actions Array of actions to handle.
100 */
101 $pods_admin_ajax_actions = apply_filters( 'pods_admin_ajax_actions', $pods_admin_ajax_actions );
102
103 if ( in_array( pods_v( 'action' ), $pods_admin_ajax_actions, true ) || in_array( pods_v( 'action', 'post' ), $pods_admin_ajax_actions, true ) ) {
104 // @codingStandardsIgnoreLine
105 foreach ( $_POST as $key => $value ) {
106 if ( 'action' === $key || 0 === strpos( $key, '_podsfix_' ) ) {
107 continue;
108 }
109
110 // @codingStandardsIgnoreLine
111 unset( $_POST[ $key ] );
112
113 // @codingStandardsIgnoreLine
114 $_POST[ '_podsfix_' . $key ] = $value;
115 }
116 }
117 }//end if
118 }
119
120 /**
121 * Attach requirements to admin header
122 *
123 * @since 2.0.0
124 */
125 public function admin_head() {
126 wp_register_script( 'pods-upgrade', PODS_URL . 'ui/js/jquery.pods.upgrade.js', array(), PODS_VERSION );
127
128 $page = sanitize_text_field( pods_v( 'page' ) );
129
130 if ( empty( $page ) ) {
131 return;
132 }
133
134 if ( 'pods' !== $page && 0 !== strpos( $page, 'pods-' ) ) {
135 return;
136 }
137 ?>
138 <script>
139 if ( 'undefined' === typeof PODS_URL ) {
140 const PODS_URL = '<?php echo esc_js( PODS_URL ); ?>';
141 }
142 </script>
143 <?php
144
145 // To be phased out.
146 wp_enqueue_script( 'jquery' );
147 wp_enqueue_script( 'jquery-ui-core' );
148 wp_enqueue_script( 'jquery-ui-sortable' );
149
150 // To be replaced.
151 wp_enqueue_script( 'jquery-qtip2' );
152 wp_enqueue_script( 'pods-qtip-init' );
153
154 // To be phased out.
155 wp_enqueue_script( 'pods' );
156
157 $action = sanitize_text_field( pods_v( 'action', 'get', 'manage' ) );
158
159 if (
160 0 === strpos( $page, 'pods-manage-' )
161 || 0 === strpos( $page, 'pods-add-new-' )
162 || 0 === strpos( $page, 'pods-settings-' )
163 ) {
164 wp_enqueue_script( 'post' );
165 } elseif (
166 in_array( $page, [ 'pods', 'pods-add-new', 'pods-packages', 'pods-wizard', 'pods-upgrade' ], true )
167 || in_array( $action, [ 'add', 'manage' ], true )
168 ) {
169 wp_enqueue_style( 'pods-wizard' );
170
171 if ( 'pods-upgrade' === $page ) {
172 wp_enqueue_script( 'pods-upgrade' );
173 }
174 }
175
176 wp_enqueue_script( 'pods-dfv' );
177 wp_enqueue_style( 'pods-styles' );
178 }
179
180 /**
181 * Build the admin menus
182 *
183 * @since 2.0.0
184 */
185 public function admin_menu() {
186
187 $advanced_content_types = PodsMeta::$advanced_content_types;
188 $taxonomies = PodsMeta::$taxonomies;
189 $settings = PodsMeta::$settings;
190
191 if ( ! PodsInit::$upgrade_needed || ( pods_is_admin() && 1 === (int) pods_v( 'pods_upgrade_bypass' ) ) ) {
192 $submenu_items = array();
193
194 if ( ! empty( $advanced_content_types ) ) {
195 $submenu = array();
196
197 $pods_pages = 0;
198
199 foreach ( (array) $advanced_content_types as $pod ) {
200 if ( ! $pod instanceof Pod ) {
201 continue;
202 } elseif ( ! pods_is_admin(
203 array(
204 'pods',
205 'pods_content',
206 'pods_add_' . $pod['name'],
207 'pods_edit_' . $pod['name'],
208 'pods_delete_' . $pod['name'],
209 )
210 ) ) {
211 continue;
212 }
213
214 $pod_name = $pod['name'];
215
216 $pod = apply_filters( "pods_advanced_content_type_pod_data_{$pod_name}", $pod, $pod['name'] );
217 $pod = apply_filters( 'pods_advanced_content_type_pod_data', $pod, $pod['name'] );
218
219 if ( 1 === (int) pods_v( 'show_in_menu', $pod['options'], 0 ) ) {
220 $page_title = pods_v( 'label', $pod, ucwords( str_replace( '_', ' ', $pod['name'] ) ), true );
221 $page_title = apply_filters( 'pods_admin_menu_page_title', $page_title, $pod );
222
223 $menu_label = pods_v( 'menu_name', $pod['options'], $page_title, true );
224 $menu_label = strip_tags( $menu_label );
225 $menu_label = apply_filters( 'pods_admin_menu_label', $menu_label, $pod );
226
227 $singular_label = pods_v( 'label_singular', $pod['options'], pods_v( 'label', $pod, ucwords( str_replace( '_', ' ', $pod['name'] ) ), true ), true );
228 $plural_label = pods_v( 'label', $pod, ucwords( str_replace( '_', ' ', $pod['name'] ) ), true );
229
230 $menu_location = pods_v( 'menu_location', $pod['options'], 'objects' );
231 $menu_location_custom = pods_v( 'menu_location_custom', $pod['options'], '' );
232
233 $menu_position = pods_v( 'menu_position', $pod['options'], '', true );
234 $menu_icon = pods_evaluate_tags( pods_v( 'menu_icon', $pod['options'], '', true ), true );
235
236 if ( empty( $menu_position ) ) {
237 $menu_position = null;
238 }
239
240 $parent_page = null;
241
242 if ( pods_is_admin(
243 array(
244 'pods',
245 'pods_content',
246 'pods_edit_' . $pod['name'],
247 'pods_delete_' . $pod['name'],
248 )
249 ) ) {
250 if ( ! empty( $menu_location_custom ) ) {
251 if ( ! isset( $submenu_items[ $menu_location_custom ] ) ) {
252 $submenu_items[ $menu_location_custom ] = array();
253 }
254
255 $submenu_items[ $menu_location_custom ][] = array(
256 $menu_location_custom,
257 $page_title,
258 $menu_label,
259 'read',
260 'pods-manage-' . $pod['name'],
261 array( $this, 'admin_content' ),
262 );
263
264 continue;
265 } else {
266 $pods_pages ++;
267
268 $page = 'pods-manage-' . $pod['name'];
269 $parent_page = $page;
270
271 if ( empty( $menu_position ) ) {
272 $menu_position = null;
273 }
274 add_menu_page( $page_title, $menu_label, 'read', $parent_page, '', $menu_icon, $menu_position );
275
276 $all_title = $plural_label;
277 $all_label = pods_v( 'label_all_items', $pod['options'], __( 'All', 'pods' ) . ' ' . $plural_label );
278
279 if ( pods_v( 'page' ) === $page ) {
280 if ( 'edit' === pods_v( 'action', 'get', 'manage' ) ) {
281 $all_title = pods_v( 'label_edit_item', $pod['options'], __( 'Edit', 'pods' ) . ' ' . $singular_label );
282 } elseif ( 'add' === pods_v( 'action', 'get', 'manage' ) ) {
283 $all_title = pods_v( 'label_add_new_item', $pod['options'], sprintf( __( 'Add New %s', 'pods' ), $singular_label ) );
284 }
285 }
286
287 add_submenu_page(
288 $parent_page, $all_title, $all_label, 'read', $page, array(
289 $this,
290 'admin_content',
291 )
292 );
293 }//end if
294 }//end if
295
296 if ( pods_is_admin( array( 'pods', 'pods_content', 'pods_add_' . $pod['name'] ) ) ) {
297 $page = 'pods-add-new-' . $pod['name'];
298
299 if ( null === $parent_page ) {
300 $pods_pages ++;
301
302 $parent_page = $page;
303
304 if ( empty( $menu_position ) ) {
305 $menu_position = null;
306 }
307 add_menu_page( $page_title, $menu_label, 'read', $parent_page, '', $menu_icon, $menu_position );
308 }
309
310 $add_title = pods_v( 'label_add_new_item', $pod['options'], sprintf( __( 'Add New %s', 'pods' ), $singular_label ) );
311 $add_label = pods_v( 'label_add_new', $pod['options'], sprintf( __( 'Add New %s', 'pods' ), $singular_label ) );
312
313 add_submenu_page(
314 $parent_page, $add_title, $add_label, 'read', $page, array(
315 $this,
316 'admin_content',
317 )
318 );
319 }//end if
320 } elseif ( 1 === (int) pods_v( 'use_submenu_fallback', $pod['options'], 1 ) ) {
321 $submenu[] = $pod;
322 }//end if
323 }//end foreach
324
325 $submenu = apply_filters( 'pods_admin_menu_secondary_content', $submenu );
326
327 if ( ! empty( $submenu ) && ( ! defined( 'PODS_DISABLE_CONTENT_MENU' ) || ! PODS_DISABLE_CONTENT_MENU ) ) {
328 $parent_page = null;
329
330 foreach ( $submenu as $item ) {
331 $singular_label = pods_v( 'label_singular', $item['options'], pods_v( 'label', $item, ucwords( str_replace( '_', ' ', $item['name'] ) ), true ), true );
332 $plural_label = pods_v( 'label', $item, ucwords( str_replace( '_', ' ', $item['name'] ) ), true );
333
334 if ( pods_is_admin(
335 array(
336 'pods',
337 'pods_content',
338 'pods_edit_' . $item['name'],
339 'pods_delete_' . $item['name'],
340 )
341 ) ) {
342 $page = 'pods-manage-' . $item['name'];
343
344 if ( null === $parent_page ) {
345 $parent_page = $page;
346
347 add_menu_page( 'Pods', 'Pods', 'read', $parent_page, null, pods_svg_icon( 'pods' ), '58.5' );
348 }
349
350 $all_title = $plural_label;
351 $all_label = __( 'Manage', 'pods' ) . ' ' . $plural_label;
352
353 if ( pods_v( 'page' ) === $page ) {
354 if ( 'edit' === pods_v( 'action', 'get', 'manage' ) ) {
355 $all_title = __( 'Edit', 'pods' ) . ' ' . $singular_label;
356 } elseif ( 'add' === pods_v( 'action', 'get', 'manage' ) ) {
357 $all_title = __( 'Add New', 'pods' ) . ' ' . $singular_label;
358 }
359 }
360
361 add_submenu_page(
362 $parent_page, $all_title, $all_label, 'read', $page, array(
363 $this,
364 'admin_content',
365 )
366 );
367 } elseif ( current_user_can( 'pods_add_' . $item['name'] ) ) {
368 $page = 'pods-add-new-' . $item['name'];
369
370 if ( null === $parent_page ) {
371 $parent_page = $page;
372
373 add_menu_page( 'Pods', 'Pods', 'read', $parent_page, null, pods_svg_icon( 'pods' ), '58.5' );
374 }
375
376 $add_title = __( 'Add New', 'pods' ) . ' ' . $singular_label;
377 $add_label = __( 'Manage', 'pods' ) . ' ' . $plural_label;
378
379 add_submenu_page(
380 $parent_page, $add_title, $add_label, 'read', $page, array(
381 $this,
382 'admin_content',
383 )
384 );
385 }//end if
386 }//end foreach
387 }//end if
388 }//end if
389
390 if ( ! empty( $taxonomies ) ) {
391 foreach ( (array) $taxonomies as $pod ) {
392 // Default taxonomy capability
393 $capability = 'manage_categories';
394
395 if ( ! empty( $pod['options']['capability_type'] ) ) {
396 if ( 'custom' === $pod['options']['capability_type'] && ! empty( $pod['options']['capability_type_custom'] ) ) {
397 $capability = 'manage_' . (string) $pod['options']['capability_type_custom'] . '_terms';
398 }
399 }
400
401 // Check capabilities.
402 if ( ! pods_is_admin(
403 array(
404 'pods',
405 'pods_content',
406 'pods_edit_' . $pod['name'],
407 $capability,
408 )
409 ) ) {
410 continue;
411 }
412
413 // Check UI settings
414 if ( 1 !== (int) pods_v( 'show_ui', $pod['options'], 0 ) || 1 !== (int) pods_v( 'show_in_menu', $pod['options'], 0 ) ) {
415 continue;
416 }
417
418 $menu_location = pods_v( 'menu_location', $pod['options'], 'default' );
419
420 if ( 'default' === $menu_location ) {
421 continue;
422 }
423
424 $page_title = pods_v( 'label', $pod, ucwords( str_replace( '_', ' ', $pod['name'] ) ), true );
425 $page_title = apply_filters( 'pods_admin_menu_page_title', $page_title, $pod );
426
427 $menu_label = pods_v( 'menu_name', $pod['options'], $page_title, true );
428 $menu_label = strip_tags( $menu_label );
429 $menu_label = apply_filters( 'pods_admin_menu_label', $menu_label, $pod );
430
431 $menu_icon = pods_evaluate_tags( pods_v( 'menu_icon', $pod['options'], '', true ), true );
432 $menu_slug = 'edit-tags.php?taxonomy=' . $pod['name'];
433 $menu_location_custom = pods_v( 'menu_location_custom', $pod['options'], '' );
434
435 $menu_position = pods_v( 'menu_position', $pod['options'], '', true );
436 if ( empty( $menu_position ) ) {
437 $menu_position = null;
438 }
439
440 $taxonomy_data = get_taxonomy( $pod['name'] );
441
442 foreach ( (array) $taxonomy_data->object_type as $post_type ) {
443 if ( 'post' === $post_type ) {
444 remove_submenu_page( 'edit.php', $menu_slug );
445 } elseif ( 'attachment' === $post_type ) {
446 remove_submenu_page( 'upload.php', $menu_slug . '&amp;post_type=' . $post_type );
447 } else {
448 remove_submenu_page( 'edit.php?post_type=' . $post_type, $menu_slug . '&amp;post_type=' . $post_type );
449 }
450 }
451
452 if ( 'settings' === $menu_location ) {
453 add_options_page( $page_title, $menu_label, 'read', $menu_slug );
454 } elseif ( 'appearances' === $menu_location ) {
455 add_theme_page( $page_title, $menu_label, 'read', $menu_slug );
456 } elseif ( 'objects' === $menu_location || 'top' === $menu_location ) {
457 add_menu_page( $page_title, $menu_label, 'read', $menu_slug, '', $menu_icon, $menu_position );
458 } elseif ( 'submenu' === $menu_location && ! empty( $menu_location_custom ) ) {
459 if ( ! isset( $submenu_items[ $menu_location_custom ] ) ) {
460 $submenu_items[ $menu_location_custom ] = array();
461 }
462
463 $submenu_items[ $menu_location_custom ][] = array(
464 $menu_location_custom,
465 $page_title,
466 $menu_label,
467 'read',
468 $menu_slug,
469 '',
470 );
471 }//end if
472 }//end foreach
473 }//end if
474
475 if ( ! empty( $settings ) ) {
476 foreach ( (array) $settings as $pod ) {
477 if ( ! pods_is_admin( array( 'pods', 'pods_content', 'pods_edit_' . $pod['name'] ) ) ) {
478 continue;
479 }
480
481 $page_title = pods_v( 'label', $pod, ucwords( str_replace( '_', ' ', $pod['name'] ) ), true );
482 $page_title = apply_filters( 'pods_admin_menu_page_title', $page_title, $pod );
483
484 $menu_label = pods_v( 'menu_name', $pod['options'], $page_title, true );
485 $menu_label = strip_tags( $menu_label );
486 $menu_label = apply_filters( 'pods_admin_menu_label', $menu_label, $pod );
487
488 $menu_icon = pods_evaluate_tags( pods_v( 'menu_icon', $pod['options'], '', true ), true );
489
490 $menu_position = pods_v( 'menu_position', $pod['options'], '', true );
491 if ( empty( $menu_position ) ) {
492 $menu_position = null;
493 }
494
495 $menu_slug = 'pods-settings-' . $pod['name'];
496 $menu_location = pods_v( 'menu_location', $pod['options'], 'settings' );
497 $menu_location_custom = pods_v( 'menu_location_custom', $pod['options'], '' );
498 $menu_callback = array( $this, 'admin_content_settings' );
499
500 if ( 'settings' === $menu_location ) {
501 add_options_page( $page_title, $menu_label, 'read', $menu_slug, $menu_callback, $menu_position );
502 } elseif ( 'appearances' === $menu_location ) {
503 add_theme_page( $page_title, $menu_label, 'read', $menu_slug, $menu_callback, $menu_position );
504 } elseif ( 'objects' === $menu_location || 'top' === $menu_location ) {
505 add_menu_page( $page_title, $menu_label, 'read', $menu_slug, $menu_callback, $menu_icon, $menu_position );
506 } elseif ( 'submenu' === $menu_location && ! empty( $menu_location_custom ) ) {
507 if ( ! isset( $submenu_items[ $menu_location_custom ] ) ) {
508 $submenu_items[ $menu_location_custom ] = array();
509 }
510
511 $submenu_items[ $menu_location_custom ][] = array(
512 $menu_location_custom,
513 $page_title,
514 $menu_label,
515 'read',
516 $menu_slug,
517 $menu_callback,
518 $menu_position,
519 );
520 }//end if
521 }//end foreach
522 }//end if
523
524 foreach ( $submenu_items as $items ) {
525 foreach ( $items as $item ) {
526 call_user_func_array( 'add_submenu_page', $item );
527 }
528 }
529
530 $edit_pods_title = null;
531
532 if ( 'pods' === pods_v( 'page' ) && 'edit' === pods_v( 'action' ) ) {
533 $edit_pods_title = __( 'Edit Pod', 'pods' );
534 }
535
536 $admin_menus = array(
537 'pods' => array(
538 'label' => __( 'Edit Pods', 'pods' ),
539 'title' => $edit_pods_title,
540 'function' => array( $this, 'admin_setup' ),
541 'access' => 'pods',
542 ),
543 'pods-add-new' => array(
544 'label' => __( 'Add New', 'pods' ),
545 'title' => __( 'Add New Pod', 'pods' ),
546 'function' => array( $this, 'admin_setup' ),
547 'access' => 'pods',
548 ),
549 'pods-components' => array(
550 'label' => __( 'Components', 'pods' ),
551 'title' => __( 'Pods Components', 'pods' ),
552 'function' => array( $this, 'admin_components' ),
553 'access' => 'pods_components',
554 ),
555 'pods-access-rights-review' => array(
556 'label' => __( 'Review Access Rights', 'pods' ),
557 'title' => __( 'Pods Review Access Rights', 'pods' ),
558 'function' => array( $this, 'admin_access_rights_review' ),
559 'access' => 'pods',
560 ),
561 'pods-settings' => array(
562 'label' => __( 'Settings', 'pods' ),
563 'title' => __( 'Pods Settings', 'pods' ),
564 'function' => array( $this, 'admin_settings' ),
565 'access' => 'pods_settings',
566 ),
567 'pods-help' => array(
568 'label' => __( 'Help', 'pods' ),
569 'title' => __( 'Pods Help', 'pods' ),
570 'function' => array( $this, 'admin_help' ),
571 ),
572 );
573
574 add_filter( 'parent_file', array( $this, 'parent_file' ) );
575 } else {
576 $admin_menus = array(
577 'pods-upgrade' => array(
578 'label' => __( 'Upgrade', 'pods' ),
579 'function' => array( $this, 'admin_upgrade' ),
580 'access' => 'manage_options',
581 ),
582 'pods-settings' => array(
583 'label' => __( 'Settings', 'pods' ),
584 'title' => __( 'Pods Settings', 'pods' ),
585 'function' => array( $this, 'admin_settings' ),
586 'access' => 'pods_settings',
587 ),
588 'pods-help' => array(
589 'label' => __( 'Help', 'pods' ),
590 'title' => __( 'Pods Help', 'pods' ),
591 'function' => array( $this, 'admin_help' ),
592 ),
593 );
594
595 add_action( 'admin_notices', array( $this, 'upgrade_notice' ) );
596 }//end if
597
598 /**
599 * Add or change Pods Admin menu items
600 *
601 * @param array $admin_menus The submenu items in Pods Admin menu.
602 *
603 * @since unknown
604 */
605 $admin_menus = apply_filters( 'pods_admin_menu', $admin_menus );
606
607 $parent = false;
608
609 // PODS_LIGHT disables all Pods components so remove the components menu
610 if ( pods_light() ) {
611 unset( $admin_menus['pods-components'] );
612 }
613
614 if ( ! empty( $admin_menus ) && ( ! defined( 'PODS_DISABLE_ADMIN_MENU' ) || ! PODS_DISABLE_ADMIN_MENU ) ) {
615 foreach ( $admin_menus as $page => $menu_item ) {
616 if ( ! pods_is_admin( pods_v( 'access', $menu_item ) ) ) {
617 continue;
618 }
619
620 // Don't just show the help page
621 if ( false === $parent && 'pods-help' === $page ) {
622 continue;
623 }
624
625 if ( empty( $menu_item['label'] ) ) {
626 $menu_item['label'] = $page;
627 }
628
629 if ( empty( $menu_item['title'] ) ) {
630 $menu_item['title'] = $menu_item['label'];
631 }
632
633 if ( false === $parent ) {
634 $parent = $page;
635
636 $menu = __( 'Pods Admin', 'pods' );
637
638 if ( 'pods-upgrade' === $parent ) {
639 $menu = __( 'Pods Upgrade', 'pods' );
640 }
641
642 add_menu_page( $menu, $menu, 'read', $parent, null, pods_svg_icon( 'pods' ) );
643 }
644
645 add_submenu_page( $parent, $menu_item['title'], $menu_item['label'], 'read', $page, $menu_item['function'] );
646
647 if ( 'pods-components' === $page && is_object( PodsInit::$components ) ) {
648 PodsInit::$components->menu( $parent );
649 }
650 }//end foreach
651 }//end if
652 }
653
654 /**
655 * Set the correct parent_file to highlight the correct top level menu
656 *
657 * @param string $parent_file The parent file.
658 *
659 * @return mixed|string
660 *
661 * @since unknown
662 */
663 public function parent_file( $parent_file ) {
664 global $current_screen, $submenu_file;
665
666 if ( isset( $current_screen ) && ! empty( $current_screen->taxonomy ) ) {
667 $taxonomies = PodsMeta::$taxonomies;
668 if ( ! empty( $taxonomies ) ) {
669 foreach ( (array) $taxonomies as $pod ) {
670 if ( $current_screen->taxonomy !== $pod['name'] ) {
671 continue;
672 }
673
674 $menu_slug = 'edit-tags.php?taxonomy=' . $pod['name'];
675 $menu_location = pods_v( 'menu_location', $pod['options'], 'default' );
676 $menu_location_custom = pods_v( 'menu_location_custom', $pod['options'], '' );
677
678 if ( 'settings' === $menu_location ) {
679 $parent_file = 'options-general.php';
680 } elseif ( 'appearances' === $menu_location ) {
681 $parent_file = 'themes.php';
682 } elseif ( 'objects' === $menu_location ) {
683 $parent_file = $menu_slug;
684 } elseif ( 'top' === $menu_location ) {
685 $parent_file = $menu_slug;
686 } elseif ( 'submenu' === $menu_location && ! empty( $menu_location_custom ) ) {
687 $parent_file = $menu_location_custom;
688 }
689
690 break;
691 }//end foreach
692 }//end if
693 }//end if
694
695 if ( isset( $current_screen ) && ! empty( $current_screen->post_type ) && is_object( PodsInit::$components ) ) {
696 $components_menu_items = PodsInit::$components->components_menu_items;
697
698 foreach ( $components_menu_items as $menu_item ) {
699 if ( empty( $menu_item['menu_page'] ) || $parent_file !== $menu_item['menu_page'] ) {
700 continue;
701 }
702
703 $parent_file = 'pods';
704
705 // @codingStandardsIgnoreLine
706 $submenu_file = $menu_item['menu_page'];
707
708 break;
709 }
710 }
711
712 return $parent_file;
713 }
714
715 /**
716 * Show upgrade notice.
717 */
718 public function upgrade_notice() {
719
720 echo '<div class="error fade"><p>';
721 // @codingStandardsIgnoreLine
722 echo sprintf( __( '<strong>NOTICE:</strong> Pods %1$s requires your action to complete the upgrade. Please run the <a href="%2$s">Upgrade Wizard</a>.', 'pods' ), esc_html( PODS_VERSION ), esc_url( admin_url( 'admin.php?page=pods-upgrade' ) ) );
723 echo '</p></div>';
724 }
725
726 /**
727 * Create PodsUI content for the administration pages
728 */
729 public function admin_content() {
730
731 // @codingStandardsIgnoreLine
732 $pod_name = str_replace( array( 'pods-manage-', 'pods-add-new-' ), '', $_GET['page'] );
733
734 $pod = pods_get_instance( $pod_name, pods_v( 'id', 'get', null, true ) );
735
736 if ( ! $pod->pod_data->has_fields() ) {
737 pods_message( __( 'This Pod does not have any fields defined.', 'pods' ), 'error' );
738 return;
739 }
740
741 // @codingStandardsIgnoreLine
742 if ( false !== strpos( $_GET['page'], 'pods-add-new-' ) ) {
743 // @codingStandardsIgnoreLine
744 $_GET['action'] = pods_v( 'action', 'get', 'add' );
745 }
746
747 $pod->ui();
748 }
749
750 /**
751 * Create PodsUI content for the settings administration pages
752 */
753 public function admin_content_settings() {
754
755 // @codingStandardsIgnoreLine
756 $pod_name = str_replace( 'pods-settings-', '', $_GET['page'] );
757
758 $pod = pods_get_instance( $pod_name );
759
760 if ( empty( $pod->pod_data ) ) {
761 printf(
762 '<div class="wrap"><p>%s</p></div>',
763 esc_html__( 'This content type is not configured correctly. There could be an issue in your configuration storagae. Please contact support.', 'pods' )
764 );
765
766 return;
767 }
768
769 if ( 'custom' !== pods_v( 'ui_style', $pod->pod_data['options'], 'settings', true ) ) {
770 $actions_disabled = array(
771 'manage' => 'manage',
772 'add' => 'add',
773 'delete' => 'delete',
774 'duplicate' => 'duplicate',
775 'view' => 'view',
776 'export' => 'export',
777 );
778
779 // @codingStandardsIgnoreLine
780 $_GET['action'] = 'edit';
781
782 $page_title = pods_v( 'label', $pod->pod_data, ucwords( str_replace( '_', ' ', $pod->pod_data['name'] ) ), true );
783 $page_title = apply_filters( 'pods_admin_menu_page_title', $page_title, $pod->pod_data );
784
785 $pod_pod_name = $pod->pod;
786
787 $ui = array(
788 'id' => $pod_pod_name,
789 'pod' => $pod,
790 'fields' => array(
791 'edit' => $pod->pod_data->get_fields(),
792 ),
793 'header' => array(
794 'edit' => $page_title,
795 ),
796 'label' => array(
797 'edit' => __( 'Save Changes', 'pods' ),
798 ),
799 'style' => pods_v( 'ui_style', $pod->pod_data['options'], 'settings', true ),
800 'icon' => pods_evaluate_tags( pods_v( 'menu_icon', $pod->pod_data['options'] ), true ),
801 'actions_disabled' => $actions_disabled,
802 );
803
804 $ui = apply_filters( "pods_admin_ui_{$pod_pod_name}", apply_filters( 'pods_admin_ui', $ui, $pod->pod, $pod ), $pod->pod, $pod );
805
806 // Force disabled actions, do not pass go, do not collect $two_hundred
807 $ui['actions_disabled'] = $actions_disabled;
808
809 pods_ui( $ui );
810 } else {
811 $pod_pod_name = $pod->pod;
812 do_action( 'pods_admin_ui_custom', $pod );
813 do_action( "pods_admin_ui_custom_{$pod_pod_name}", $pod );
814 }//end if
815 }
816
817 /**
818 * Add media button for Pods shortcode
819 *
820 * @param string $context Media button context.
821 */
822 public function media_button( $context = null ) {
823 if ( ! empty( $_GET['action'] ) && 'elementor' === $_GET['action'] ) {
824 return;
825 }
826
827 // If shortcodes are disabled don't show the button
828 if ( defined( 'PODS_DISABLE_SHORTCODE' ) && PODS_DISABLE_SHORTCODE ) {
829 return;
830 }
831
832 /**
833 * Filter to remove Pods shortcode button from the post editor.
834 *
835 * @param bool $show_button Set to false to block the shortcode button from appearing.
836 * @param string $context Media button context.
837 *
838 * @since 2.3.19
839 */
840 if ( ! apply_filters( 'pods_admin_media_button', true, $context ) ) {
841 return;
842 }
843
844 $current_page = basename( $_SERVER['PHP_SELF'] );
845 $current_page = explode( '?', $current_page );
846 $current_page = explode( '#', $current_page[0] );
847 $current_page = $current_page[0];
848
849 // Only show the button on post type pages
850 if ( ! in_array(
851 $current_page, array(
852 'post-new.php',
853 'post.php',
854 ), true
855 ) ) {
856 return;
857 }
858
859 add_action( 'admin_footer', array( $this, 'mce_popup' ) );
860
861 echo '<a href="#TB_inline?width=640&inlineId=pods_shortcode_form" class="thickbox button" id="add_pod_button" title="Pods Shortcode"><img style="padding: 0px 6px 0px 0px; margin: -3px 0px 0px;" src="' . esc_url( PODS_URL . 'ui/images/icon16.png' ) . '" alt="' . esc_attr__( 'Pods Shortcode', 'pods' ) . '" />' . esc_html__( 'Pods Shortcode', 'pods' ) . '</a>';
862 }
863
864 /**
865 * Enqueue assets for Media Library Popup
866 */
867 public function register_media_assets() {
868
869 if ( 'pods_media_attachment' === pods_v( 'inlineId' ) ) {
870 wp_enqueue_style( 'pods-styles' );
871 }
872 }
873
874 /**
875 * Output Pods shortcode popup window
876 */
877 public function mce_popup() {
878
879 pods_view( PODS_DIR . 'ui/admin/shortcode.php', compact( array_keys( get_defined_vars() ) ) );
880 }
881
882 /**
883 * Handle main Pods Setup area for managing Pods and Fields
884 */
885 public function admin_setup() {
886 $api = pods_api();
887
888 $pods = $api->load_pods( array( 'fields' => false ) );
889
890 $id = pods_v( 'id' );
891 $action = pods_v( 'action' );
892 $view = pods_v( 'view', 'get', 'all', true );
893
894 // @codingStandardsIgnoreLine
895 if ( empty( $pods ) && ! isset( $_GET['action'] ) ) {
896 // @codingStandardsIgnoreLine
897 $_GET['action'] = 'add';
898 }
899
900 if ( 'pods' === $_GET['page'] && empty( $pods ) ) {
901 pods_message( __( 'You do not have any Pods set up yet. You can set up your very first Pod below.', 'pods ' ) );
902 }
903
904 // @codingStandardsIgnoreLine
905 if ( 'pods-add-new' === $_GET['page'] || empty( $pods ) ) {
906 // @codingStandardsIgnoreLine
907 if ( isset( $_GET['action'] ) && 'add' !== $_GET['action'] ) {
908 pods_redirect(
909 pods_query_arg(
910 array(
911 'page' => 'pods',
912 // @codingStandardsIgnoreLine
913 'action' => $_GET['action'],
914 )
915 )
916 );
917 } else {
918 // @codingStandardsIgnoreLine
919 $_GET['action'] = 'add';
920 }
921 // @codingStandardsIgnoreLine
922 } elseif ( isset( $_GET['action'] ) && 'add' === $_GET['action'] ) {
923 pods_redirect(
924 pods_query_arg(
925 array(
926 'page' => 'pods-add-new',
927 'action' => '',
928 'id' => '',
929 'do' => '',
930 '_wpnonce' => '',
931 )
932 )
933 );
934 }//end if
935
936 $pod_types = $api->get_pod_types();
937 $storage_types = $api->get_storage_types();
938
939 $row = false;
940
941 $pod_types_found = [];
942 $sources_found = [];
943 $source_types = [];
944
945 $include_row_counts = filter_var( pods_v( 'pods_include_row_counts' ), FILTER_VALIDATE_BOOLEAN );
946 $include_row_counts_refresh = filter_var( pods_v( 'pods_include_row_counts_refresh' ), FILTER_VALIDATE_BOOLEAN );
947
948 $fields = [
949 'label' => [
950 'label' => __( 'Label', 'pods' ),
951 ],
952 'name' => [
953 'label' => __( 'Name', 'pods' ),
954 ],
955 'type' => [
956 'label' => __( 'Type', 'pods' ),
957 ],
958 'source' => [
959 'label' => __( 'Source', 'pods' ),
960 'width' => '10%',
961 'type' => 'raw',
962 ],
963 'storage' => [
964 'label' => __( 'Storage Type', 'pods' ),
965 'width' => '10%',
966 ],
967 'group_count' => [
968 'label' => __( 'Groups', 'pods' ),
969 'width' => '8%',
970 ],
971 'field_count' => [
972 'label' => __( 'Fields', 'pods' ),
973 'width' => '8%',
974 ],
975 ];
976
977 if ( $include_row_counts ) {
978 $fields['row_count'] = [
979 'label' => __( 'Data Rows', 'pods' ),
980 'width' => '8%',
981 ];
982
983 $fields['row_meta_count'] = [
984 'label' => __( 'Meta Rows', 'pods' ),
985 'width' => '8%',
986 ];
987
988 $fields['podsrel_count'] = [
989 // translators: "PodsRel" references the name of the Pods relationships table in the database.
990 'label' => __( 'PodsRel Rows', 'pods' ),
991 'width' => '10%',
992 ];
993 }
994
995 $total_groups = 0;
996 $total_fields = 0;
997 $total_rows = 0;
998 $total_row_meta = 0;
999 $total_podsrel_rows = 0;
1000
1001 /**
1002 * Filters whether to extend internal Pods.
1003 *
1004 * @since 2.8.0
1005 *
1006 * @param bool $extend_internal Whether to extend internal Pods.
1007 */
1008 $extend_internal = apply_filters( 'pods_admin_setup_extend_pods_internal', false );
1009
1010 $pod_list = array();
1011
1012 $is_tableless = pods_tableless();
1013
1014 $has_source = false;
1015 $has_storage_type = false;
1016
1017 foreach ( $pods as $k => $pod ) {
1018 $pod_type = $pod['type'];
1019 $pod_type_label = null;
1020 $pod_storage = $pod['storage'];
1021
1022 if ( empty( $pod_type ) || ! is_string( $pod_type ) ) {
1023 $pod_type = 'post_type';
1024 }
1025
1026 if ( empty( $pod_storage ) || ! is_string( $pod_storage ) ) {
1027 $pod_storage = 'meta';
1028 }
1029
1030 $show_meta_count = 'meta' === $pod_storage || in_array( $pod['type'], [ 'post_type', 'taxonomy', 'user', 'comment' ], true );
1031
1032 if ( ! empty( $pod['internal'] ) ) {
1033 // Don't show internal if we aren't extending them.
1034 if ( ! $extend_internal ) {
1035 continue;
1036 }
1037
1038 $pod_type = 'internal';
1039 $pod_storage = 'meta';
1040 }
1041
1042 if ( 'settings' === $pod_type ) {
1043 $pod_storage = 'option';
1044 }
1045
1046 if ( 'meta' !== $pod_storage ) {
1047 $has_storage_type = true;
1048 }
1049
1050 if ( isset( $pod_types[ $pod_type ] ) ) {
1051 $pod_type_label = $pod_types[ $pod_type ];
1052 }
1053
1054 $pod_real_type = $pod_type;
1055
1056 $storage_type_label = ucwords( $pod_storage );
1057
1058 if ( isset( $storage_types[ $pod_storage ] ) ) {
1059 $storage_type_label = $storage_types[ $pod_storage ];
1060 }
1061
1062 if ( null !== $pod_type_label ) {
1063 if ( ! $pod->is_extended() && in_array( $pod_type, array(
1064 'post_type',
1065 'taxonomy',
1066 ), true ) ) {
1067 if ( 'post_type' === $pod_type ) {
1068 $pod_type = 'cpt';
1069 } else {
1070 $pod_type = 'ct';
1071 }
1072
1073 if ( isset( $pod_types[ $pod_type ] ) ) {
1074 $pod_type_label = $pod_types[ $pod_type ];
1075 }
1076 }
1077
1078 if ( ! isset( $pod_types_found[ $pod_type ] ) ) {
1079 $pod_types_found[ $pod_type ] = 1;
1080 } else {
1081 $pod_types_found[ $pod_type ] ++;
1082 }
1083
1084 if ( 'all' !== $view && $view !== $pod_type ) {
1085 continue;
1086 }
1087
1088 $pod_real_type = $pod_type;
1089 $pod_type = $pod_type_label;
1090 } elseif ( 'all' !== $view ) {
1091 continue;
1092 }//end if
1093
1094 $group_count = 0;
1095 $field_count = 0;
1096
1097 if ( ! pods_is_types_only( false, $pod->get_name() ) ) {
1098 $group_count = $pod->count_groups();
1099 $field_count = $pod->count_fields();
1100 }
1101
1102 if ( $include_row_counts ) {
1103 $count_transient_prefix = 'pods_admin_' . $pod['type'] . '_' . $pod['name'] . '_';
1104
1105 $row_counts = [
1106 'row_count' => false,
1107 'row_meta_count' => false,
1108 'podsrel_count' => false,
1109 ];
1110
1111 if ( ! $include_row_counts_refresh ) {
1112 $row_counts['row_count'] = pods_transient_get( $count_transient_prefix . 'row_count' );
1113 $row_counts['row_meta_count'] = pods_transient_get( $count_transient_prefix . 'row_meta_count' );
1114 $row_counts['podsrel_count'] = pods_transient_get( $count_transient_prefix . 'podsrel_count' );
1115 }
1116
1117 if ( ! is_numeric( $row_counts['row_count'] ) ) {
1118 $row_counts['row_count'] = $pod->count_rows();
1119
1120 pods_transient_set( $count_transient_prefix . 'row_count', $row_counts['row_count'], HOUR_IN_SECONDS * 3 );
1121 }
1122
1123 if ( $show_meta_count && ! is_numeric( $row_counts['row_meta_count'] ) ) {
1124 $row_counts['row_meta_count'] = $pod->count_row_meta();
1125
1126 pods_transient_set( $count_transient_prefix . 'row_meta_count', $row_counts['row_meta_count'], HOUR_IN_SECONDS * 3 );
1127 }
1128
1129 if ( ! $is_tableless && ! is_numeric( $row_counts['podsrel_count'] ) ) {
1130 $row_counts['podsrel_count'] = $pod->count_podsrel_rows();
1131
1132 pods_transient_set( $count_transient_prefix . 'podsrel_count', $row_counts['podsrel_count'], HOUR_IN_SECONDS * 3 );
1133 }
1134 }
1135
1136 $object_storage_type = $pod->get_object_storage_type();
1137 $source = $pod->get_object_storage_type_label();
1138
1139 if ( $source ) {
1140 $source_types[ $object_storage_type ] = $source;
1141
1142 if ( ! isset( $sources_found[ $object_storage_type ] ) ) {
1143 $sources_found[ $object_storage_type ] = 1;
1144 } else {
1145 $sources_found[ $object_storage_type ] ++;
1146 }
1147 }
1148
1149 $source = esc_html( $source );
1150
1151 if ( 'post_type' !== $object_storage_type ) {
1152 $has_source = true;
1153
1154 if ( 'file' === $object_storage_type ) {
1155 $file_source = $pod->get_arg( '_pods_file_source' );
1156
1157 if ( $file_source ) {
1158 if ( 0 === strpos( $file_source, ABSPATH ) ) {
1159 $file_source = str_replace( ABSPATH, '', $file_source );
1160 }
1161
1162 ob_start();
1163
1164 pods_help(
1165 sprintf(
1166 '<strong>%s:</strong> %s',
1167 esc_html__( 'File source', 'pods' ),
1168 esc_html( $file_source )
1169 ),
1170 null,
1171 '.pods-admin-container'
1172 );
1173
1174 $source .= ' ' . ob_get_clean();
1175 }
1176 } elseif ( 'collection' === $object_storage_type ) {
1177 $code_source = $pod->get_arg( '_pods_code_source' );
1178
1179 if ( $code_source ) {
1180 if ( 0 === strpos( $code_source, ABSPATH ) ) {
1181 $code_source = str_replace( ABSPATH, '', $code_source );
1182 }
1183
1184 ob_start();
1185
1186 pods_help(
1187 sprintf(
1188 '<strong>%s:</strong> %s',
1189 esc_html__( 'Code source', 'pods' ),
1190 esc_html( $code_source )
1191 ),
1192 null,
1193 '.pods-admin-container'
1194 );
1195
1196 $source .= ' ' . ob_get_clean();
1197 }
1198 }
1199 }
1200
1201 $pod = [
1202 'id' => $pod['id'],
1203 'label' => $pod['label'],
1204 'name' => $pod['name'],
1205 'object' => $pod['object'],
1206 'type' => $pod_type,
1207 'real_type' => $pod_real_type,
1208 'storage' => $storage_type_label,
1209 'source' => $source,
1210 'pod_object' => $pod,
1211 ];
1212
1213 if ( ! pods_is_types_only( false, $pod['name'] ) ) {
1214 $pod['group_count'] = number_format_i18n( $group_count );
1215 $pod['field_count'] = number_format_i18n( $field_count );
1216
1217 $total_groups += $group_count;
1218 $total_fields += $field_count;
1219 }
1220
1221 if ( $include_row_counts ) {
1222 $pod['row_count'] = number_format_i18n( $row_counts['row_count'] );
1223
1224 $total_rows += $row_counts['row_count'];
1225
1226 $pod['row_meta_count'] = 'n/a';
1227 $pod['podsrel_count'] = 'n/a';
1228
1229 if ( $show_meta_count ) {
1230 $pod['row_meta_count'] = number_format_i18n( $row_counts['row_meta_count'] );
1231
1232 $total_row_meta += $row_counts['row_meta_count'];
1233 }
1234
1235 if ( ! $is_tableless ) {
1236 $pod['podsrel_count'] = number_format_i18n( $row_counts['podsrel_count'] );
1237
1238 $total_podsrel_rows += $row_counts['podsrel_count'];
1239 }
1240 }
1241
1242 // @codingStandardsIgnoreLine
1243 if ( 'manage' !== pods_v( 'action' ) ) {
1244 $found_id = (int) pods_v( 'id' );
1245 $found_name = pods_v( 'name' );
1246
1247 if (
1248 (
1249 $found_id
1250 && $pod['id'] === $found_id
1251 )
1252 || (
1253 $found_name
1254 && $pod['name'] === $found_name
1255 )
1256 ) {
1257 $row = $pod;
1258 }
1259 }
1260
1261 $pod_list[] = $pod;
1262 }//end foreach
1263
1264 if ( ! $has_storage_type ) {
1265 unset( $fields['storage'] );
1266 }
1267
1268 if ( ! $has_source ) {
1269 unset( $fields['source'] );
1270 }
1271
1272 if (
1273 (
1274 0 === $total_groups
1275 && 0 === $total_fields
1276 )
1277 || pods_is_types_only()
1278 ) {
1279 unset( $fields['group_count'], $fields['field_count'] );
1280 }
1281
1282 if ( false === $row && 0 < pods_v( 'id' ) && 'delete' !== pods_v( 'action' ) ) {
1283 pods_message( 'Pod not found', 'error' );
1284
1285 // @codingStandardsIgnoreLine
1286 unset( $_GET['id'], $_GET['action'] );
1287 }
1288
1289 $total_pods = count( $pod_list );
1290
1291 $extra_total_text = '';
1292
1293 if ( ! pods_is_types_only() ) {
1294 $extra_total_text .= sprintf(
1295 ', %1$s %2$s, %3$s %4$s',
1296 number_format_i18n( $total_groups ),
1297 _n( 'group', 'groups', $total_groups, 'pods' ),
1298 number_format_i18n( $total_fields ),
1299 _n( 'field', 'fields', $total_fields, 'pods' )
1300 );
1301 }
1302
1303 if ( $include_row_counts ) {
1304 $extra_total_text .= sprintf(
1305 ', %1$s %2$s, %3$s %4$s, %5$s %6$s',
1306 number_format_i18n( $total_rows ),
1307 _n( 'data row', 'data rows', $total_rows, 'pods' ),
1308 number_format_i18n( $total_row_meta ),
1309 _n( 'meta row', 'meta rows', $total_row_meta, 'pods' ),
1310 number_format_i18n( $total_podsrel_rows ),
1311 // translators: "podsrel" references the name of the Pods relationships table in the database.
1312 _n( 'podsrel row', 'podsrel rows', $total_podsrel_rows, 'pods' )
1313 );
1314 }
1315
1316 $pod_list = wp_list_sort( $pod_list, 'label', 'ASC', true );
1317
1318 $ui = [
1319 'data' => $pod_list,
1320 'row' => $row,
1321 'total' => $total_pods,
1322 'total_found' => $total_pods,
1323 'items' => 'Pods',
1324 'item' => 'Pod',
1325 'fields' => [
1326 'manage' => $fields,
1327 ],
1328 'sql' => [
1329 'field_id' => 'id',
1330 'field_index' => 'label',
1331 ],
1332 'actions_disabled' => [ 'view', 'export', 'delete', 'duplicate' ],
1333 'actions_custom' => [
1334 'add' => [ $this, 'admin_setup_add' ],
1335 'edit' => [
1336 'callback' => [ $this, 'admin_setup_edit' ],
1337 'restrict_callback' => [ $this, 'admin_restrict_non_db_type' ],
1338 ],
1339 'duplicate_pod' => [
1340 'label' => __( 'Duplicate', 'pods' ),
1341 'callback' => [ $this, 'admin_setup_duplicate' ],
1342 'restrict_callback' => [ $this, 'admin_setup_duplicate_restrict' ],
1343 'nonce' => true,
1344 ],
1345 'delete_pod' => [
1346 'label' => __( 'Delete', 'pods' ),
1347 'confirm' => __( 'Are you sure you want to delete this Pod?', 'pods' )
1348 . "\n\n"
1349 . __( 'All of the content and items will remain in the database.', 'pods' )
1350 . "\n\n"
1351 . __( 'You may want to go to Pods Admin > Settings > Cleanup & Reset > "Delete all content for a Pod" first.', 'pods' ),
1352 'callback' => [ $this, 'admin_setup_delete' ],
1353 'restrict_callback' => [ $this, 'admin_restrict_non_db_type' ],
1354 'nonce' => true,
1355 'span_class' => 'delete',
1356 ],
1357 ],
1358 'action_links' => [
1359 'add' => pods_query_arg( [
1360 'page' => 'pods-add-new',
1361 'action' => '',
1362 'id' => '',
1363 'do' => '',
1364 '_wpnonce' => '',
1365 ] ),
1366 'duplicate_pod' => pods_query_arg( [
1367 'action' => 'duplicate_pod',
1368 'id' => '{@id}',
1369 'name' => '{@name}',
1370 ] ),
1371 ],
1372 'search' => false,
1373 'searchable' => false,
1374 'sortable' => true,
1375 'pagination' => false,
1376 'extra' => [
1377 'total' => $extra_total_text,
1378 ],
1379 ];
1380
1381 if ( 1 < count( $pod_types_found ) ) {
1382 $ui['views'] = [ 'all' => __( 'All', 'pods' ) . ' (' . $total_pods . ')' ];
1383 $ui['view'] = $view;
1384 $ui['heading'] = [ 'views' => __( 'Type', 'pods' ) ];
1385 $ui['filters_enhanced'] = true;
1386
1387 foreach ( $pod_types_found as $pod_type => $number_found ) {
1388 $ui['views'][ $pod_type ] = sprintf(
1389 '%1$s (%2$s)',
1390 $pod_types[ $pod_type ],
1391 number_format_i18n( $number_found )
1392 );
1393 }
1394
1395 if ( $has_source && 1 < count( $sources_found ) ) {
1396 foreach ( $sources_found as $source_type => $number_found ) {
1397 $ui['views'][ 'source/' . $source_type ] = sprintf(
1398 '%1$s: %2$s (%3$s)',
1399 __( 'Source', 'pods' ),
1400 $source_types[ $source_type ],
1401 $number_found
1402 );
1403 }
1404 }
1405 }
1406
1407 // Maybe auto-map the slugs to ID when editing.
1408 if ( 'edit' === $action && $id && ! is_numeric( $id ) ) {
1409 foreach ( $ui['data'] as $check_pod ) {
1410 if ( $check_pod['name'] === $id && $check_pod['id'] && is_numeric( $check_pod['id'] ) ) {
1411 pods_redirect( pods_query_arg( [ 'id' => (int) $check_pod['id'] ] ) );
1412
1413 break;
1414 }
1415 }
1416 }
1417
1418 // Add our custom callouts.
1419 $this->handle_callouts_updates();
1420
1421 add_filter( 'pods_ui_manage_custom_container_classes', array( $this, 'admin_manage_container_class' ) );
1422
1423 if ( $this->has_horizontal_callout() ) {
1424 add_action( 'pods_ui_manage_before_container', [ $this, 'admin_manage_callouts' ] );
1425 } else {
1426 add_action( 'pods_ui_manage_after_container', [ $this, 'admin_manage_callouts' ] );
1427 }
1428
1429 pods_ui( $ui );
1430 }
1431
1432 /**
1433 * Handle the Review Access Rights screen.
1434 */
1435 public function admin_access_rights_review() {
1436 $api = pods_api();
1437
1438 $pods = $api->load_pods( [ 'fields' => false ] );
1439
1440 if ( empty( $pods ) ) {
1441 pods_message( __( 'You do not have any Pods set up yet.', 'pods ' ) );
1442 }
1443
1444 $pod_types = $api->get_pod_types();
1445
1446 $first_pods_version = get_option( 'pods_framework_version_first' );
1447 $first_pods_version = '' === $first_pods_version ? PODS_VERSION : $first_pods_version;
1448
1449 $dynamic_features_allow_options = pods_access_get_dynamic_features_allow_options();
1450 $restricted_dynamic_features_options = pods_access_get_restricted_dynamic_features_options();
1451
1452 $other_view_groups = [
1453 'public' => [
1454 'label' => __( 'Content Privacy', 'pods' ),
1455 'views' => [
1456 '1' => [
1457 'label' => __( 'Public', 'pods' ),
1458 'count' => 0,
1459 ],
1460 '0' => [
1461 'label' => __( 'Private', 'pods' ),
1462 'count' => 0,
1463 ],
1464 ],
1465 ],
1466 'dynamic_features_allow' => [
1467 'label' => __( 'Dynamic Features', 'pods' ),
1468 'views' => [],
1469 ],
1470 'restricted_dynamic_features' => [
1471 'label' => __( 'Dynamic Features', 'pods' ),
1472 'views' => [
1473 'unrestricted' => [
1474 'label' => __( 'Unrestricted', 'pods' ),
1475 'count' => 0,
1476 ],
1477 'restricted' => [
1478 'label' => __( 'Restricted', 'pods' ),
1479 'count' => 0,
1480 ],
1481 ],
1482 ],
1483 ];
1484
1485 foreach ( $dynamic_features_allow_options as $dynamic_features_allow_option => $dynamic_features_allow_option_label ) {
1486 $other_view_groups['dynamic_features_allow']['views'][ $dynamic_features_allow_option ] = [
1487 'label' => trim( str_replace( '🔒', '', $dynamic_features_allow_option_label ) ),
1488 'count' => 0,
1489 ];
1490 }
1491
1492 $other_view_groups['dynamic_features_allow']['views']['inherit']['label'] = __( 'WP Default', 'pods' );
1493
1494 $row = false;
1495
1496 $pod_types_found = [];
1497 $sources_found = [];
1498 $source_types = [];
1499
1500 $fields = [
1501 'label' => [
1502 'label' => __( 'Label', 'pods' ),
1503 ],
1504 'name' => [
1505 'label' => __( 'Name', 'pods' ),
1506 ],
1507 'type' => [
1508 'label' => __( 'Type', 'pods' ),
1509 ],
1510 'source' => [
1511 'label' => __( 'Source', 'pods' ),
1512 'width' => '10%',
1513 'type' => 'raw',
1514 ],
1515 'public' => [
1516 'label' => __( 'Content Privacy', 'pods' ),
1517 'type' => 'raw',
1518 ],
1519 'dynamic_features_allow' => [
1520 'label' => __( 'Allow Dynamic Features', 'pods' ),
1521 'type' => 'raw',
1522 ],
1523 'restricted_dynamic_features' => [
1524 'label' => __( 'Restricted Dynamic Features', 'pods' ),
1525 'type' => 'pick',
1526 ],
1527 ];
1528
1529 /**
1530 * Filters whether to extend internal Pods.
1531 *
1532 * @since 2.8.0
1533 *
1534 * @param bool $extend_internal Whether to extend internal Pods.
1535 */
1536 $extend_internal = apply_filters( 'pods_admin_setup_extend_pods_internal', false );
1537
1538 $pod_list = array();
1539
1540 $has_source = false;
1541
1542 foreach ( $pods as $k => $pod ) {
1543 $pod_type = $pod['type'];
1544 $pod_type_label = null;
1545
1546 if ( empty( $pod_type ) || ! is_string( $pod_type ) ) {
1547 $pod_type = 'post_type';
1548 }
1549
1550 if ( ! empty( $pod['internal'] ) ) {
1551 // Don't show internal if we aren't extending them.
1552 if ( ! $extend_internal ) {
1553 continue;
1554 }
1555
1556 $pod_type = 'internal';
1557 }
1558
1559 if ( isset( $pod_types[ $pod_type ] ) ) {
1560 $pod_type_label = $pod_types[ $pod_type ];
1561 }
1562
1563 $pod_real_type = $pod_type;
1564
1565 if ( null !== $pod_type_label ) {
1566 if ( ! $pod->is_extended() && in_array( $pod_type, array(
1567 'post_type',
1568 'taxonomy',
1569 ), true ) ) {
1570 if ( 'post_type' === $pod_type ) {
1571 $pod_type = 'cpt';
1572 } else {
1573 $pod_type = 'ct';
1574 }
1575
1576 if ( isset( $pod_types[ $pod_type ] ) ) {
1577 $pod_type_label = $pod_types[ $pod_type ];
1578 }
1579 }
1580
1581 if ( ! isset( $pod_types_found[ $pod_type ] ) ) {
1582 $pod_types_found[ $pod_type ] = 1;
1583 } else {
1584 $pod_types_found[ $pod_type ] ++;
1585 }
1586
1587 $pod_real_type = $pod_type;
1588 $pod_type = $pod_type_label;
1589 }
1590
1591 $object_storage_type = $pod->get_object_storage_type();
1592 $source = $pod->get_object_storage_type_label();
1593
1594 if ( $source ) {
1595 $source_types[ $object_storage_type ] = $source;
1596
1597 if ( ! isset( $sources_found[ $object_storage_type ] ) ) {
1598 $sources_found[ $object_storage_type ] = 1;
1599 } else {
1600 $sources_found[ $object_storage_type ] ++;
1601 }
1602 }
1603
1604 $source = esc_html( $source );
1605
1606 if ( 'post_type' !== $object_storage_type ) {
1607 $has_source = true;
1608
1609 if ( 'file' === $object_storage_type ) {
1610 $file_source = $pod->get_arg( '_pods_file_source' );
1611
1612 if ( $file_source ) {
1613 if ( 0 === strpos( $file_source, ABSPATH ) ) {
1614 $file_source = str_replace( ABSPATH, '', $file_source );
1615 }
1616
1617 $source .= ' ' . pods_help(
1618 sprintf(
1619 '<strong>%s:</strong> %s',
1620 esc_html__( 'File source', 'pods' ),
1621 esc_html( $file_source )
1622 ),
1623 null,
1624 '.pods-admin-container',
1625 true
1626 );
1627 }
1628 } elseif ( 'collection' === $object_storage_type ) {
1629 $code_source = $pod->get_arg( '_pods_code_source' );
1630
1631 if ( $code_source ) {
1632 if ( 0 === strpos( $code_source, ABSPATH ) ) {
1633 $code_source = str_replace( ABSPATH, '', $code_source );
1634 }
1635
1636 $source .= ' ' . pods_help(
1637 sprintf(
1638 '<strong>%s:</strong> %s',
1639 esc_html__( 'Code source', 'pods' ),
1640 esc_html( $code_source )
1641 ),
1642 null,
1643 '.pods-admin-container',
1644 true
1645 );
1646 }
1647 }
1648 }
1649
1650 $is_public = pods_is_type_public(
1651 [
1652 'pod' => $pod,
1653 ]
1654 );
1655
1656 $dynamic_features_allow_default = 'inherit';
1657
1658 if ( 'pod' === $pod->get_type() ) {
1659 $dynamic_features_allow_default = version_compare( $first_pods_version, '3.1.0-a-1', '<' ) ? '1' : '0';
1660 }
1661
1662 $dynamic_features_allow = $pod->get_arg( 'dynamic_features_allow', $dynamic_features_allow_default, true );
1663
1664 if ( isset( $other_view_groups['dynamic_features_allow']['views'][ $dynamic_features_allow ] ) ) {
1665 $other_view_groups['dynamic_features_allow']['views'][ $dynamic_features_allow ]['count'] ++;
1666 }
1667
1668 $dynamic_features_allow_label = isset( $dynamic_features_allow_options[ $dynamic_features_allow ] ) ? $dynamic_features_allow_options[ $dynamic_features_allow ] : $dynamic_features_allow_options[ $dynamic_features_allow_default ];
1669
1670 if ( $dynamic_features_allow_label === $dynamic_features_allow_options['inherit'] ) {
1671 $dynamic_features_allow_label .= ' - ' . ( $is_public ? $dynamic_features_allow_options['1'] : $dynamic_features_allow_options['0'] );
1672 }
1673
1674 $restrict_dynamic_features = (int) $pod->get_arg( 'restrict_dynamic_features', '1' );
1675
1676 $pod_row = [
1677 'id' => $pod['id'],
1678 'label' => $pod['label'],
1679 'name' => $pod['name'],
1680 'object' => $pod['object'],
1681 'type' => $pod_type,
1682 'real_type' => $pod_real_type,
1683 'source' => $source,
1684 'real_source' => $object_storage_type,
1685 'bulk_disabled' => 'post_type' !== $object_storage_type,
1686 'pod_object' => $pod,
1687 'public' => $is_public ? __( 'Public', 'pods' ) : '🔒 ' . __( 'Private', 'pods' ),
1688 'real_public' => $is_public ? 1 : 0,
1689 'dynamic_features_allow' => $dynamic_features_allow_label,
1690 'real_dynamic_features_allow' => $dynamic_features_allow,
1691 'restricted_dynamic_features' => $pod->get_arg( 'restricted_dynamic_features' ),
1692 ];
1693
1694 if ( 0 === $restrict_dynamic_features ) {
1695 $pod_row['restricted_dynamic_features'] = [];
1696 }
1697
1698 if ( ! is_array( $pod_row['restricted_dynamic_features'] ) ) {
1699 $pod_row['restricted_dynamic_features'] = [
1700 'display',
1701 'form',
1702 ];
1703 }
1704
1705 if ( $pod->is_extended() ) {
1706 $extended_help_text = pods_help(
1707 __( 'This is an extended content type. The Content Privacy cannot be changed by Pods. You can choose to enable Dynamic Features separately anyway if it has "WP Default" used.', 'pods' ),
1708 null,
1709 '.pods-admin-container',
1710 true
1711 );
1712
1713 $pod_row['public'] .= $extended_help_text;
1714
1715 if ( 'inherit' === $dynamic_features_allow ) {
1716 $pod_row['dynamic_features_allow'] .= $extended_help_text;
1717 }
1718 }
1719
1720 $other_view_groups['public']['views'][ (string) $pod_row['real_public'] ]['count'] ++;
1721
1722 if ( empty( $pod_row['restricted_dynamic_features'] ) ) {
1723 $pod_row['restricted_dynamic_features'] = __( 'Unrestricted', 'pods' );
1724 $pod_row['real_restricted_dynamic_features'] = 'unrestricted';
1725 } else {
1726 foreach ( $pod_row['restricted_dynamic_features'] as $fk => $feature ) {
1727 $pod_row['restricted_dynamic_features'][ $fk ] = pods_v( $feature, $restricted_dynamic_features_options, ucwords( $feature ) );
1728 }
1729
1730 $pod_row['real_restricted_dynamic_features'] = 'restricted';
1731 }
1732
1733 $other_view_groups['restricted_dynamic_features']['views'][ $pod_row['real_restricted_dynamic_features'] ]['count'] ++;
1734
1735 // @codingStandardsIgnoreLine
1736 if ( 'manage' !== pods_v( 'action' ) ) {
1737 $found_id = (int) pods_v( 'id' );
1738 $found_name = pods_v( 'name' );
1739
1740 if (
1741 (
1742 $found_id
1743 && $pod_row['id'] === $found_id
1744 )
1745 || (
1746 $found_name
1747 && $pod_row['name'] === $found_name
1748 )
1749 ) {
1750 $row = $pod_row;
1751 }
1752 }
1753
1754 $pod_list[] = $pod_row;
1755 }//end foreach
1756
1757 if ( ! $has_source ) {
1758 unset( $fields['source'] );
1759 }
1760
1761 if ( false === $row && 0 < pods_v( 'id' ) && 'delete' !== pods_v( 'action' ) ) {
1762 pods_message( 'Pod not found', 'error' );
1763
1764 // @codingStandardsIgnoreLine
1765 unset( $_GET['id'], $_GET['action'] );
1766 }
1767
1768 $total_pods = count( $pod_list );
1769
1770 $total_pods_unfiltered = $total_pods;
1771
1772 // Handle filtering.
1773 $view_filters = [
1774 'type' => 'real_type',
1775 'source' => 'real_source',
1776 'public' => 'real_public',
1777 'dynamic_features_allow' => 'real_dynamic_features_allow',
1778 'restricted_dynamic_features' => 'real_restricted_dynamic_features',
1779 ];
1780
1781 $view = pods_v( 'view', 'get', 'all', true );
1782 $view_filter_info = explode( '/', $view );
1783 $view_filter_group_active = isset( $view_filter_info[0] ) ? $view_filter_info[0] : null;
1784 $view_filter_key_active = isset( $view_filter_info[1] ) ? $view_filter_info[1] : null;
1785
1786 foreach ( $view_filters as $view_filter => $real_key ) {
1787 if ( $view_filter_group_active !== $view_filter ) {
1788 continue;
1789 }
1790
1791 foreach ( $pod_list as $pod_key => $pod ) {
1792 // Maybe remove the pod from the list.
1793 if ( (string) $view_filter_key_active !== (string) $pod[ $real_key ] ) {
1794 unset( $pod_list[ $pod_key ] );
1795 }
1796 }
1797 }
1798
1799 $pod_list = wp_list_sort( array_values( $pod_list ), 'label' );
1800
1801 $total_pods = count( $pod_list );
1802
1803 $ui = [
1804 'data' => $pod_list,
1805 'row' => $row,
1806 'total' => $total_pods,
1807 'total_found' => $total_pods,
1808 'items' => 'Pods',
1809 'item' => 'Pod',
1810 'header' => [
1811 'manage' => '🔒 ' . __( 'Review Access Rights for Pods', 'pods' ),
1812 ],
1813 'fields' => [
1814 'manage' => $fields,
1815 ],
1816 'sql' => [
1817 'field_id' => 'id',
1818 'field_index' => 'label',
1819 ],
1820 'actions_disabled' => [ 'add', 'view', 'export', 'delete', 'duplicate' ],
1821 'actions_custom' => [
1822 'edit' => [
1823 'label' => __( 'Edit Pod', 'pods' ),
1824 'restrict_callback' => [ $this, 'admin_restrict_non_db_type' ],
1825 ],
1826 'make_public' => [
1827 'label' => __( 'Make public', 'pods' ),
1828 'callback' => [ $this, 'admin_access_rights_review_make_public' ],
1829 'restrict_callback' => [ $this, 'admin_restrict_access_rights_review_make_public' ],
1830 'nonce' => true,
1831 ],
1832 'make_private' => [
1833 'label' => __( 'Make private', 'pods' ),
1834 'callback' => [ $this, 'admin_access_rights_review_make_private' ],
1835 'restrict_callback' => [ $this, 'admin_restrict_access_rights_review_make_private' ],
1836 'nonce' => true,
1837 ],
1838 'wp_default_dynamic_features' => [
1839 'label' => __( 'Set Dynamic Features to WP Default', 'pods' ),
1840 'callback' => [ $this, 'admin_access_rights_review_wp_default_dynamic_features' ],
1841 'restrict_callback' => [ $this, 'admin_restrict_access_rights_review_wp_default_dynamic_features' ],
1842 'nonce' => true,
1843 ],
1844 'enable_dynamic_features' => [
1845 'label' => __( 'Enable Dynamic Features', 'pods' ),
1846 'callback' => [ $this, 'admin_access_rights_review_enable_dynamic_features' ],
1847 'restrict_callback' => [ $this, 'admin_restrict_access_rights_review_enable_dynamic_features' ],
1848 'nonce' => true,
1849 ],
1850 'disable_dynamic_features' => [
1851 'label' => __( 'Disable Dynamic Features', 'pods' ),
1852 'callback' => [ $this, 'admin_access_rights_review_disable_dynamic_features' ],
1853 'restrict_callback' => [ $this, 'admin_restrict_access_rights_review_disable_dynamic_features' ],
1854 'nonce' => true,
1855 ],
1856 'restrict_dynamic_features' => [
1857 'label' => __( 'Restrict all dynamic features', 'pods' ),
1858 'callback' => [ $this, 'admin_access_rights_review_restrict_dynamic_features' ],
1859 'restrict_callback' => [ $this, 'admin_restrict_access_rights_review_restrict_dynamic_features' ],
1860 'nonce' => true,
1861 ],
1862 'unrestrict_dynamic_features' => [
1863 'label' => __( 'Unrestrict all dynamic features', 'pods' ),
1864 'callback' => [ $this, 'admin_access_rights_review_unrestrict_dynamic_features' ],
1865 'restrict_callback' => [ $this, 'admin_restrict_access_rights_review_unrestrict_dynamic_features' ],
1866 'nonce' => true,
1867 ],
1868 ],
1869 'actions_bulk' => [
1870 'make_public' => [
1871 'label' => __( 'Make public', 'pods' ),
1872 'callback' => [ $this, 'admin_access_rights_review_make_public_bulk' ],
1873 ],
1874 'make_private' => [
1875 'label' => __( 'Make private', 'pods' ),
1876 'callback' => [ $this, 'admin_access_rights_review_make_private_bulk' ],
1877 ],
1878 'wp_default_dynamic_features' => [
1879 'label' => __( 'Set Dynamic Features to WP Default', 'pods' ),
1880 'callback' => [ $this, 'admin_access_rights_review_wp_default_dynamic_features_bulk' ],
1881 ],
1882 'enable_dynamic_features' => [
1883 'label' => __( 'Enable Dynamic Features', 'pods' ),
1884 'callback' => [ $this, 'admin_access_rights_review_enable_dynamic_features_bulk' ],
1885 ],
1886 'disable_dynamic_features' => [
1887 'label' => __( 'Disable Dynamic Features', 'pods' ),
1888 'callback' => [ $this, 'admin_access_rights_review_disable_dynamic_features_bulk' ],
1889 ],
1890 'restrict_dynamic_features' => [
1891 'label' => __( 'Restrict all dynamic features', 'pods' ),
1892 'callback' => [ $this, 'admin_access_rights_review_restrict_dynamic_features_bulk' ],
1893 ],
1894 'unrestrict_dynamic_features' => [
1895 'label' => __( 'Unrestrict all dynamic features', 'pods' ),
1896 'callback' => [ $this, 'admin_access_rights_review_unrestrict_dynamic_features_bulk' ],
1897 ],
1898 ],
1899 'action_links' => [
1900 'edit' => pods_query_arg( [
1901 'page' => 'pods',
1902 'action' => 'edit',
1903 'id' => '{@id}',
1904 'name' => '{@name}',
1905 ] ),
1906 ],
1907 'search' => false,
1908 'searchable' => false,
1909 'sortable' => true,
1910 'pagination' => false,
1911 ];
1912
1913 $ui['views'] = [ 'all' => __( 'All', 'pods' ) . ' (' . $total_pods_unfiltered . ')' ];
1914 $ui['view'] = $view;
1915 $ui['heading'] = [ 'views' => __( 'View', 'pods' ) ];
1916 $ui['filters_enhanced'] = true;
1917
1918 if ( 1 < count( $pod_types_found ) ) {
1919 foreach ( $pod_types_found as $pod_type => $number_found ) {
1920 $ui['views'][ 'type/' . $pod_type ] = sprintf(
1921 '<strong>%1$s:</strong> %2$s (%3$s)',
1922 esc_html__( 'Type', 'pods' ),
1923 esc_html( $pod_types[ $pod_type ] ),
1924 number_format_i18n( $number_found )
1925 );
1926 }
1927 }
1928
1929 if ( $has_source && 1 < count( $sources_found ) ) {
1930 foreach ( $sources_found as $source_type => $number_found ) {
1931 $ui['views'][ 'source/' . $source_type ] = sprintf(
1932 '<strong>%1$s:</strong> %2$s (%3$s)',
1933 esc_html__( 'Source', 'pods' ),
1934 esc_html( $source_types[ $source_type ] ),
1935 number_format_i18n( $number_found )
1936 );
1937 }
1938 }
1939
1940 foreach ( $other_view_groups as $view_group_key => $view_group_info ) {
1941 if ( empty( $view_group_info['views'] ) ) {
1942 continue;
1943 }
1944
1945 foreach ( $view_group_info['views'] as $view_key => $view_info ) {
1946 $ui['views'][ $view_group_key . '/' . $view_key ] = sprintf(
1947 '<strong>%1$s:</strong> %2$s (%3$s)',
1948 $view_group_info['label'],
1949 esc_html( $view_info['label'] ),
1950 number_format_i18n( $view_info['count'] )
1951 );
1952 }
1953 }
1954
1955 $this->handle_callouts_updates();
1956
1957 add_action( 'pods_ui_manage_before_filters', static function() {
1958 $callout_dismiss_link = add_query_arg( [
1959 'pods_callout_dismiss' => 'access_rights',
1960 'pods_callout_dismiss_nonce' => wp_create_nonce( 'pods_callout_dismiss_access_rights' ),
1961 ] );
1962
1963 pods_message(
1964 wpautop(
1965 esc_html__( 'This screen is for reviewing the access rights and settings for your Pods. You can change the access rights for each Pod individually or in bulk.', 'pods' )
1966 . "\n\n" . esc_html__( 'Carefully review whether your content types should be public and if dynamic features should be allowed.', 'pods' )
1967 . "\n\n" . '<a href="https://docs.pods.io/displaying-pods/access-rights-in-pods/" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Read the documentation for more information', 'pods' ) . ' &raquo;</a>'
1968 ),
1969 'info',
1970 false,
1971 false
1972 );
1973
1974 $callouts = PodsAdmin::$instance->get_callouts();
1975
1976 if ( ! empty( $callouts['access_rights'] ) ) {
1977 pods_message(
1978 wpautop(
1979 esc_html__( 'You have not confirmed your Pods access rights below yet.', 'pods' )
1980 . "\n\n" . esc_html__( 'Make changes below or confirm them.', 'pods' )
1981 . "\n\n" . '<a href="' . esc_url( $callout_dismiss_link ) . '" class="button button-primary">' . esc_html__( 'Yes, I confirm the access rights below are correct for my site', 'pods' ) . '</a>'
1982 ),
1983 'warning',
1984 false,
1985 false
1986 );
1987 }
1988
1989 if ( ! pods_can_use_dynamic_features() ) {
1990 pods_message(
1991 wpautop(
1992 sprintf(
1993 '
1994 🔒 %s
1995
1996 <a href="%s">%s &raquo;</a>
1997 ',
1998 esc_html__( 'Dynamic Features are currently disabled globally which will automatically override any Dynamic Feature setting below from being referenced.', 'pods' ),
1999 esc_url( admin_url( 'admin.php?page=pods-settings' ) ),
2000 esc_html__( 'You can adjust this in your Pods Settings', 'pods' )
2001 )
2002 ),
2003 'error',
2004 false,
2005 false
2006 );
2007 }
2008 } );
2009
2010 pods_ui( $ui );
2011 }
2012
2013 /**
2014 * Get list of callouts to show.
2015 *
2016 * @since 2.7.17
2017 *
2018 * @return array List of callouts.
2019 */
2020 public function get_callouts() {
2021 // Demo mode always bypasses callouts.
2022 if ( pods_is_demo() ) {
2023 return [];
2024 }
2025
2026 $force_callouts = 1 === (int) pods_v( 'pods_force_callouts' );
2027
2028 $page = pods_v( 'page' );
2029
2030 if ( in_array( $page, array( 'pods-settings', 'pods-help' ), true ) ) {
2031 $force_callouts = true;
2032 }
2033
2034 $callouts = get_option( 'pods_callouts' );
2035
2036 if ( ! $callouts ) {
2037 $callouts = [
2038 'friends_2024_docs' => 1,
2039 'access_rights' => (
2040 PodsInit::$version_last
2041 && version_compare( PodsInit::$version_last, '3.1.0-a-1', '<' )
2042 ) ? 1 : 0,
2043 ];
2044
2045 update_option( 'pods_callouts', $callouts );
2046 }
2047
2048 // Handle callouts logic.
2049 $callouts['access_rights'] = ! isset( $callouts['access_rights'] ) || $callouts['access_rights'] ? 1 : 0;
2050 $callouts['friends_2024_docs'] = ! isset( $callouts['friends_2024_docs'] ) || $callouts['friends_2024_docs'] || $force_callouts ? 1 : 0;
2051
2052 /**
2053 * Allow hooking into whether or not the specific callouts should show.
2054 *
2055 * @since 2.7.17
2056 *
2057 * @param array $callouts List of callouts to enable.
2058 */
2059 $callouts = apply_filters( 'pods_admin_callouts', $callouts );
2060
2061 return $callouts;
2062 }
2063
2064 /**
2065 * Determine whether there's a horizontal callout.
2066 *
2067 * @since 3.1.0
2068 *
2069 * @param array $callouts The list of callouts if available, otherwise it will be fetched.
2070 *
2071 * @return bool Whether there's a horizontal callout.
2072 */
2073 public function has_horizontal_callout( array $callouts = [] ): bool {
2074 if ( ! $callouts ) {
2075 $callouts = $this->get_callouts();
2076 }
2077
2078 return ! empty( $callouts['access_rights'] );
2079 }
2080
2081 /**
2082 * Handle callouts update logic.
2083 *
2084 * @since 2.7.17
2085 */
2086 public function handle_callouts_updates() {
2087 $callouts = get_option( 'pods_callouts' );
2088
2089 if ( ! $callouts ) {
2090 $callouts = array();
2091 }
2092
2093 $callout_dismiss = sanitize_text_field( pods_v( 'pods_callout_dismiss' ) );
2094 $callout_dismiss_nonce = pods_v( 'pods_callout_dismiss_nonce' );
2095
2096 // Demo mode will auto-update the option for future loads.
2097 $is_demo = pods_is_demo();
2098
2099 // Handle reset dismiss separately.
2100 if ( 'reset' === $callout_dismiss && pods_is_admin() ) {
2101 // Internal-only action.
2102
2103 // Reset callouts.
2104 update_option( 'pods_callouts', [] );
2105
2106 return;
2107 }
2108
2109 // Invalid nonce, cannot do anything with this dismiss request.
2110 if (
2111 ! $is_demo
2112 && (
2113 ! $callout_dismiss_nonce
2114 || false === wp_verify_nonce( $callout_dismiss_nonce, 'pods_callout_dismiss_' . $callout_dismiss )
2115 )
2116 ) {
2117 return;
2118 }
2119
2120 if ( $is_demo ) {
2121 // Disable Friends of Pods callout on demos.
2122 $callout_dismiss = 'friends_2024_docs';
2123 }
2124
2125 if ( $callout_dismiss ) {
2126 $this->update_callout( $callout_dismiss, false );
2127 }
2128 }
2129
2130 /**
2131 * Handle updating whether a callout should be enabled.
2132 *
2133 * @since 3.1.0
2134 *
2135 * @param string $callout The callout to update.
2136 * @param bool $enabled Whether the callout should be enabled.
2137 */
2138 public function update_callout( string $callout, bool $enabled ) {
2139 $callouts = get_option( 'pods_callouts' );
2140
2141 if ( ! $callouts ) {
2142 $callouts = array();
2143 }
2144
2145 $callouts[ $callout ] = (int) $enabled;
2146
2147 update_option( 'pods_callouts', $callouts );
2148 }
2149
2150 /**
2151 * Add class to container if we have callouts to show.
2152 *
2153 * @since 2.7.17
2154 *
2155 * @param array $classes List of classes to use.
2156 *
2157 * @return array List of classes to use.
2158 */
2159 public function admin_manage_container_class( $classes ) {
2160 $callouts = $this->get_callouts();
2161
2162 // Only get enabled callouts.
2163 $callouts = array_filter( $callouts );
2164
2165 if ( ! empty( $callouts ) ) {
2166 if ( $this->has_horizontal_callout( $callouts ) ) {
2167 $classes[] = 'pods-admin--flex-horizontal';
2168 } else {
2169 $classes[] = 'pods-admin--flex';
2170 }
2171 }
2172
2173 return $classes;
2174 }
2175
2176 /**
2177 * Add callouts to let admins know about certain things.
2178 *
2179 * @since 2.7.17
2180 */
2181 public function admin_manage_callouts() {
2182 static $did_callout = false;
2183
2184 if ( $did_callout ) {
2185 return;
2186 }
2187
2188 $force_callouts = false;
2189
2190 $page = pods_v( 'page' );
2191
2192 if ( in_array( $page, array( 'pods-settings', 'pods-help' ), true ) ) {
2193 $force_callouts = true;
2194 }
2195
2196 $callouts = $this->get_callouts();
2197
2198 if ( ! empty( $callouts['access_rights'] ) ) {
2199 $did_callout = true;
2200
2201 pods_view( PODS_DIR . 'ui/admin/callouts/access_rights.php', compact( array_keys( get_defined_vars() ) ) );
2202 } elseif ( ! empty( $callouts['friends_2024_docs'] ) ) {
2203 $did_callout = true;
2204
2205 pods_view( PODS_DIR . 'ui/admin/callouts/friends_2024_docs.php', compact( array_keys( get_defined_vars() ) ) );
2206 }
2207 }
2208
2209 /**
2210 * Get the add page of an object
2211 *
2212 * @param PodsUI $obj PodsUI object.
2213 */
2214 public function admin_setup_add( $obj ) {
2215 pods_view( PODS_DIR . 'ui/admin/setup-add.php', compact( array_keys( get_defined_vars() ) ) );
2216 }
2217
2218 /**
2219 * Get the edit page of an object
2220 *
2221 * @param boolean $duplicate Whether the screen is for duplicating.
2222 * @param PodsUI $obj PodsUI object.
2223 */
2224 public function admin_setup_edit( $duplicate, $obj ) {
2225 $api = pods_api();
2226
2227 $pod = $obj->row['pod_object'];
2228
2229 if ( ! $pod instanceof Pod ) {
2230 $obj->id = null;
2231 $obj->row = [];
2232 $obj->action = 'manage';
2233
2234 $obj->error( __( 'Invalid Pod configuration detected.', 'pods' ) );
2235 $obj->manage();
2236
2237 return null;
2238 }
2239
2240 if ( 'post_type' !== $pod->get_object_storage_type() ) {
2241 $obj->id = null;
2242 $obj->row = [];
2243 $obj->action = 'manage';
2244
2245 // translators: %s: The pod label.
2246 $obj->error( sprintf( __( 'Unable to edit the "%s" Pod configuration.', 'pods' ), $pod->get_label() ) );
2247 $obj->manage();
2248
2249 return null;
2250 }
2251
2252 $original_field_count = 0;
2253
2254 foreach ( $obj->data as $row ) {
2255 if ( (int) $row['id'] === (int) $obj->id ) {
2256 if ( ! isset( $row['field_count'] ) ) {
2257 $row['field_count'] = 0;
2258 }
2259
2260 $original_field_count = (int) $row['field_count'];
2261
2262 break;
2263 }
2264 }
2265
2266 $find_orphan_fields = (
2267 1 === (int) pods_v( 'pods_debug_find_orphan_fields', 'get', 0 )
2268 && pods_is_admin( array( 'pods' ) )
2269 );
2270
2271 $migrated = false;
2272
2273 if ( $find_orphan_fields || 1 !== (int) $pod->get_arg( '_migrated_28' ) ) {
2274 $pod = $this->maybe_migrate_pod_fields_into_group( $pod );
2275
2276 $migrated = true;
2277
2278 // Maybe redirect the page to reload it fresh.
2279 if ( $find_orphan_fields ) {
2280 pods_redirect( pods_query_arg( [ 'pods_debug_find_orphan_fields' => null ] ) );
2281 die();
2282 }
2283
2284 // Check again in case the pod migrated wrong.
2285 if ( ! $pod instanceof Pod ) {
2286 $obj->id = null;
2287 $obj->row = [];
2288 $obj->action = 'manage';
2289
2290 $obj->error( __( 'Invalid Pod configuration detected.', 'pods' ) );
2291 $obj->manage();
2292
2293 return null;
2294 }
2295 }
2296
2297 $current_pod = $pod->export( [
2298 'include_groups' => true,
2299 'include_group_fields' => true,
2300 'include_fields' => false,
2301 ] );
2302
2303 $group_field_count = wp_list_pluck( $current_pod['groups'], 'fields' );
2304 $group_field_count = array_map( 'count', $group_field_count );
2305 $group_field_count = array_sum( $group_field_count );
2306
2307 // Detect if there may be a migration/repair needed.
2308 if ( $original_field_count !== $group_field_count ) {
2309 if ( ! $migrated ) {
2310 $pod = $this->maybe_migrate_pod_fields_into_group( $pod );
2311
2312 // Check again in case the pod migrated wrong.
2313 if ( ! $pod instanceof Pod ) {
2314 $obj->id = null;
2315 $obj->row = [];
2316 $obj->action = 'manage';
2317
2318 $obj->error( __( 'Invalid Pod configuration detected.', 'pods' ) );
2319 $obj->manage();
2320
2321 return null;
2322 }
2323
2324 $current_pod = $pod->export( [
2325 'include_groups' => true,
2326 'include_group_fields' => true,
2327 'include_fields' => false,
2328 ] );
2329 } else {
2330 pods_message( __( 'You may need to repair this Pod, we detected some fields not assigned to the groups shown in this configuration. You can find the tool at Pods Admin > Settings > Tools.', 'pods' ) );
2331 }
2332 }
2333
2334 $config = [
2335 'currentPod' => $current_pod,
2336 'global' => $this->get_global_config( $pod ),
2337 'fieldTypes' => PodsForm::field_types(),
2338 'relatedObjects' => $this->get_field_related_objects(),
2339 'podTypes' => $api->get_pod_types(),
2340 'storageTypes' => $api->get_storage_types(),
2341 // @todo SKC: Remove these below and replace any references to podsDFVConfig
2342 'wp_locale' => $GLOBALS['wp_locale'],
2343 'userLocale' => str_replace( '_', '-', get_user_locale() ),
2344 'currencies' => PodsField_Currency::data_currencies(),
2345 'datetime' => [
2346 'start_of_week' => (int) get_option( 'start_of_week', 0 ),
2347 'gmt_offset' => (int) get_option( 'gmt_offset', 0 ),
2348 ],
2349 ];
2350
2351 $config['currentPod']['podType'] = [
2352 'name' => $config['currentPod']['type'],
2353 ];
2354
2355 $config['currentPod']['storageType'] = [
2356 'name' => $config['currentPod']['storage'],
2357 ];
2358
2359 if ( ! empty( $config['currentPod']['internal'] ) ) {
2360 $config['currentPod']['podType']['name'] = 'internal';
2361 } elseif ( ! $pod->is_extended() ) {
2362 if ( 'post_type' === $config['currentPod']['type'] ) {
2363 $config['currentPod']['podType']['name'] = 'cpt';
2364 } elseif ( 'taxonomy' === $config['currentPod']['type'] ) {
2365 $config['currentPod']['podType']['name'] = 'ct';
2366 }
2367 }
2368
2369 $config['currentPod']['podType']['label'] = ucwords( str_replace( '_', ' ', $config['currentPod']['podType']['name'] ) );
2370
2371 if ( ! empty( $config['podTypes'][ $config['currentPod']['podType']['name'] ] ) ) {
2372 $config['currentPod']['podType']['label'] = $config['podTypes'][ $config['currentPod']['podType']['name'] ];
2373 }
2374
2375 if ( 'settings' === $config['currentPod']['type'] ) {
2376 $config['currentPod']['storageType']['name'] = 'option';
2377 }
2378
2379 $config['currentPod']['storageType']['label'] = ucwords( $config['currentPod']['storageType']['name'] );
2380
2381 if ( ! empty( $config['storageTypes'][ $config['currentPod']['storageType']['name'] ] ) ) {
2382 $config['currentPod']['storageType']['label'] = $config['storageTypes'][ $config['currentPod']['storageType']['name'] ];
2383 }
2384
2385 /**
2386 * Allow filtering the admin config data.
2387 *
2388 * @since 2.8.0
2389 *
2390 * @param array $config The admin config data.
2391 * @param Pod $pod The pod object.
2392 * @param PodsUI $obj The PodsUI object.
2393 */
2394 $config = apply_filters( 'pods_admin_setup_edit_pod_config', $config, $pod, $obj );
2395
2396 wp_localize_script( 'pods-dfv', 'podsAdminConfig', $config );
2397
2398 pods_view( PODS_DIR . 'ui/admin/setup-edit.php', compact( array_keys( get_defined_vars() ) ) );
2399 }
2400
2401 /**
2402 * Get list of field related objects.
2403 *
2404 * @since 2.8.0
2405 *
2406 * @return array List of field related objects.
2407 */
2408 protected function get_field_related_objects() {
2409 $related_object_groups = PodsForm::field_method( 'pick', 'related_objects', true );
2410
2411 $related_objects = [];
2412
2413 foreach ( $related_object_groups as $group => $group_objects ) {
2414 foreach ( $group_objects as $name => $label ) {
2415 $related_objects[ $name ] = [
2416 'name' => $name,
2417 'label' => $label,
2418 ];
2419 }
2420 }
2421
2422 return $related_objects;
2423 }
2424
2425 /**
2426 * Maybe migrate pod fields into a group (if they have no group).
2427 *
2428 * @since 2.8.0
2429 *
2430 * @param Pod $pod The pod object.
2431 *
2432 * @return Pod The pod object.
2433 */
2434 public function maybe_migrate_pod_fields_into_group( $pod ) {
2435 $tool = pods_container( Repair::class );
2436
2437 $results = $tool->repair_groups_and_fields_for_pod( $pod, 'upgrade' );
2438
2439 if ( '' !== $results['message_html'] ) {
2440 if ( 'pods' === pods_v( 'page' ) && 'edit' === pods_v( 'action' ) && 'create' === pods_v( 'do' ) ) {
2441 // Refresh the page if we just added the Pod.
2442 pods_redirect();
2443 } else {
2444 pods_message( $results['message_html'] );
2445 }
2446 }
2447
2448 return $results['upgraded_pod'];
2449 }
2450
2451 /**
2452 * Get the global config for Pods admin.
2453 *
2454 * @param null|\Pods\Whatsit $current_pod
2455 *
2456 * @return array Global config array.
2457 *@since 2.8.0
2458 *
2459 */
2460 public function get_global_config( $current_pod = null ) {
2461 $config_pod = pods_container( Config_Pod::class );
2462 $config_group = pods_container( Config_Group::class );
2463 $config_field = pods_container( Config_Field::class );
2464
2465 // Pod: Backwards compatible configs and hooks.
2466 $pod_tabs = $config_pod->get_tabs( $current_pod);
2467 $pod_tab_options = $config_pod->get_fields( $current_pod, $pod_tabs );
2468
2469 $this->backcompat_convert_tabs_to_groups( $pod_tabs, $pod_tab_options, 'pod/_pods_pod' );
2470
2471 // If not types-only mode, handle groups/fields configs.
2472 if ( ! pods_is_types_only( false, $current_pod->get_name() ) ) {
2473 // Group: Backwards compatible methods and hooks.
2474 $group_tabs = $config_group->get_tabs( $current_pod);
2475 $group_tab_options = $config_group->get_fields( $current_pod, $group_tabs );
2476
2477 $this->backcompat_convert_tabs_to_groups( $group_tabs, $group_tab_options, 'pod/_pods_group' );
2478
2479 // Field: Backwards compatible methods and hooks.
2480 $field_tabs = $config_field->get_tabs( $current_pod);
2481 $field_tab_options = $config_field->get_fields( $current_pod, $field_tabs );
2482
2483 $this->backcompat_convert_tabs_to_groups( $field_tabs, $field_tab_options, 'pod/_pods_field' );
2484 }
2485
2486 $object_collection = Pods\Whatsit\Store::get_instance();
2487
2488 /** @var Pods\Whatsit\Storage $storage */
2489 $storage = $object_collection->get_storage_object( 'collection' );
2490
2491 // Get objects from storage.
2492 $pod_object = $storage->get( [
2493 'object_type' => 'pod',
2494 'name' => '_pods_pod',
2495 'bypass_cache' => true,
2496 ] );
2497
2498 $group_object = $storage->get( [
2499 'object_type' => 'pod',
2500 'name' => '_pods_group',
2501 'bypass_cache' => true,
2502 ] );
2503
2504 $field_object = $storage->get( [
2505 'object_type' => 'pod',
2506 'name' => '_pods_field',
2507 'bypass_cache' => true,
2508 ] );
2509
2510 $global_config = [
2511 'showFields' => ! pods_is_types_only( false, $current_pod->get_name() ),
2512 'pod' => $pod_object->export( [
2513 'include_groups' => true,
2514 'include_group_fields' => true,
2515 'include_fields' => false,
2516 'include_field_data' => true,
2517 'bypass_cache' => true,
2518 'ref_id' => 'global/' . $pod_object->get_type() . '/' . $pod_object->get_name(),
2519 ] ),
2520 'group' => $group_object->export( [
2521 'include_groups' => true,
2522 'include_group_fields' => true,
2523 'include_fields' => false,
2524 'include_field_data' => true,
2525 'bypass_cache' => true,
2526 'ref_id' => 'global/' . $pod_object->get_type() . '/' . $pod_object->get_name(),
2527 ] ),
2528 'field' => $field_object->export( [
2529 'include_groups' => true,
2530 'include_group_fields' => true,
2531 'include_fields' => false,
2532 'include_field_data' => true,
2533 'bypass_cache' => true,
2534 'ref_id' => 'global/' . $pod_object->get_type() . '/' . $pod_object->get_name(),
2535 ] ),
2536 ];
2537
2538 /**
2539 * Allow hooking into the global config setup for a Pod.
2540 *
2541 * @param array $global_config The global config object.
2542 * @param null|\Pods\Whatsit $current_pod The Pod object.
2543 */
2544 $global_config = apply_filters( 'pods_admin_setup_global_config', $global_config, $current_pod );
2545
2546 return $global_config;
2547 }
2548
2549 /**
2550 * Convert the tabs and their options to groups/fields in the collection storage.
2551 *
2552 * @since 2.8.0
2553 *
2554 * @param array $tabs List of registered tabs.
2555 * @param array $options List of tab options.
2556 * @param string $parent The parent object to register to.
2557 *
2558 * @return array Global config array.
2559 */
2560 protected function backcompat_convert_tabs_to_groups( array $tabs, array $options, $parent ) {
2561 $object_collection = Pods\Whatsit\Store::get_instance();
2562
2563 /** @var Pods\Whatsit\Storage\Collection $storage */
2564 $storage = $object_collection->get_storage_object( 'collection' );
2565
2566 $groups = [];
2567 $fields = [];
2568
2569 foreach ( $tabs as $group_name => $group_label ) {
2570 if ( empty( $options[ $group_name ] ) ) {
2571 continue;
2572 }
2573
2574 if ( is_array( $group_label ) ) {
2575 $group_args = $group_label;
2576 } else {
2577 $group_args = [
2578 'name' => $group_name,
2579 'label' => $group_label,
2580 ];
2581 }
2582
2583 $group_args['parent'] = $parent;
2584
2585 $group = new \Pods\Whatsit\Group( $group_args );
2586
2587 $groups[] = $storage->add( $group );
2588
2589 $group_fields = $options[ $group_name ];
2590
2591 $sections = false;
2592
2593 foreach ( $group_fields as $field_name => $field_options ) {
2594 // Support sections.
2595 if ( ! isset( $field_options['label'] ) ) {
2596 $sections = true;
2597 }
2598
2599 break;
2600 }
2601
2602 $group_sections = $group_fields;
2603
2604 // Store the same whether it's a section or not.
2605 if ( ! $sections ) {
2606 $group_sections = [
2607 $group_fields,
2608 ];
2609 }
2610
2611 foreach ( $group_sections as $section_label => $section_fields ) {
2612 // Add section field (maybe).
2613 if ( ! is_int( $section_label ) ) {
2614 $field_args = [
2615 'name' => sanitize_title( $section_label ),
2616 'label' => $section_label,
2617 'type' => 'heading',
2618 'parent' => $parent,
2619 'group' => 'group/' . $parent . '/' . $group_name,
2620 ];
2621
2622 $field = new \Pods\Whatsit\Field( $field_args );
2623
2624 $fields[] = $storage->add( $field );
2625 }
2626
2627 if ( ! is_array( $section_fields ) ) {
2628 continue;
2629 }
2630
2631 // Add fields for section.
2632 foreach ( $section_fields as $field_name => $field_options ) {
2633 $boolean_group = [];
2634
2635 // Handle auto-formatting from shorthand.
2636 if ( ! empty( $field_options['boolean_group'] ) ) {
2637 $boolean_group = $field_options['boolean_group'];
2638
2639 foreach ( $boolean_group as $bgf_key => $boolean_group_field ) {
2640 // Make sure each field has a field name.
2641 if ( is_string( $bgf_key ) ) {
2642 $boolean_group[ $bgf_key ]['name'] = $bgf_key;
2643 }
2644 }
2645
2646 $boolean_group = array_values( $boolean_group );
2647
2648 $field_options['boolean_group'] = $boolean_group;
2649 }
2650
2651 if ( empty( $field_options['type'] ) ) {
2652 continue;
2653 }
2654
2655 // Set a unique field name for boolean group headings.
2656 if ( ! empty( $boolean_group ) ) {
2657 $field_options['name'] = $field_name . '_' . md5( json_encode( $boolean_group ) );
2658 }
2659
2660 $field = $this->backcompat_convert_tabs_to_groups_setup_field( [
2661 'field_name' => $field_name,
2662 'field_options' => $field_options,
2663 'parent' => $parent,
2664 'group_name' => $group_name,
2665 ] );
2666
2667 $fields[] = $storage->add( $field );
2668 }
2669 }
2670 }
2671
2672 return compact( 'groups', 'fields' );
2673 }
2674
2675 /**
2676 * Setup field for backwards compatibility tabs to groups layer.
2677 *
2678 * @since 2.8.0
2679 *
2680 * @param array $args {
2681 * The field arguments.
2682 *
2683 * @type string $field_name The field name.
2684 * @type array $field_options The field options.
2685 * @type string|int $parent The parent group.
2686 * @type string $group_name The group name.
2687 * }
2688 *
2689 * @return \Pods\Whatsit\Field The field object.
2690 */
2691 public function backcompat_convert_tabs_to_groups_setup_field( $args ) {
2692 $field_name = $args['field_name'];
2693 $field_options = $args['field_options'];
2694 $parent = $args['parent'];
2695 $group_name = $args['group_name'];
2696
2697 $field_args = $field_options;
2698
2699 if ( ! isset( $field_args['name'] ) ) {
2700 $field_args['name'] = $field_name;
2701 }
2702
2703 $field_args['parent'] = $parent;
2704 $field_args['group'] = 'group/' . $parent . '/' . $group_name;
2705
2706 $dfv_args = (object) [
2707 'id' => 0,
2708 'name' => $field_args['name'],
2709 'value' => '',
2710 'pod' => null,
2711 'type' => pods_v( 'type', $field_args ),
2712 'options' => array_merge( [
2713 'id' => 0,
2714 ], $field_args ),
2715 'build_item_data' => true,
2716 ];
2717
2718 if ( ! empty( $dfv_args->type ) ) {
2719 $field_args = PodsForm::field_method( $dfv_args->type, 'build_dfv_field_options', $field_args, $dfv_args );
2720 }
2721
2722 return new \Pods\Whatsit\Field( $field_args );
2723 }
2724
2725 /**
2726 * Duplicate a pod
2727 *
2728 * @param PodsUI $obj PodsUI object.
2729 */
2730 public function admin_setup_duplicate( $obj ) {
2731 $new_id = pods_api()->duplicate_pod( array( 'name' => $obj->row['name'] ) );
2732
2733 if ( 0 < $new_id ) {
2734 pods_redirect(
2735 pods_query_arg(
2736 array(
2737 'action' => 'edit',
2738 'id' => $new_id,
2739 'do' => 'duplicate',
2740 'name' => null,
2741 )
2742 )
2743 );
2744
2745 return;
2746 }
2747
2748 $obj->error( __( 'An error occurred, the Pod was not duplicated.', 'pods' ) );
2749 }
2750
2751 /**
2752 * Restrict Duplicate action to custom types, not extended
2753 *
2754 * @param bool $restricted Whether action is restricted.
2755 * @param array $restrict Restriction array.
2756 * @param string $action Current action.
2757 * @param array $row Item data row.
2758 * @param PodsUI $obj PodsUI object.
2759 *
2760 * @since 2.3.10
2761 *
2762 * @return bool
2763 */
2764 public function admin_setup_duplicate_restrict( $restricted, $restrict, $action, $row, $obj ) {
2765 if ( in_array(
2766 $row['real_type'], array(
2767 'user',
2768 'media',
2769 'comment',
2770 ), true
2771 ) ) {
2772 $restricted = true;
2773 }
2774
2775 return $restricted;
2776 }
2777
2778 /**
2779 * Delete a pod
2780 *
2781 * @param PodsUI $obj PodsUI object.
2782 * @param int|string $id Item ID.
2783 *
2784 * @return mixed
2785 */
2786 public function admin_setup_delete( $obj, $id ) {
2787
2788 $pod = pods_api()->load_pod( array( 'id' => $id ), false );
2789
2790 if ( empty( $pod ) ) {
2791 return $obj->error( __( 'Pod not found.', 'pods' ) );
2792 }
2793
2794 if ( 'post_type' !== $pod->get_object_storage_type() ) {
2795 return $obj->error( __( 'Pod cannot be deleted.', 'pods' ) );
2796 }
2797
2798 pods_api()->delete_pod( array( 'id' => $id ) );
2799
2800 foreach ( $obj->data as $key => $data_pod ) {
2801 if ( (int) $id === (int) $data_pod['id'] ) {
2802 unset( $obj->data[ $key ] );
2803 }
2804 }
2805
2806 $obj->total = count( $obj->data );
2807 $obj->total_found = count( $obj->data );
2808
2809 $obj->message( __( 'Pod deleted successfully.', 'pods' ) );
2810
2811 $obj->manage();
2812 }
2813
2814 /**
2815 * Handle access rights review bulk action to make public for a pod.
2816 *
2817 * @since 3.1.0
2818 *
2819 * @param int[]|string[] $ids Item IDs.
2820 * @param PodsUI $obj PodsUI object.
2821 *
2822 * @return false This always returns false unless there was a real error.
2823 */
2824 public function admin_access_rights_review_make_public_bulk( $ids, $obj ) {
2825 foreach ( $ids as $id ) {
2826 if ( ! $id ) {
2827 continue;
2828 }
2829
2830 $this->admin_access_rights_review_make_public( $obj, $id, 'bulk' );
2831 }
2832
2833 $obj->message( __( 'Selected Pod(s) made public successfully.', 'pods' ) );
2834
2835 $this->update_callout( 'access_rights', false );
2836
2837 return false;
2838 }
2839
2840 /**
2841 * Handle access rights review action to make public for a pod.
2842 *
2843 * @since 3.1.0
2844 *
2845 * @param PodsUI $obj PodsUI object.
2846 * @param int|string $id Item ID.
2847 * @param string $mode Action mode.
2848 *
2849 * @return mixed
2850 */
2851 public function admin_access_rights_review_make_public( $obj, $id, $mode = 'single' ) {
2852 $pod = pods_api()->load_pod( [ 'id' => $id ], false );
2853
2854 if ( empty( $pod ) ) {
2855 return 'bulk' !== $mode ? $obj->error( __( 'Pod not found.', 'pods' ) ) : false;
2856 }
2857
2858 if ( 'post_type' !== $pod->get_object_storage_type() || $pod->is_extended() ) {
2859 return 'bulk' !== $mode ? $obj->error( __( 'Pod cannot be modified.', 'pods' ) ) : false;
2860 }
2861
2862 $params = [
2863 'id' => $id,
2864 'public' => 1,
2865 ];
2866
2867 if ( in_array( $pod->get_type(), [ 'post_type', 'taxonomy' ], true ) ) {
2868 $params['publicly_queryable'] = 1;
2869 }
2870
2871 pods_api()->save_pod( $params );
2872
2873 foreach ( $obj->data as $key => $data_pod ) {
2874 if ( (int) $id === (int) $data_pod['id'] ) {
2875 $obj->data[ $key ]['public'] = __( 'Public', 'pods' );
2876 $obj->data[ $key ]['real_public'] = 1;
2877 }
2878 }
2879
2880 if ( 'bulk' !== $mode ) {
2881 $obj->message( __( 'Pod made public successfully.', 'pods' ) );
2882
2883 $this->update_callout( 'access_rights', false );
2884
2885 $obj->manage();
2886 }
2887 }
2888
2889 /**
2890 * Handle access rights review bulk action to make private for a pod.
2891 *
2892 * @since 3.1.0
2893 *
2894 * @param int[]|string[] $ids Item IDs.
2895 * @param PodsUI $obj PodsUI object.
2896 *
2897 * @return false This always returns false unless there was a real error.
2898 */
2899 public function admin_access_rights_review_make_private_bulk( $ids, $obj ) {
2900 foreach ( $ids as $id ) {
2901 if ( ! $id ) {
2902 continue;
2903 }
2904
2905 $this->admin_access_rights_review_make_private( $obj, $id, 'bulk' );
2906 }
2907
2908 $obj->message( __( 'Selected Pod(s) made private successfully.', 'pods' ) );
2909
2910 $this->update_callout( 'access_rights', false );
2911
2912 return false;
2913 }
2914
2915 /**
2916 * Handle access rights review action to make private for a pod.
2917 *
2918 * @since 3.1.0
2919 *
2920 * @param PodsUI $obj PodsUI object.
2921 * @param int|string $id Item ID.
2922 * @param string $mode Action mode.
2923 *
2924 * @return mixed
2925 */
2926 public function admin_access_rights_review_make_private( $obj, $id, $mode = 'single' ) {
2927 $pod = pods_api()->load_pod( [ 'id' => $id ], false );
2928
2929 if ( empty( $pod ) ) {
2930 return 'bulk' !== $mode ? $obj->error( __( 'Pod not found.', 'pods' ) ) : false;
2931 }
2932
2933 if ( 'post_type' !== $pod->get_object_storage_type() || $pod->is_extended() ) {
2934 return 'bulk' !== $mode ? $obj->error( __( 'Pod cannot be modified.', 'pods' ) ) : false;
2935 }
2936
2937 $params = [
2938 'id' => $id,
2939 ];
2940
2941 if ( in_array( $pod->get_type(), [ 'post_type', 'taxonomy' ], true ) ) {
2942 $params['publicly_queryable'] = 0;
2943 } else {
2944 $params['public'] = 0;
2945 }
2946
2947 pods_api()->save_pod( $params );
2948
2949 foreach ( $obj->data as $key => $data_pod ) {
2950 if ( (int) $id === (int) $data_pod['id'] ) {
2951 $obj->data[ $key ]['public'] = '🔒 ' . __( 'Private', 'pods' );
2952 $obj->data[ $key ]['real_public'] = 0;
2953 }
2954 }
2955
2956 if ( 'bulk' !== $mode ) {
2957 $obj->message( __( 'Pod made private successfully.', 'pods' ) );
2958
2959 $this->update_callout( 'access_rights', false );
2960
2961 $obj->manage();
2962 }
2963 }
2964
2965 /**
2966 * Handle access rights review bulk action to restrict dynamic features for a pod.
2967 *
2968 * @since 3.1.0
2969 *
2970 * @param int[]|string[] $ids Item IDs.
2971 * @param PodsUI $obj PodsUI object.
2972 *
2973 * @return false This always returns false unless there was a real error.
2974 */
2975 public function admin_access_rights_review_restrict_dynamic_features_bulk( $ids, $obj ) {
2976 foreach ( $ids as $id ) {
2977 if ( ! $id ) {
2978 continue;
2979 }
2980
2981 $this->admin_access_rights_review_restrict_dynamic_features( $obj, $id, 'bulk' );
2982 }
2983
2984 $obj->message( __( 'Selected Pod(s) restricted dynamic features successfully.', 'pods' ) );
2985
2986 $this->update_callout( 'access_rights', false );
2987
2988 return false;
2989 }
2990
2991 /**
2992 * Handle access rights review action to restrict dynamic features for a pod.
2993 *
2994 * @since 3.1.0
2995 *
2996 * @param PodsUI $obj PodsUI object.
2997 * @param int|string $id Item ID.
2998 * @param string $mode Action mode.
2999 *
3000 * @return mixed
3001 */
3002 public function admin_access_rights_review_restrict_dynamic_features( $obj, $id, $mode = 'single' ) {
3003 $pod = pods_api()->load_pod( [ 'id' => $id ], false );
3004
3005 if ( empty( $pod ) ) {
3006 return 'bulk' !== $mode ? $obj->error( __( 'Pod not found.', 'pods' ) ) : false;
3007 }
3008
3009 if ( 'post_type' !== $pod->get_object_storage_type() ) {
3010 return 'bulk' !== $mode ? $obj->error( __( 'Pod cannot be modified.', 'pods' ) ) : false;
3011 }
3012
3013 pods_api()->save_pod( [
3014 'id' => $id,
3015 'restrict_dynamic_features' => '1',
3016 'restricted_dynamic_features' => [
3017 'display',
3018 'form',
3019 ],
3020 ] );
3021
3022 foreach ( $obj->data as $key => $data_pod ) {
3023 if ( (int) $id === (int) $data_pod['id'] ) {
3024 $obj->data[ $key ]['restricted_dynamic_features'] = pods_access_get_restricted_dynamic_features_options();
3025
3026 $obj->data[ $key ]['real_restricted_dynamic_features'] = 'restricted';
3027 }
3028 }
3029
3030 if ( 'bulk' !== $mode ) {
3031 $obj->message( __( 'Pod restricted dynamic features successfully.', 'pods' ) );
3032
3033 $this->update_callout( 'access_rights', false );
3034
3035 $obj->manage();
3036 }
3037 }
3038
3039 /**
3040 * Handle access rights review bulk action to restrict dynamic features for a pod.
3041 *
3042 * @since 3.1.0
3043 *
3044 * @param int[]|string[] $ids Item IDs.
3045 * @param PodsUI $obj PodsUI object.
3046 *
3047 * @return false This always returns false unless there was a real error.
3048 */
3049 public function admin_access_rights_review_unrestrict_dynamic_features_bulk( $ids, $obj ) {
3050 foreach ( $ids as $id ) {
3051 if ( ! $id ) {
3052 continue;
3053 }
3054
3055 $this->admin_access_rights_review_unrestrict_dynamic_features( $obj, $id, 'bulk' );
3056 }
3057
3058 $obj->message( __( 'Selected Pod(s) unrestricted dynamic features successfully.', 'pods' ) );
3059
3060 $this->update_callout( 'access_rights', false );
3061
3062 return false;
3063 }
3064
3065 /**
3066 * Handle access rights review action to unrestrict dynamic features for a pod.
3067 *
3068 * @since 3.1.0
3069 *
3070 * @param PodsUI $obj PodsUI object.
3071 * @param int|string $id Item ID.
3072 * @param string $mode Action mode.
3073 *
3074 * @return mixed
3075 */
3076 public function admin_access_rights_review_unrestrict_dynamic_features( $obj, $id, $mode = 'single' ) {
3077 $pod = pods_api()->load_pod( [ 'id' => $id ], false );
3078
3079 if ( empty( $pod ) ) {
3080 return 'bulk' !== $mode ? $obj->error( __( 'Pod not found.', 'pods' ) ) : false;
3081 }
3082
3083 if ( 'post_type' !== $pod->get_object_storage_type() ) {
3084 return 'bulk' !== $mode ? $obj->error( __( 'Pod cannot be modified.', 'pods' ) ) : false;
3085 }
3086
3087 pods_api()->save_pod( [
3088 'id' => $id,
3089 'restrict_dynamic_features' => '0',
3090 'restricted_dynamic_features' => [],
3091 ] );
3092
3093 foreach ( $obj->data as $key => $data_pod ) {
3094 if ( (int) $id === (int) $data_pod['id'] ) {
3095 $obj->data[ $key ]['restricted_dynamic_features'] = __( 'Unrestricted', 'pods' );
3096 $obj->data[ $key ]['real_restricted_dynamic_features'] = 'unrestricted';
3097 }
3098 }
3099
3100 if ( 'bulk' !== $mode ) {
3101 $obj->message( __( 'Pod unrestricted dynamic features successfully.', 'pods' ) );
3102
3103 $this->update_callout( 'access_rights', false );
3104
3105 $obj->manage();
3106 }
3107 }
3108
3109 /**
3110 * Restrict actions that can't be done for Pods with a non DB source.
3111 *
3112 * @since 3.1.0
3113 *
3114 * @param bool $restricted Whether action is restricted.
3115 * @param array $restrict Restriction array.
3116 * @param string $action Current action.
3117 * @param array $row Item data row.
3118 * @param PodsUI $obj PodsUI object.
3119 *
3120 * @return bool Whether the action is restricted.
3121 */
3122 public function admin_restrict_non_db_type( $restricted, $restrict, $action, $row, $obj ) {
3123 if ( __( 'DB', 'pods' ) !== $row['source'] ) {
3124 $restricted = true;
3125 }
3126
3127 return $restricted;
3128 }
3129
3130 /**
3131 * Restrict actions that can't be done for Pods with a non DB source.
3132 *
3133 * @since 3.1.0
3134 *
3135 * @param bool $restricted Whether action is restricted.
3136 * @param array $restrict Restriction array.
3137 * @param string $action Current action.
3138 * @param array $row Item data row.
3139 * @param PodsUI $obj PodsUI object.
3140 *
3141 * @return bool Whether the action is restricted.
3142 */
3143 public function admin_restrict_access_rights_review_make_public( $restricted, $restrict, $action, $row, $obj ) {
3144 $restricted = $this->admin_restrict_non_db_type( $restricted, $restrict, $action, $row, $obj );
3145
3146 if (
3147 ! $restricted
3148 && (
3149 1 === $row['real_public']
3150 || $row['pod_object']->is_extended()
3151 )
3152 ) {
3153 $restricted = true;
3154 }
3155
3156 return $restricted;
3157 }
3158
3159 /**
3160 * Restrict actions that can't be done for Pods with a non DB source.
3161 *
3162 * @since 3.1.0
3163 *
3164 * @param bool $restricted Whether action is restricted.
3165 * @param array $restrict Restriction array.
3166 * @param string $action Current action.
3167 * @param array $row Item data row.
3168 * @param PodsUI $obj PodsUI object.
3169 *
3170 * @return bool Whether the action is restricted.
3171 */
3172 public function admin_restrict_access_rights_review_make_private( $restricted, $restrict, $action, $row, $obj ) {
3173 $restricted = $this->admin_restrict_non_db_type( $restricted, $restrict, $action, $row, $obj );
3174
3175 if (
3176 ! $restricted
3177 && (
3178 0 === $row['real_public']
3179 || $row['pod_object']->is_extended()
3180 )
3181 ) {
3182 $restricted = true;
3183 }
3184
3185 return $restricted;
3186 }
3187
3188 /**
3189 * Restrict actions that can't be done for Pods with a non DB source.
3190 *
3191 * @since 3.1.0
3192 *
3193 * @param bool $restricted Whether action is restricted.
3194 * @param array $restrict Restriction array.
3195 * @param string $action Current action.
3196 * @param array $row Item data row.
3197 * @param PodsUI $obj PodsUI object.
3198 *
3199 * @return bool Whether the action is restricted.
3200 */
3201 public function admin_restrict_access_rights_review_restrict_dynamic_features( $restricted, $restrict, $action, $row, $obj ) {
3202 $restricted = $this->admin_restrict_non_db_type( $restricted, $restrict, $action, $row, $obj );
3203
3204 if ( ! $restricted && 'restricted' === $row['real_restricted_dynamic_features'] ) {
3205 $restricted = true;
3206 }
3207
3208 return $restricted;
3209 }
3210
3211 /**
3212 * Handle access rights review bulk action to set dynamic features as WP Default for a pod.
3213 *
3214 * @since 3.1.0
3215 *
3216 * @param int[]|string[] $ids Item IDs.
3217 * @param PodsUI $obj PodsUI object.
3218 *
3219 * @return false This always returns false unless there was a real error.
3220 */
3221 public function admin_access_rights_review_wp_default_dynamic_features_bulk( $ids, $obj ) {
3222 foreach ( $ids as $id ) {
3223 if ( ! $id ) {
3224 continue;
3225 }
3226
3227 $this->admin_access_rights_review_wp_default_dynamic_features( $obj, $id, 'bulk' );
3228 }
3229
3230 $obj->message( __( 'Selected Pod(s) Dynamic Features set to WP Default successfully.', 'pods' ) );
3231
3232 $this->update_callout( 'access_rights', false );
3233
3234 return false;
3235 }
3236
3237 /**
3238 * Handle access rights review bulk action to set dynamic features as WP Default for a pod.
3239 *
3240 * @since 3.1.0
3241 *
3242 * @param PodsUI $obj PodsUI object.
3243 * @param int|string $id Item ID.
3244 * @param string $mode Action mode.
3245 *
3246 * @return mixed
3247 */
3248 public function admin_access_rights_review_wp_default_dynamic_features( $obj, $id, $mode = 'single' ) {
3249 $pod = pods_api()->load_pod( [ 'id' => $id ], false );
3250
3251 if ( empty( $pod ) ) {
3252 return 'bulk' !== $mode ? $obj->error( __( 'Pod not found.', 'pods' ) ) : false;
3253 }
3254
3255 if ( 'post_type' !== $pod->get_object_storage_type() || $pod->is_extended() ) {
3256 return 'bulk' !== $mode ? $obj->error( __( 'Pod cannot be modified.', 'pods' ) ) : false;
3257 }
3258
3259 $is_public = pods_is_type_public(
3260 [
3261 'pod' => $pod,
3262 ]
3263 );
3264
3265 $options = pods_access_get_dynamic_features_allow_options();
3266 $value = 'inherit';
3267 $label = $options[ $value ] . ' - ' . ( $is_public ? $options['1'] : $options['0'] );
3268
3269 pods_api()->save_pod( [ 'id' => $id, 'dynamic_features_allow' => $value ] );
3270
3271 foreach ( $obj->data as $key => $data_pod ) {
3272 if ( (int) $id === (int) $data_pod['id'] ) {
3273 $obj->data[ $key ]['dynamic_features_allow'] = $label;
3274 $obj->data[ $key ]['real_dynamic_features_allow'] = $value;
3275 }
3276 }
3277
3278 if ( 'bulk' !== $mode ) {
3279 $obj->message( __( 'Pod Dynamic Features set to WP Default successfully.', 'pods' ) );
3280
3281 $this->update_callout( 'access_rights', false );
3282
3283 $obj->manage();
3284 }
3285 }
3286
3287 /**
3288 * Restrict actions that can't be done for Pods with a non DB source.
3289 *
3290 * @since 3.1.0
3291 *
3292 * @param bool $restricted Whether action is restricted.
3293 * @param array $restrict Restriction array.
3294 * @param string $action Current action.
3295 * @param array $row Item data row.
3296 * @param PodsUI $obj PodsUI object.
3297 *
3298 * @return bool Whether the action is restricted.
3299 */
3300 public function admin_restrict_access_rights_review_wp_default_dynamic_features( $restricted, $restrict, $action, $row, $obj ) {
3301 $restricted = $this->admin_restrict_non_db_type( $restricted, $restrict, $action, $row, $obj );
3302
3303 if ( ! $restricted && 'inherit' === $row['real_dynamic_features_allow'] ) {
3304 $restricted = true;
3305 }
3306
3307 return $restricted;
3308 }
3309
3310 /**
3311 * Handle access rights review bulk action to set dynamic features as enabled for a pod.
3312 *
3313 * @since 3.1.0
3314 *
3315 * @param int[]|string[] $ids Item IDs.
3316 * @param PodsUI $obj PodsUI object.
3317 *
3318 * @return false This always returns false unless there was a real error.
3319 */
3320 public function admin_access_rights_review_enable_dynamic_features_bulk( $ids, $obj ) {
3321 foreach ( $ids as $id ) {
3322 if ( ! $id ) {
3323 continue;
3324 }
3325
3326 $this->admin_access_rights_review_enable_dynamic_features( $obj, $id, 'bulk' );
3327 }
3328
3329 $obj->message( __( 'Selected Pod(s) Dynamic Features set to Enabled successfully.', 'pods' ) );
3330
3331 $this->update_callout( 'access_rights', false );
3332
3333 return false;
3334 }
3335
3336 /**
3337 * Handle access rights review bulk action to set dynamic features as enabled for a pod.
3338 *
3339 * @since 3.1.0
3340 *
3341 * @param PodsUI $obj PodsUI object.
3342 * @param int|string $id Item ID.
3343 * @param string $mode Action mode.
3344 *
3345 * @return mixed
3346 */
3347 public function admin_access_rights_review_enable_dynamic_features( $obj, $id, $mode = 'single' ) {
3348 $pod = pods_api()->load_pod( [ 'id' => $id ], false );
3349
3350 if ( empty( $pod ) ) {
3351 return 'bulk' !== $mode ? $obj->error( __( 'Pod not found.', 'pods' ) ) : false;
3352 }
3353
3354 if ( 'post_type' !== $pod->get_object_storage_type() || $pod->is_extended() ) {
3355 return 'bulk' !== $mode ? $obj->error( __( 'Pod cannot be modified.', 'pods' ) ) : false;
3356 }
3357
3358 $options = pods_access_get_dynamic_features_allow_options();
3359 $value = '1';
3360 $label = $options[ $value ];
3361
3362 pods_api()->save_pod( [ 'id' => $id, 'dynamic_features_allow' => $value ] );
3363
3364 foreach ( $obj->data as $key => $data_pod ) {
3365 if ( (int) $id === (int) $data_pod['id'] ) {
3366 $obj->data[ $key ]['dynamic_features_allow'] = $label;
3367 $obj->data[ $key ]['real_dynamic_features_allow'] = $value;
3368 }
3369 }
3370
3371 if ( 'bulk' !== $mode ) {
3372 $obj->message( __( 'Pod Dynamic Features set to Enabled successfully.', 'pods' ) );
3373
3374 $this->update_callout( 'access_rights', false );
3375
3376 $obj->manage();
3377 }
3378 }
3379
3380 /**
3381 * Restrict actions that can't be done for Pods with a non DB source.
3382 *
3383 * @since 3.1.0
3384 *
3385 * @param bool $restricted Whether action is restricted.
3386 * @param array $restrict Restriction array.
3387 * @param string $action Current action.
3388 * @param array $row Item data row.
3389 * @param PodsUI $obj PodsUI object.
3390 *
3391 * @return bool Whether the action is restricted.
3392 */
3393 public function admin_restrict_access_rights_review_enable_dynamic_features( $restricted, $restrict, $action, $row, $obj ) {
3394 $restricted = $this->admin_restrict_non_db_type( $restricted, $restrict, $action, $row, $obj );
3395
3396 if ( ! $restricted && '1' === $row['real_dynamic_features_allow'] ) {
3397 $restricted = true;
3398 }
3399
3400 return $restricted;
3401 }
3402
3403 /**
3404 * Handle access rights review bulk action to set dynamic features as disabled for a pod.
3405 *
3406 * @since 3.1.0
3407 *
3408 * @param int[]|string[] $ids Item IDs.
3409 * @param PodsUI $obj PodsUI object.
3410 *
3411 * @return false This always returns false unless there was a real error.
3412 */
3413 public function admin_access_rights_review_disable_dynamic_features_bulk( $ids, $obj ) {
3414 foreach ( $ids as $id ) {
3415 if ( ! $id ) {
3416 continue;
3417 }
3418
3419 $this->admin_access_rights_review_disable_dynamic_features( $obj, $id, 'bulk' );
3420 }
3421
3422 $obj->message( __( 'Selected Pod(s) Dynamic Features set to Disabled successfully.', 'pods' ) );
3423
3424 $this->update_callout( 'access_rights', false );
3425
3426 return false;
3427 }
3428
3429 /**
3430 * Handle access rights review bulk action to set dynamic features as disabled for a pod.
3431 *
3432 * @since 3.1.0
3433 *
3434 * @param PodsUI $obj PodsUI object.
3435 * @param int|string $id Item ID.
3436 * @param string $mode Action mode.
3437 *
3438 * @return mixed
3439 */
3440 public function admin_access_rights_review_disable_dynamic_features( $obj, $id, $mode = 'single' ) {
3441 $pod = pods_api()->load_pod( [ 'id' => $id ], false );
3442
3443 if ( empty( $pod ) ) {
3444 return 'bulk' !== $mode ? $obj->error( __( 'Pod not found.', 'pods' ) ) : false;
3445 }
3446
3447 if ( 'post_type' !== $pod->get_object_storage_type() || $pod->is_extended() ) {
3448 return 'bulk' !== $mode ? $obj->error( __( 'Pod cannot be modified.', 'pods' ) ) : false;
3449 }
3450
3451 $options = pods_access_get_dynamic_features_allow_options();
3452 $value = '0';
3453 $label = $options[ $value ];
3454
3455 pods_api()->save_pod( [ 'id' => $id, 'dynamic_features_allow' => $value ] );
3456
3457 foreach ( $obj->data as $key => $data_pod ) {
3458 if ( (int) $id === (int) $data_pod['id'] ) {
3459 $obj->data[ $key ]['dynamic_features_allow'] = $label;
3460 $obj->data[ $key ]['real_dynamic_features_allow'] = $value;
3461 }
3462 }
3463
3464 if ( 'bulk' !== $mode ) {
3465 $obj->message( __( 'Pod Dynamic Features set to Disabled successfully.', 'pods' ) );
3466
3467 $this->update_callout( 'access_rights', false );
3468
3469 $obj->manage();
3470 }
3471 }
3472
3473 /**
3474 * Restrict actions that can't be done for Pods with a non DB source.
3475 *
3476 * @since 3.1.0
3477 *
3478 * @param bool $restricted Whether action is restricted.
3479 * @param array $restrict Restriction array.
3480 * @param string $action Current action.
3481 * @param array $row Item data row.
3482 * @param PodsUI $obj PodsUI object.
3483 *
3484 * @return bool Whether the action is restricted.
3485 */
3486 public function admin_restrict_access_rights_review_disable_dynamic_features( $restricted, $restrict, $action, $row, $obj ) {
3487 $restricted = $this->admin_restrict_non_db_type( $restricted, $restrict, $action, $row, $obj );
3488
3489 if ( ! $restricted && '0' === $row['real_dynamic_features_allow'] ) {
3490 $restricted = true;
3491 }
3492
3493 return $restricted;
3494 }
3495
3496 /**
3497 * Restrict actions that can't be done for Pods with a non DB source.
3498 *
3499 * @since 3.1.0
3500 *
3501 * @param bool $restricted Whether action is restricted.
3502 * @param array $restrict Restriction array.
3503 * @param string $action Current action.
3504 * @param array $row Item data row.
3505 * @param PodsUI $obj PodsUI object.
3506 *
3507 * @return bool Whether the action is restricted.
3508 */
3509 public function admin_restrict_access_rights_review_unrestrict_dynamic_features( $restricted, $restrict, $action, $row, $obj ) {
3510 $restricted = $this->admin_restrict_non_db_type( $restricted, $restrict, $action, $row, $obj );
3511
3512 if ( ! $restricted && 'unrestricted' === $row['real_restricted_dynamic_features'] ) {
3513 $restricted = true;
3514 }
3515
3516 return $restricted;
3517 }
3518
3519 /**
3520 * Get advanced administration view.
3521 */
3522 public function admin_advanced() {
3523
3524 pods_view( PODS_DIR . 'ui/admin/advanced.php', compact( array_keys( get_defined_vars() ) ) );
3525 }
3526
3527 /**
3528 * Get settings administration view
3529 */
3530 public function admin_settings() {
3531 $hide_notice = filter_var( get_option( 'pods_tmp_hide_notice_31', false ), FILTER_VALIDATE_BOOLEAN );
3532
3533 if ( ! $hide_notice ) {
3534 if (
3535 ! empty( $_GET['hide_notice_31'] )
3536 && ! empty( $_GET['hide_notice_31_nonce'] )
3537 && wp_verify_nonce( $_GET['hide_notice_31_nonce'], 'hide_notice_31' )
3538 ) {
3539 update_option( 'pods_tmp_hide_notice_31', 1, 'no' );
3540 } else {
3541 pods_message(
3542 sprintf(
3543 '⚠️ %s <a href="%s">%s</a>',
3544 __( 'You are running an outdated version of Pods. Upgrade to the latest version of Pods to get the most out of Access Rights, security fixes, and future features.', 'pods' ),
3545 esc_url( add_query_arg( [ 'hide_notice_31' => 1, 'hide_notice_31_nonce' => wp_create_nonce( 'hide_notice_31' ) ] ) ),
3546 __( 'Hide this notice', 'pods' )
3547 ),
3548 'error'
3549 );
3550 }
3551 }
3552
3553 // Add our custom callouts.
3554 $this->handle_callouts_updates();
3555 $this->maybe_handle_display_callback_notice_dismiss();
3556
3557 /**
3558 * Allow hooking into our settings page to set up hooks.
3559 *
3560 * @since 2.8.0
3561 */
3562 do_action( 'pods_admin_settings_init' );
3563
3564 add_action( 'pods_admin_before_settings', array( $this, 'show_display_callback_notice' ) );
3565
3566 // Add our custom callouts.
3567 if ( $this->has_horizontal_callout() ) {
3568 add_action( 'pods_admin_before_settings', [ $this, 'admin_manage_callouts' ] );
3569 } else {
3570 add_action( 'pods_admin_after_settings', [ $this, 'admin_manage_callouts' ] );
3571 }
3572
3573 pods_view( PODS_DIR . 'ui/admin/settings.php', compact( array_keys( get_defined_vars() ) ) );
3574 }
3575
3576 /**
3577 * Clear the cached disallowed display callbacks when the notice is dismissed.
3578 *
3579 * @since 3.3.9.2
3580 */
3581 public function maybe_handle_display_callback_notice_dismiss() {
3582 $dismiss = pods_v( 'pods_dismiss_display_callback_notice' );
3583 $nonce = pods_v( 'pods_dismiss_display_callback_notice_nonce' );
3584
3585 if ( ! $dismiss || ! $nonce ) {
3586 return;
3587 }
3588
3589 if ( false === wp_verify_nonce( $nonce, 'pods_dismiss_display_callback_notice' ) ) {
3590 return;
3591 }
3592
3593 if ( ! pods_is_admin( 'pods_settings' ) ) {
3594 return;
3595 }
3596
3597 pods_access_clear_disallowed_display_callbacks();
3598 }
3599
3600 /**
3601 * Show an admin notice on the Pods Settings page listing detected disallowed display callbacks.
3602 *
3603 * @since 3.3.9.2
3604 */
3605 public function show_display_callback_notice() {
3606 if ( ! pods_is_truthy( pods_get_setting( 'show_display_callback_notices', '1' ) ) ) {
3607 return;
3608 }
3609
3610 $callbacks = pods_get_disallowed_display_callbacks();
3611
3612 if ( empty( $callbacks ) ) {
3613 return;
3614 }
3615
3616 $escaped_callbacks = array_map( 'esc_html', $callbacks );
3617
3618 $dismiss_link = add_query_arg( array(
3619 'pods_dismiss_display_callback_notice' => '1',
3620 'pods_dismiss_display_callback_notice_nonce' => wp_create_nonce( 'pods_dismiss_display_callback_notice' ),
3621 ) );
3622
3623 pods_message(
3624 wpautop(
3625 esc_html__( 'Disallowed display callbacks were detected on this site. These callbacks were blocked and were not run.', 'pods' )
3626 . "\n\n" . '<strong>' . esc_html__( 'Disallowed callbacks:', 'pods' ) . '</strong> ' . implode( ', ', $escaped_callbacks )
3627 . "\n\n" . esc_html__( 'Review your Display callbacks setting if you expected these functions to be allowed, or dismiss this notice after you have reviewed the list.', 'pods' )
3628 . "\n\n" . '<a href="' . esc_url( $dismiss_link ) . '" class="button">' . esc_html__( 'Dismiss and clear list', 'pods' ) . '</a>'
3629 ),
3630 'warning',
3631 false,
3632 false
3633 );
3634 }
3635
3636 /**
3637 * Get components administration UI
3638 */
3639 public function admin_components() {
3640
3641 if ( ! is_object( PodsInit::$components ) ) {
3642 return;
3643 }
3644
3645 $components = PodsInit::$components->components;
3646
3647 $view = pods_v( 'view', 'get', 'all', true );
3648
3649 $recommended = array(
3650 'advanced-relationships',
3651 'advanced-content-types',
3652 'migrate-packages',
3653 'roles-and-capabilities',
3654 'pages',
3655 'table-storage',
3656 'templates',
3657 );
3658
3659 foreach ( $components as $component => &$component_data ) {
3660 if ( ! in_array(
3661 $view, array(
3662 'all',
3663 'recommended',
3664 'dev',
3665 ), true
3666 ) && ( ! isset( $component_data['Category'] ) || sanitize_title( $component_data['Category'] ) !== $view ) ) {
3667 unset( $components[ $component ] );
3668
3669 continue;
3670 } elseif ( 'recommended' === $view && ! in_array( $component_data['ID'], $recommended, true ) ) {
3671 unset( $components[ $component ] );
3672
3673 continue;
3674 } elseif ( 'dev' === $view && pods_developer() && ! pods_v( 'DeveloperMode', $component_data, false ) ) {
3675 unset( $components[ $component ] );
3676
3677 continue;
3678 } elseif ( pods_v( 'DeveloperMode', $component_data, false ) && ! pods_developer() ) {
3679 unset( $components[ $component ] );
3680
3681 continue;
3682 } elseif ( ! pods_v( 'TablelessMode', $component_data, false ) && pods_tableless() ) {
3683 unset( $components[ $component ] );
3684
3685 continue;
3686 }//end if
3687
3688 $component_data['Name'] = strip_tags( $component_data['Name'] );
3689
3690 if ( pods_v( 'DeveloperMode', $component_data, false ) ) {
3691 $component_data['Name'] .= ' <em style="font-weight: normal; color:#333;">(Developer Preview)</em>';
3692 }
3693
3694 $meta = array();
3695
3696 if ( ! empty( $component_data['Version'] ) ) {
3697 $meta[] = sprintf( __( 'Version %s', 'pods' ), $component_data['Version'] );
3698 }
3699
3700 if ( empty( $component_data['Author'] ) ) {
3701 $component_data['Author'] = 'Pods Framework Team';
3702 $component_data['AuthorURI'] = 'https://pods.io/';
3703 }
3704
3705 if ( ! empty( $component_data['AuthorURI'] ) ) {
3706 $component_data['Author'] = '<a href="' . $component_data['AuthorURI'] . '">' . $component_data['Author'] . '</a>';
3707 }
3708
3709 $meta[] = sprintf( __( 'by %s', 'pods' ), $component_data['Author'] );
3710
3711 if ( ! empty( $component_data['URI'] ) ) {
3712 $meta[] = '<a href="' . $component_data['URI'] . '">' . __( 'Visit component site', 'pods' ) . '</a>';
3713 }
3714
3715 if ( pods_is_truthy( pods_v( 'Deprecated', $component_data, false ) ) ) {
3716 $deprecated = __( 'Deprecated', 'pods' );
3717
3718 $component_data['Name'] .= sprintf(
3719 ' <em style="font-weight: normal; color:#333;">(%s)</em>',
3720 $deprecated
3721 );
3722
3723 $deprecated_in_version = pods_v( 'DeprecatedInVersion', $component_data );
3724 $deprecated_removal_version = pods_v( 'DeprecatedRemovalVersion', $component_data );
3725
3726 if ( empty( $deprecated_removal_version ) ) {
3727 // translators: TBD means To Be Determined.
3728 $deprecated_removal_version = __( 'TBD', 'pods' );
3729 }
3730
3731 if ( $deprecated_in_version ) {
3732 $deprecated = sprintf(
3733 // translators: %1$s is the version the deprecation starts and %2$s is the version the code will be removed.
3734 __( 'Deprecated in %1$s, will be removed in %2$s', 'pods' ),
3735 $deprecated_in_version,
3736 $deprecated_removal_version
3737 );
3738 }
3739
3740 $meta[] = $deprecated;
3741 }
3742
3743 $component_data['Description'] = wpautop( trim( make_clickable( strip_tags( $component_data['Description'], 'em,strong' ) ) ) );
3744
3745 if ( ! empty( $meta ) ) {
3746 $description_style = '';
3747
3748 if ( ! empty( $component_data['Description'] ) ) {
3749 $description_style = ' style="padding:8px 0 4px;"';
3750 }
3751
3752 $component_data['Description'] .= '<div class="pods-component-meta" ' . $description_style . '>' . implode( '&nbsp;&nbsp;|&nbsp;&nbsp;', $meta ) . '</div>';
3753 }
3754
3755 $component_data = array(
3756 'id' => $component_data['ID'],
3757 'name' => $component_data['Name'],
3758 'category' => $component_data['Category'],
3759 'version' => '',
3760 'description' => $component_data['Description'],
3761 'mustuse' => pods_v( 'MustUse', $component_data, false ),
3762 'toggle' => 0,
3763 );
3764
3765 if ( ! empty( $component_data['category'] ) ) {
3766 $category_url = pods_query_arg(
3767 array(
3768 'view' => sanitize_title( $component_data['category'] ),
3769 'pg' => '',
3770 // @codingStandardsIgnoreLine
3771 'page' => $_GET['page'],
3772 )
3773 );
3774
3775 $component_data['category'] = '<a href="' . esc_url( $category_url ) . '">' . $component_data['category'] . '</a>';
3776 }
3777
3778 if ( isset( PodsInit::$components->settings['components'][ $component_data['id'] ] ) && 0 !== PodsInit::$components->settings['components'][ $component_data['id'] ] ) {
3779 $component_data['toggle'] = 1;
3780 } elseif ( $component_data['mustuse'] ) {
3781 $component_data['toggle'] = 1;
3782 }
3783 }//end foreach
3784
3785 $ui = array(
3786 'sql' => array(
3787 'field_id' => 'id',
3788 ),
3789 'data' => $components,
3790 'total' => count( $components ),
3791 'total_found' => count( $components ),
3792 'items' => __( 'Components', 'pods' ),
3793 'item' => __( 'Component', 'pods' ),
3794 'fields' => array(
3795 'manage' => array(
3796 'name' => array(
3797 'label' => __( 'Name', 'pods' ),
3798 'width' => '30%',
3799 'type' => 'text',
3800 'options' => array(
3801 'text_allow_html' => true,
3802 ),
3803 ),
3804 'category' => array(
3805 'label' => __( 'Category', 'pods' ),
3806 'width' => '10%',
3807 'type' => 'text',
3808 'options' => array(
3809 'text_allow_html' => true,
3810 ),
3811 ),
3812 'description' => array(
3813 'label' => __( 'Description', 'pods' ),
3814 'width' => '60%',
3815 'type' => 'text',
3816 'options' => array(
3817 'text_allow_html' => true,
3818 'text_allowed_html_tags' => 'strong em a ul ol li b i br div',
3819 ),
3820 ),
3821 ),
3822 ),
3823 'actions_disabled' => array( 'duplicate', 'view', 'export', 'add', 'edit', 'delete' ),
3824 'actions_custom' => array(
3825 'toggle' => array(
3826 'callback' => array( $this, 'admin_components_toggle' ),
3827 'nonce' => true,
3828 ),
3829 ),
3830 'filters_enhanced' => true,
3831 'views' => array(
3832 'all' => __( 'All', 'pods' ),
3833 // 'recommended' => __( 'Recommended', 'pods' ),
3834 'field-types' => __( 'Field Types', 'pods' ),
3835 'tools' => __( 'Tools', 'pods' ),
3836 'integration' => __( 'Integration', 'pods' ),
3837 'migration' => __( 'Migration', 'pods' ),
3838 'advanced' => __( 'Advanced', 'pods' ),
3839 ),
3840 'view' => $view,
3841 'heading' => array(
3842 'views' => __( 'Category', 'pods' ),
3843 ),
3844 'search' => false,
3845 'searchable' => false,
3846 'sortable' => false,
3847 'pagination' => false,
3848 );
3849
3850 if ( pods_developer() ) {
3851 $ui['views']['dev'] = __( 'Developer Preview', 'pods' );
3852 }
3853
3854 // Add our custom callouts.
3855 $this->handle_callouts_updates();
3856
3857 add_filter( 'pods_ui_manage_custom_container_classes', array( $this, 'admin_manage_container_class' ) );
3858
3859 if ( $this->has_horizontal_callout() ) {
3860 add_action( 'pods_ui_manage_before_container', [ $this, 'admin_manage_callouts' ] );
3861 } else {
3862 add_action( 'pods_ui_manage_after_container', [ $this, 'admin_manage_callouts' ] );
3863 }
3864
3865 pods_ui( $ui );
3866 }
3867
3868 /**
3869 * Toggle a component on or off
3870 *
3871 * @param PodsUI $ui PodsUI object.
3872 */
3873 public function admin_components_toggle( $ui ) {
3874 $component = pods_v( 'id' );
3875
3876 if ( ! empty( PodsInit::$components->components[ $component ]['PluginDependency'] ) ) {
3877 $dependency = explode( '|', PodsInit::$components->components[ $component ]['PluginDependency'] );
3878
3879 if ( ! pods_is_plugin_active( $dependency[1] ) ) {
3880 $website = 'http://wordpress.org/extend/plugins/' . dirname( $dependency[1] ) . '/';
3881
3882 if ( isset( $dependency[2] ) ) {
3883 $website = $dependency[2];
3884 }
3885
3886 if ( ! empty( $website ) ) {
3887 $website = ' ' . sprintf( __( 'You can find it at %s', 'pods' ), '<a href="' . $website . '" target="_blank" rel="noopener noreferrer">' . $website . '</a>' );
3888 }
3889
3890 $message = sprintf( __( 'The %1$s component requires that you have the <strong>%2$s</strong> plugin installed and activated.', 'pods' ), PodsInit::$components->components[ $component ]['Name'], $dependency[0] ) . $website;
3891
3892 $ui->error( $message );
3893
3894 $ui->manage();
3895
3896 return;
3897 }
3898 }//end if
3899
3900 if ( ! empty( PodsInit::$components->components[ $component ]['ThemeDependency'] ) ) {
3901 $dependency = explode( '|', PodsInit::$components->components[ $component ]['ThemeDependency'] );
3902
3903 $check = strtolower( $dependency[1] );
3904
3905 if ( strtolower( get_template() ) !== $check && strtolower( get_stylesheet() ) !== $check ) {
3906 $website = '';
3907
3908 if ( isset( $dependency[2] ) ) {
3909 $website = ' ' . sprintf( __( 'You can find it at %s', 'pods' ), '<a href="' . $dependency[2] . '" target="_blank" rel="noopener noreferrer">' . $dependency[2] . '</a>' );
3910 }
3911
3912 $message = sprintf( __( 'The %1$s component requires that you have the <strong>%2$s</strong> theme installed and activated.', 'pods' ), PodsInit::$components->components[ $component ]['Name'], $dependency[0] ) . $website;
3913
3914 $ui->error( $message );
3915
3916 $ui->manage();
3917
3918 return;
3919 }
3920 }//end if
3921
3922 if ( ! empty( PodsInit::$components->components[ $component ]['MustUse'] ) ) {
3923 $message = sprintf( __( 'The %s component can not be disabled from here. You must deactivate the plugin or theme that added it.', 'pods' ), PodsInit::$components->components[ $component ]['Name'] );
3924
3925 $ui->error( $message );
3926
3927 $ui->manage();
3928
3929 return;
3930 }
3931
3932 if ( 1 === (int) pods_v( 'toggled' ) ) {
3933 $toggle = PodsInit::$components->toggle( $component );
3934
3935 if ( true === $toggle ) {
3936 $ui->message( PodsInit::$components->components[ $component ]['Name'] . ' ' . __( 'Component enabled', 'pods' ) );
3937 } elseif ( false === $toggle ) {
3938 $ui->message( PodsInit::$components->components[ $component ]['Name'] . ' ' . __( 'Component disabled', 'pods' ) );
3939 }
3940
3941 $components = PodsInit::$components->components;
3942
3943 foreach ( $components as $component => &$component_data ) {
3944 $toggle = 0;
3945
3946 if ( isset( PodsInit::$components->settings['components'][ $component_data['ID'] ] ) ) {
3947 if ( 0 !== PodsInit::$components->settings['components'][ $component_data['ID'] ] ) {
3948 $toggle = 1;
3949 }
3950 }
3951 if ( true === $component_data['DeveloperMode'] ) {
3952 if ( ! pods_developer() ) {
3953 unset( $components[ $component ] );
3954 continue;
3955 }
3956 }
3957
3958 $component_data = array(
3959 'id' => $component_data['ID'],
3960 'name' => $component_data['Name'],
3961 'description' => make_clickable( $component_data['Description'] ),
3962 'version' => $component_data['Version'],
3963 'author' => $component_data['Author'],
3964 'toggle' => $toggle,
3965 );
3966 }//end foreach
3967
3968 $ui->data = $components;
3969
3970 pods_transient_clear( 'pods_components' );
3971
3972 $url = pods_query_arg( array( 'toggled' => null ) );
3973
3974 pods_redirect( $url );
3975 } elseif ( 1 === (int) pods_v( 'toggle' ) ) {
3976 $ui->message( PodsInit::$components->components[ $component ]['Name'] . ' ' . __( 'Component enabled', 'pods' ) );
3977 } else {
3978 $ui->message( PodsInit::$components->components[ $component ]['Name'] . ' ' . __( 'Component disabled', 'pods' ) );
3979 }//end if
3980
3981 $ui->manage();
3982 }
3983
3984 /**
3985 * Get the admin upgrade page
3986 */
3987 public function admin_upgrade() {
3988
3989 foreach ( PodsInit::$upgrades as $old_version => $new_version ) {
3990 if ( version_compare( $old_version, PodsInit::$version_last, '<=' ) && version_compare( PodsInit::$version_last, $new_version, '<' ) ) {
3991 $new_version = str_replace( '.', '_', $new_version );
3992
3993 pods_view( PODS_DIR . 'ui/admin/upgrade/upgrade_' . $new_version . '.php', compact( array_keys( get_defined_vars() ) ) );
3994
3995 break;
3996 }
3997 }
3998 }
3999
4000 /**
4001 * Get the admin help page
4002 */
4003 public function admin_help() {
4004 // Add our custom callouts.
4005 $this->handle_callouts_updates();
4006
4007 if ( $this->has_horizontal_callout() ) {
4008 add_action( 'pods_admin_before_help', [ $this, 'admin_manage_callouts' ] );
4009 } else {
4010 add_action( 'pods_admin_after_help', [ $this, 'admin_manage_callouts' ] );
4011 }
4012
4013 pods_view( PODS_DIR . 'ui/admin/help.php', compact( array_keys( get_defined_vars() ) ) );
4014 }
4015
4016 /**
4017 * Add pods specific capabilities.
4018 *
4019 * @param array $capabilities List of extra capabilities to add.
4020 *
4021 * @return array
4022 */
4023 public function admin_capabilities( $capabilities ) {
4024
4025 $pods = pods_api()->load_pods(
4026 array(
4027 'type' => array(
4028 'settings',
4029 'post_type',
4030 'taxonomy',
4031 ),
4032 )
4033 );
4034
4035 $other_pods = pods_api()->load_pods(
4036 array(
4037 'type' => array(
4038 'pod',
4039 'table',
4040 ),
4041 )
4042 );
4043
4044 $pods = array_merge( $pods, $other_pods );
4045
4046 $capabilities[] = 'pods';
4047 $capabilities[] = 'pods_content';
4048 $capabilities[] = 'pods_settings';
4049 $capabilities[] = 'pods_components';
4050
4051 foreach ( $pods as $pod ) {
4052 if ( 'settings' === $pod['type'] ) {
4053 $capabilities[] = 'pods_edit_' . $pod['name'];
4054 } elseif ( 'post_type' === $pod['type'] ) {
4055 $capability_type = pods_v_sanitized( 'capability_type_custom', $pod['options'], pods_v( 'name', $pod ) );
4056
4057 if ( 'custom' === pods_v( 'capability_type', $pod['options'] ) && is_string( $capability_type ) && 0 < strlen( $capability_type ) ) {
4058 $capabilities[] = 'read_' . $capability_type;
4059 $capabilities[] = 'edit_' . $capability_type;
4060 $capabilities[] = 'delete_' . $capability_type;
4061
4062 if ( 1 === (int) pods_v( 'capability_type_extra', $pod['options'], 1 ) ) {
4063 $capability_type_plural = $capability_type . 's';
4064
4065 $capabilities[] = 'read_private_' . $capability_type_plural;
4066 $capabilities[] = 'edit_' . $capability_type_plural;
4067 $capabilities[] = 'edit_others_' . $capability_type_plural;
4068 $capabilities[] = 'edit_private_' . $capability_type_plural;
4069 $capabilities[] = 'edit_published_' . $capability_type_plural;
4070 $capabilities[] = 'publish_' . $capability_type_plural;
4071 $capabilities[] = 'delete_' . $capability_type_plural;
4072 $capabilities[] = 'delete_private_' . $capability_type_plural;
4073 $capabilities[] = 'delete_published_' . $capability_type_plural;
4074 $capabilities[] = 'delete_others_' . $capability_type_plural;
4075 }
4076 }
4077 } elseif ( 'taxonomy' === $pod['type'] ) {
4078 if ( 'custom' === pods_v( 'capability_type', $pod['options'], 'terms' ) ) {
4079 $capability_type = pods_v_sanitized( 'capability_type_custom', $pod['options'], pods_v( 'name', $pod ) . 's' );
4080
4081 $capability_type .= '_term';
4082 $capability_type_plural = $capability_type . 's';
4083
4084 // Singular
4085 $capabilities[] = 'edit_' . $capability_type;
4086 $capabilities[] = 'delete_' . $capability_type;
4087 $capabilities[] = 'assign_' . $capability_type;
4088 // Plural
4089 $capabilities[] = 'manage_' . $capability_type_plural;
4090 $capabilities[] = 'edit_' . $capability_type_plural;
4091 $capabilities[] = 'delete_' . $capability_type_plural;
4092 $capabilities[] = 'assign_' . $capability_type_plural;
4093 }
4094 } else {
4095 $capabilities[] = 'pods_add_' . $pod['name'];
4096 $capabilities[] = 'pods_edit_' . $pod['name'];
4097 $capabilities[] = 'pods_delete_' . $pod['name'];
4098
4099 if ( $pod instanceof Pod ) {
4100 $author_field = $pod->get_field( 'author', null, false );
4101 } else {
4102 $author_field = pods_v( 'author', $pod['fields'] );
4103 }
4104
4105 if ( $author_field && 'pick' === $author_field['type'] && 'user' === $author_field['pick_object'] ) {
4106 $capabilities[] = 'pods_edit_others_' . $pod['name'];
4107 $capabilities[] = 'pods_delete_others_' . $pod['name'];
4108 }
4109
4110 $actions_enabled = pods_v( 'ui_actions_enabled', $pod['options'] );
4111
4112 if ( ! empty( $actions_enabled ) ) {
4113 $actions_enabled = (array) $actions_enabled;
4114 } else {
4115 $actions_enabled = array();
4116 }
4117
4118 $available_actions = array(
4119 'add',
4120 'edit',
4121 'duplicate',
4122 'delete',
4123 'reorder',
4124 'export',
4125 );
4126
4127 if ( ! empty( $actions_enabled ) ) {
4128 $actions_disabled = array(
4129 'view' => 'view',
4130 );
4131
4132 foreach ( $available_actions as $action ) {
4133 if ( ! in_array( $action, $actions_enabled, true ) ) {
4134 $actions_disabled[ $action ] = $action;
4135 }
4136 }
4137
4138 if ( ! in_array( 'export', $actions_disabled, true ) ) {
4139 $capabilities[] = 'pods_export_' . $pod['name'];
4140 }
4141
4142 if ( ! in_array( 'reorder', $actions_disabled, true ) ) {
4143 $capabilities[] = 'pods_reorder_' . $pod['name'];
4144 }
4145 } elseif ( 1 === (int) pods_v( 'ui_export', $pod['options'], 0 ) ) {
4146 $capabilities[] = 'pods_export_' . $pod['name'];
4147 }//end if
4148 }//end if
4149 }//end foreach
4150
4151 return $capabilities;
4152 }
4153
4154 /**
4155 * Handle ajax calls for the administration
4156 */
4157 public function admin_ajax() {
4158
4159 if ( false === headers_sent() ) {
4160 pods_session_start();
4161
4162 header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ) );
4163 }
4164
4165 // Sanitize input
4166 // @codingStandardsIgnoreLine
4167 $params = pods_unslash( (array) $_POST );
4168
4169 foreach ( $params as $key => $value ) {
4170 if ( 'action' === $key ) {
4171 continue;
4172 }
4173
4174 // Fixup $_POST data @codingStandardsIgnoreLine
4175 $_POST[ str_replace( '_podsfix_', '', $key ) ] = $_POST[ $key ];
4176
4177 // Fixup $params with unslashed data
4178 $params[ str_replace( '_podsfix_', '', $key ) ] = $value;
4179
4180 // Unset the _podsfix_* keys
4181 unset( $params[ $key ] );
4182 }
4183
4184 $params = (object) $params;
4185
4186 $methods = array(
4187 'add_pod' => array( 'priv' => true ),
4188 'save_pod' => array( 'priv' => true ),
4189 'load_sister_fields' => array( 'priv' => true ),
4190 'process_form' => array( 'custom_nonce' => true ),
4191 // priv handled through nonce
4192 'upgrade' => array( 'priv' => true ),
4193 'migrate' => array( 'priv' => true ),
4194 );
4195
4196 /**
4197 * AJAX Callbacks in field editor
4198 *
4199 * @since unknown
4200 *
4201 * @param array $methods Callback methods.
4202 * @param PodsAdmin $obj PodsAdmin object.
4203 */
4204 $methods = apply_filters( 'pods_admin_ajax_methods', $methods, $this );
4205
4206 if ( ! isset( $params->method ) || ! isset( $methods[ $params->method ] ) ) {
4207 return pods_error( __( 'Invalid AJAX request method', 'pods' ), $this );
4208 }
4209
4210 $defaults = array(
4211 'priv' => null,
4212 'name' => $params->method,
4213 'custom_nonce' => null,
4214 );
4215
4216 $method = (object) array_merge( $defaults, (array) $methods[ $params->method ] );
4217
4218 if ( empty( $method->priv ) && empty( $method->custom_nonce ) ) {
4219 return pods_error( __( 'Invalid AJAX request nonce handling', 'pods' ), $this );
4220 }
4221
4222 if (
4223 true !== $method->custom_nonce
4224 && (
4225 ! is_user_logged_in()
4226 || ! isset( $params->_wpnonce )
4227 || false === wp_verify_nonce( $params->_wpnonce, 'pods-' . $params->method )
4228 )
4229 ) {
4230 return pods_error( __( 'Unauthorized form request', 'pods' ), $this );
4231 }
4232
4233 // Cleaning up $params
4234 unset( $params->action );
4235 unset( $params->method );
4236
4237 if ( true !== $method->custom_nonce ) {
4238 unset( $params->_wpnonce );
4239 }
4240
4241 // Check permissions (convert to array to support multiple)
4242 if ( ! empty( $method->priv ) && ! pods_is_admin( array( 'pods' ) ) ) {
4243 if ( true !== $method->priv && pods_is_admin( $method->priv ) ) {
4244 // They have access to the custom priv.
4245 } else {
4246 // They do not have access.
4247 return pods_error( __( 'Access denied', 'pods' ), $this );
4248 }
4249 }
4250
4251 $params->method = $method->name;
4252
4253 $method_name = $method->name;
4254
4255 $params = apply_filters( "pods_api_{$method_name}", $params, $method );
4256
4257 $api = pods_api();
4258
4259 $api->display_errors = false;
4260
4261 if ( 'upgrade' === $method->name ) {
4262 $output = (string) pods_upgrade( $params->version )->ajax( $params );
4263 } elseif ( 'migrate' === $method->name ) {
4264 $output = (string) apply_filters( 'pods_api_migrate_run', $params );
4265 } else {
4266 if ( ! method_exists( $api, $method->name ) ) {
4267 return pods_error( __( 'API method does not exist', 'pods' ), $this );
4268 } elseif ( 'save_pod' === $method->name ) {
4269 if ( isset( $params->field_data_json ) && is_array( $params->field_data_json ) ) {
4270 $params->fields = $params->field_data_json;
4271
4272 unset( $params->field_data_json );
4273
4274 foreach ( $params->fields as $k => $v ) {
4275 if ( empty( $v ) ) {
4276 unset( $params->fields[ $k ] );
4277 } elseif ( ! is_array( $v ) ) {
4278 $params->fields[ $k ] = (array) @json_decode( $v, true );
4279 }
4280 }
4281 }
4282 }
4283
4284 // Dynamically call the API method
4285 $params = (array) $params;
4286
4287 $output = call_user_func( array( $api, $method->name ), $params );
4288 }//end if
4289
4290 // Output in json format
4291 if ( false !== $output ) {
4292
4293 /**
4294 * Pods Admin AJAX request was successful
4295 *
4296 * @since 2.6.8
4297 *
4298 * @param array $params AJAX parameters.
4299 * @param array|object|string $output Output for AJAX request.
4300 */
4301 do_action( "pods_admin_ajax_success_{$method->name}", $params, $output );
4302
4303 if ( is_array( $output ) || is_object( $output ) ) {
4304 wp_send_json( $output );
4305 } else {
4306 // @codingStandardsIgnoreLine
4307 echo $output;
4308 }
4309 } else {
4310 return pods_error( __( 'There was a problem with your request.', 'pods' ) );
4311 }//end if
4312
4313 die();
4314 // KBAI!
4315 }
4316
4317 /**
4318 * Profiles the Pods configuration
4319 *
4320 * @param null|string|array $pod Which Pod(s) to get configuration for. Can be a the name
4321 * of one Pod, or an array of names of Pods, or null, which is the
4322 * default, to profile all Pods.
4323 * @param bool $full_field_info If true all info about each field is returned. If false,
4324 * which is the default only name and type, will be returned.
4325 *
4326 * @return array
4327 *
4328 * @since 2.7.0
4329 * @deprecated 2.8.0
4330 */
4331 public function configuration( $pod = null, $full_field_info = false ) {
4332 pods_deprecated( 'PodsAdmin::configuration', '2.8' );
4333
4334 $api = pods_api();
4335
4336 if ( null === $pod ) {
4337 $the_pods = $api->load_pods();
4338 } elseif ( is_array( $pod ) ) {
4339 foreach ( $pod as $p ) {
4340 $the_pods[] = $api->load_pod( $p );
4341 }
4342 } else {
4343 $the_pods[] = $api->load_pod( $pod );
4344 }
4345
4346 foreach ( $the_pods as $the_pod ) {
4347 $configuration[ $the_pod['name'] ] = array(
4348 'name' => $the_pod['name'],
4349 'ID' => $the_pod['id'],
4350 'storage' => $the_pod['storage'],
4351 'fields' => $the_pod['fields'],
4352 );
4353 }
4354
4355 if ( ! $full_field_info ) {
4356 foreach ( $the_pods as $the_pod ) {
4357 $fields = $configuration[ $the_pod['name'] ]['fields'];
4358
4359 unset( $configuration[ $the_pod['name'] ]['fields'] );
4360
4361 foreach ( $fields as $field ) {
4362 $info = array(
4363 'name' => $field['name'],
4364 'type' => $field['type'],
4365 );
4366
4367 if ( 'pick' === $info['type'] ) {
4368 $info['pick_object'] = $field['pick_object'];
4369
4370 if ( isset( $field['pick_val'] ) && '' !== $field['pick_val'] ) {
4371 $info['pick_val'] = $field['pick_val'];
4372 }
4373 }
4374
4375 if ( is_array( $info ) ) {
4376 $configuration[ $the_pod['name'] ]['fields'][ $field['name'] ] = $info;
4377 }
4378
4379 unset( $info );
4380
4381 }//end foreach
4382 }//end foreach
4383 }//end if
4384
4385 if ( is_array( $configuration ) ) {
4386 return $configuration;
4387 }
4388
4389 }
4390
4391 /**
4392 * Build UI for extending REST API, if makes sense to do so.
4393 *
4394 * @since 2.6.0
4395 *
4396 * @access protected
4397 */
4398 protected function rest_admin() {
4399
4400 if ( function_exists( 'register_rest_field' ) ) {
4401 add_filter(
4402 'pods_admin_setup_edit_field_options', array(
4403 $this,
4404 'add_rest_fields_to_field_editor',
4405 ), 12, 2
4406 );
4407 add_filter( 'pods_admin_setup_edit_field_tabs', array( $this, 'add_rest_field_tab' ), 12, 2 );
4408 }
4409
4410 add_filter( 'pods_admin_setup_edit_tabs', array( $this, 'add_rest_settings_tab' ), 12, 2 );
4411 add_filter( 'pods_admin_setup_edit_options', array( $this, 'add_rest_settings_tab_fields' ), 12, 2 );
4412
4413 }
4414
4415 /**
4416 * Check if Pod type <em>could</em> extend core REST API response
4417 *
4418 * @since 2.5.6
4419 *
4420 * @access protected
4421 *
4422 * @param array $pod Pod options.
4423 *
4424 * @return bool
4425 */
4426 protected function restable_pod( $pod ) {
4427
4428 $type = $pod['type'];
4429
4430 $restable_types = array(
4431 'post_type',
4432 'user',
4433 'taxonomy',
4434 'media',
4435 );
4436
4437 return in_array( $type, $restable_types, true );
4438
4439 }
4440
4441 /**
4442 * Add a rest api tab.
4443 *
4444 * @since 2.6.0
4445 *
4446 * @param array $tabs Tab array.
4447 * @param array $pod Pod options.
4448 *
4449 * @return array
4450 */
4451 public function add_rest_settings_tab( $tabs, $pod ) {
4452 if ( ! $this->restable_pod( $pod ) ) {
4453 return $tabs;
4454 }
4455
4456 $tabs['rest-api'] = __( 'REST API', 'pods' );
4457
4458 return $tabs;
4459
4460 }
4461
4462 /**
4463 * Populate REST API tab.
4464 *
4465 * @since 0.1.0
4466 *
4467 * @param array $options Tab options.
4468 * @param Pod $pod Pod options.
4469 *
4470 * @return array
4471 */
4472 public function add_rest_settings_tab_fields( $options, $pod ) {
4473 if ( ! $this->restable_pod( $pod ) ) {
4474 return $options;
4475 }
4476
4477 $options['rest-api'] = [
4478 'rest_enable' => [
4479 'label' => __( 'Enable', 'pods' ),
4480 'help' => __( 'Add REST API support for this Pod.', 'pods' ),
4481 'type' => 'boolean',
4482 'default' => '',
4483 'dependency' => true,
4484 ],
4485 'rest_base' => [
4486 'label' => __( 'REST Base (if any)', 'pods' ),
4487 'help' => __( 'This will form the url for the route. Default / empty value here will use the pod name.', 'pods' ),
4488 'type' => 'text',
4489 'default' => '',
4490 'depends-on' => [ 'rest_enable' => true ],
4491 ],
4492 'rest_namespace' => [
4493 'label' => __( 'REST API namespace', 'pods' ),
4494 'help' => __( 'This will change the namespace URL of the REST API route to a different one from the default one that all normal route endpoints use.', 'pods' ),
4495 'type' => 'text',
4496 'default' => '',
4497 'placeholder' => 'wp/v2',
4498 'depends-on' => [ 'rest_enable' => true ],
4499 ],
4500 'read_all' => [
4501 'label' => __( 'Show All Fields (read-only)', 'pods' ),
4502 'help' => __( 'Show all fields in REST API. If unchecked fields must be enabled on a field by field basis.', 'pods' ),
4503 'type' => 'boolean',
4504 'default' => '',
4505 'depends-on' => [ 'rest_enable' => true ],
4506 'dependency' => true,
4507 ],
4508 'read_all_access' => [
4509 'label' => __( 'Read All Access', 'pods' ),
4510 'help' => __( 'By default the REST API will allow the fields to be returned for everyone who has access to that endpoint/object. You can also restrict the access of your field based on whether the person is logged in.', 'pods' ),
4511 'type' => 'boolean',
4512 'boolean_yes_label' => __( 'Require being logged in to read all field values via REST', 'pods' ),
4513 'depends-on' => [
4514 'read_all' => true,
4515 ],
4516 ],
4517 'write_all' => [
4518 'label' => __( 'Allow All Fields To Be Updated', 'pods' ),
4519 'help' => __( 'Allow all fields to be updated via the REST API. If unchecked fields must be enabled on a field by field basis.', 'pods' ),
4520 'type' => 'boolean',
4521 'default' => '',
4522 'depends-on' => [ 'rest_enable' => true, 'read_all' => true ],
4523 ],
4524 /*'write_all_access' => [
4525 'label' => __( 'Write All Access', 'pods' ),
4526 'help' => __( 'By default the REST API will allow the fields to be written by everyone who has access to edit that object. You can also restrict the access of your field based on whether the person is logged in.', 'pods' ),
4527 'type' => 'boolean',
4528 'boolean_yes_label' => __( 'Require being logged in to write to all field values via REST', 'pods' ),
4529 'depends-on' => [
4530 'write_all' => true,
4531 ],
4532 ],*/
4533 'rest_api_field_mode' => [
4534 'label' => __( 'Field Mode', 'pods' ),
4535 'help' => __( 'Specify how you would like your values returned in the REST API responses. If you choose to show Both raw and rendered values then an object will be returned for each field that contains the value and rendered properties.', 'pods' ),
4536 'type' => 'pick',
4537 'pick_format_single' => 'radio',
4538 'default' => 'value',
4539 'depends-on' => [ 'rest_enable' => true ],
4540 'data' => [
4541 'value' => __( 'Raw values', 'pods' ),
4542 'render' => __( 'Rendered values', 'pods' ),
4543 'value_and_render' => __( 'Both raw and rendered values {value: raw_value, rendered: rendered_value}', 'pods' ),
4544 ],
4545 ],
4546 'rest_api_field_location' => [
4547 'label' => __( 'Field Location', 'pods' ),
4548 'help' => __( 'Specify where you would like your values returned in the REST API responses. To show in the "meta" object of the response, you must have Custom Fields enabled in the Post Type Supports features.', 'pods' ),
4549 'type' => 'pick',
4550 'pick_format_single' => 'radio',
4551 'default' => 'object',
4552 'depends-on' => [ 'rest_enable' => true ],
4553 'data' => [
4554 'object' => __( 'Show as a custom object field (response.field_name)', 'pods' ),
4555 'meta' => __( 'Include in the meta object (response.meta.field_name)', 'pods' ),
4556 ],
4557 ],
4558 ];
4559
4560 if ( ! $pod->is_extended() ) {
4561 unset( $options['rest_base'] );
4562 unset( $options['rest_namespace'] );
4563 }
4564
4565 if ( 'post_type' !== $pod->get_type() ) {
4566 unset( $options['rest_api_field_location'] );
4567 }
4568
4569 return $options;
4570 }
4571
4572 /**
4573 * Add a REST API section to advanced tab of field editor.
4574 *
4575 * @since 2.5.6
4576 *
4577 * @param array $options Tab options.
4578 * @param array $pod Pod options.
4579 *
4580 * @return array
4581 */
4582 public function add_rest_fields_to_field_editor( $options, $pod ) {
4583 if ( ! $this->restable_pod( $pod ) ) {
4584 return $options;
4585 }
4586
4587 $layout_non_input_field_types = PodsForm::layout_field_types() + PodsForm::non_input_field_types();
4588
4589 $options['rest'] = [
4590 'rest_read_write' => [
4591 'name' => 'rest_read_write',
4592 'type' => 'heading',
4593 'label' => __( 'Read/Write', 'pods' ),
4594 ],
4595 'rest_read' => [
4596 'label' => __( 'Read via REST API', 'pods' ),
4597 'help' => __( 'Should this field be readable via the REST API? You must enable REST API support for this Pod.', 'pods' ),
4598 'type' => 'boolean',
4599 'default' => '',
4600 'excludes-on' => [
4601 'type' => $layout_non_input_field_types,
4602 ],
4603 ],
4604 'rest_read_access' => [
4605 'label' => __( 'Read Access', 'pods' ),
4606 'help' => __( 'By default the REST API will allow the fields to be returned for everyone who has access to that endpoint/object. You can also restrict the access of your field based on whether the person is logged in.', 'pods' ),
4607 'type' => 'boolean',
4608 'boolean_yes_label' => __( 'Require being logged in to read this field value via REST', 'pods' ),
4609 'depends-on' => [
4610 'rest_read' => true,
4611 ],
4612 'excludes-on' => [
4613 'type' => $layout_non_input_field_types,
4614 ],
4615 ],
4616 'rest_write' => [
4617 'label' => __( 'Write via REST API', 'pods' ),
4618 'help' => __( 'Should this field be writeable via the REST API? You must enable REST API support for this Pod.', 'pods' ),
4619 'type' => 'boolean',
4620 'default' => '',
4621 'excludes-on' => [
4622 'type' => $layout_non_input_field_types,
4623 ],
4624 ],
4625 /*'rest_write_access' => [
4626 'label' => __( 'Write Access', 'pods' ),
4627 'help' => __( 'By default the REST API will allow the fields to be written by everyone who has access to edit that object. You can also restrict the access of your field based on whether the person is logged in.', 'pods' ),
4628 'type' => 'boolean',
4629 'boolean_yes_label' => __( 'Require being logged in to write to this field value via REST', 'pods' ),
4630 'depends-on' => [
4631 'rest_write' => true,
4632 ],
4633 'excludes-on' => [
4634 'type' => $layout_non_input_field_types,
4635 ],
4636 ],*/
4637 'rest_field_options' => [
4638 'name' => 'rest_field_options',
4639 'label' => __( 'Relationship Field Options', 'pods' ),
4640 'type' => 'heading',
4641 'depends-on' => [
4642 'type' => 'pick',
4643 ],
4644 ],
4645 'rest_pick_response' => [
4646 'label' => __( 'Response Type', 'pods' ),
4647 'help' => __( 'This will determine what amount of data for the related items will be returned.', 'pods' ),
4648 'type' => 'pick',
4649 'pick_format_single' => 'dropdown',
4650 'default' => 'array',
4651 'depends-on' => [
4652 'type' => 'pick',
4653 ],
4654 'dependency' => true,
4655 'data' => [
4656 'array' => __( 'All fields', 'pods' ),
4657 'id' => __( 'ID only', 'pods' ),
4658 'name' => __( 'Name only', 'pods' ),
4659 'custom' => __( 'Custom return (specify field to return)', 'pods' ),
4660 ],
4661 'excludes-on' => [
4662 'type' => $layout_non_input_field_types,
4663 ],
4664 ],
4665 'rest_pick_depth' => [
4666 'label' => __( 'Depth', 'pods' ),
4667 'help' => __( 'How far to traverse relationships in response. 1 will get you all of the fields on the related item. 2 will get you all of those fields plus related items and their fields. The higher the depth, the more data will be returned and the slower performance the REST API calls will be. Updates to this field do NOT take depth into account, so you will always send the ID of the related item when saving.', 'pods' ),
4668 'type' => 'number',
4669 'default' => '1',
4670 'depends-on' => [
4671 'type' => 'pick',
4672 'rest_pick_response' => 'array',
4673 ],
4674 'excludes-on' => [
4675 'type' => $layout_non_input_field_types,
4676 ],
4677 ],
4678 'rest_pick_custom' => [
4679 'label' => __( 'Custom return', 'pods' ),
4680 'help' => __( 'Specify the field to use following the established this_field_name.ID traversal pattern. You must include this field name in the selector for this to work properly.', 'pods' ),
4681 'type' => 'text',
4682 'default' => '',
4683 'placeholder' => 'this_field_name.ID',
4684 'depends-on' => [
4685 'type' => 'pick',
4686 'rest_pick_response' => 'custom',
4687 ],
4688 'excludes-on' => [
4689 'type' => $layout_non_input_field_types,
4690 ],
4691 ],
4692 ];
4693
4694 return $options;
4695 }
4696
4697 /**
4698 * Add REST field tab
4699 *
4700 * @since 2.5.6
4701 *
4702 * @param array $tabs Tab list.
4703 * @param array $pod The ood object.
4704 *
4705 * @return array
4706 */
4707 public function add_rest_field_tab( $tabs, $pod ) {
4708 if ( ! $this->restable_pod( $pod ) ) {
4709 return $tabs;
4710 }
4711
4712 $tabs['rest'] = __( 'REST API', 'pods' );
4713
4714 return $tabs;
4715 }
4716
4717 /**
4718 * Add Pods-specific debug info to Site Info debug area.
4719 *
4720 * @since 2.7.13
4721 *
4722 * @param array $info Debug info.
4723 *
4724 * @return array Debug info with Pods-specific debug info added.
4725 */
4726 public function add_debug_information( $info ) {
4727 $auto_start = pods_session_auto_start();
4728
4729 if ( 'auto' !== $auto_start ) {
4730 // Turn boolean into 0/1.
4731 $auto_start = (int) $auto_start;
4732 }
4733
4734 // Turn into a string.
4735 $auto_start = (string) $auto_start;
4736
4737 $settings = pods_container( Settings::class );
4738
4739 $settings_fields = $settings->get_setting_fields();
4740
4741 $settings_values = $settings->get_settings();
4742
4743 $auto_start = pods_v( $auto_start, $settings_fields['session_auto_start']['data'], __( 'Unknown', 'pods' ) );
4744
4745 global $wpdb;
4746
4747 $info['pods'] = [
4748 'label' => 'Pods',
4749 'description' => __( 'Debug information for Pods installations.', 'pods' ),
4750 'fields' => [
4751 'pods-version' => [
4752 'label' => __( 'Pods Version', 'pods' ),
4753 'value' => PODS_VERSION,
4754 ],
4755 'pods-first-version' => [
4756 'label' => __( 'Pods Version (First installed)', 'pods' ),
4757 'value' => get_option( 'pods_framework_version_first', PODS_VERSION ),
4758 ],
4759 'pods-last-version' => [
4760 'label' => __( 'Pods Version (Last updated from)', 'pods' ),
4761 'value' => get_option( 'pods_framework_version_last', PODS_VERSION ),
4762 ],
4763 'pods-server-software' => [
4764 'label' => __( 'Server Software', 'pods' ),
4765 'value' => ! empty( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : 'N/A',
4766 ],
4767 'pods-user-agent' => [
4768 'label' => __( 'Your User Agent', 'pods' ),
4769 'value' => ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : 'N/A',
4770 ],
4771 'pods-session-save-path' => [
4772 'label' => __( 'Session Save Path', 'pods' ),
4773 'value' => session_save_path(),
4774 ],
4775 'pods-session-save-path-exists' => [
4776 'label' => __( 'Session Save Path Exists', 'pods' ),
4777 'value' => file_exists( session_save_path() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4778 ],
4779 'pods-session-save-path-writable' => [
4780 'label' => __( 'Session Save Path Writeable', 'pods' ),
4781 'value' => is_writable( session_save_path() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4782 ],
4783 'pods-session-max-lifetime' => [
4784 'label' => __( 'Session Max Lifetime', 'pods' ),
4785 'value' => ini_get( 'session.gc_maxlifetime' ),
4786 ],
4787 'pods-opcode-cache-apc' => [
4788 'label' => __( 'Opcode Cache: Apc', 'pods' ),
4789 'value' => function_exists( 'apc_cache_info' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4790 ],
4791 'pods-opcode-cache-memcached' => [
4792 'label' => __( 'Opcode Cache: Memcached', 'pods' ),
4793 'value' => class_exists( 'eaccelerator_put' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4794 ],
4795 'pods-opcode-cache-opcache' => [
4796 'label' => __( 'Opcode Cache: OPcache', 'pods' ),
4797 'value' => function_exists( 'opcache_get_status' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4798 ],
4799 'pods-opcode-cache-redis' => [
4800 'label' => __( 'Opcode Cache: Redis', 'pods' ),
4801 'value' => class_exists( 'xcache_set' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4802 ],
4803 'pods-object-cache-apc' => [
4804 'label' => __( 'Object Cache: APC', 'pods' ),
4805 'value' => function_exists( 'apc_cache_info' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4806 ],
4807 'pods-object-cache-apcu' => [
4808 'label' => __( 'Object Cache: APCu', 'pods' ),
4809 'value' => function_exists( 'apcu_cache_info' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4810 ],
4811 'pods-object-cache-memcache' => [
4812 'label' => __( 'Object Cache: Memcache', 'pods' ),
4813 'value' => class_exists( 'Memcache' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4814 ],
4815 'pods-object-cache-memcached' => [
4816 'label' => __( 'Object Cache: Memcached', 'pods' ),
4817 'value' => class_exists( 'Memcached' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4818 ],
4819 'pods-object-cache-redis' => [
4820 'label' => __( 'Object Cache: Redis', 'pods' ),
4821 'value' => class_exists( 'Redis' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4822 ],
4823 'pods-memory-current-usage' => [
4824 'label' => __( 'Current Memory Usage', 'pods' ),
4825 'value' => number_format_i18n( memory_get_usage() / 1024 / 1024, 3 ) . 'M' . ( defined( 'WP_MEMORY_LIMIT' ) ? ' / ' . WP_MEMORY_LIMIT : '' ),
4826 ],
4827 'pods-memory-current-usage-real' => [
4828 'label' => __( 'Current Memory Usage (real)', 'pods' ),
4829 'value' => number_format_i18n( memory_get_usage( true ) / 1024 / 1024, 3 ) . 'M',
4830 ],
4831 'pods-network-wide' => [
4832 'label' => __( 'Pods Network-Wide Activated', 'pods' ),
4833 'value' => is_plugin_active_for_network( basename( PODS_DIR ) . '/init.php' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4834 ],
4835 'pods-install-location' => [
4836 'label' => __( 'Pods Install Location', 'pods' ),
4837 'value' => str_replace( ABSPATH, '/', PODS_DIR ),
4838 ],
4839 'pods-developer' => [
4840 'label' => __( 'Pods Developer Activated' ),
4841 'value' => ( pods_developer() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4842 ],
4843 'pods-tableless-mode' => [
4844 'label' => __( 'Pods Tableless Mode Activated', 'pods' ),
4845 'value' => ( pods_tableless() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4846 ],
4847 'pods-relationship-table-enabled' => [
4848 'label' => __( 'Pods Relationship Table Enabled', 'pods' ),
4849 'value' => ( pods_podsrel_enabled() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4850 ],
4851 'pods-relationship-table-status' => [
4852 'label' => __( 'Pods Relationship Table Count' ),
4853 'value' => ( ! pods_tableless() ? number_format( (float) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}podsrel" ) ) : 'No table' ),
4854 ],
4855 'pods-light-mode' => [
4856 'label' => __( 'Pods Light Mode Activated', 'pods' ),
4857 'value' => ( pods_light() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4858 ],
4859 'pods-strict' => [
4860 'label' => __( 'Pods Strict Activated' ),
4861 'value' => ( pods_strict( false ) ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4862 ],
4863 'pods-allow-deprecated' => [
4864 'label' => __( 'Pods Allow Deprecated' ),
4865 'value' => ( pods_allow_deprecated() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4866 ],
4867 'pods-api-cache' => [
4868 'label' => __( 'Pods API Cache Activated' ),
4869 'value' => ( pods_api_cache() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4870 ],
4871 'pods-shortcode-allow-evaluate-tags' => [
4872 'label' => __( 'Pods Shortcode Allow Evaluate Tags' ),
4873 'value' => ( pods_shortcode_allow_evaluate_tags() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4874 ],
4875 'pods-can-use-sessions' => [
4876 'label' => __( 'Pods Can Use Sessions' ),
4877 'value' => ( pods_can_use_sessions( true ) ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
4878 ],
4879 ],
4880 ];
4881
4882 foreach ( $settings_fields as $setting_name => $setting_field ) {
4883 if ( empty( $setting_field['site_health_include_in_info'] ) ) {
4884 continue;
4885 }
4886
4887 if ( isset( $setting_field['name'] ) ) {
4888 $setting_name = $setting_field['name'];
4889 }
4890
4891 $setting_key = 'pods-settings-' . sanitize_title_with_dashes( $setting_name );
4892
4893 $value = pods_v( $setting_name, $settings_values );
4894
4895 $original_value = is_array( $value ) ? implode( ',', $value ) : (string) $value;
4896
4897 if ( is_array( $value ) ) {
4898 foreach ( $value as $k => $v ) {
4899 $v = (string) $v;
4900
4901 $has_v = 0 < strlen( $v );
4902
4903 if ( $has_v && isset( $setting_field['site_health_data'] ) && isset( $setting_field['site_health_data'][ $v ] ) ) {
4904 $value[ $k ] = $setting_field['site_health_data'][ $v ];
4905 } elseif ( $has_v && isset( $setting_field['data'] ) && isset( $setting_field['data'][ $v ] ) ) {
4906 $value[ $k ] = $setting_field['data'][ $v ];
4907 }
4908 }
4909
4910 $value = pods_serial_comma( $value );
4911 } else {
4912 $value = (string) $value;
4913
4914 $has_value = 0 < strlen( $value );
4915
4916 if ( $has_value && isset( $setting_field['site_health_data'] ) && isset( $setting_field['site_health_data'][ $value ] ) ) {
4917 $value = $setting_field['site_health_data'][ $value ];
4918 } elseif ( $has_value && isset( $setting_field['data'] ) && isset( $setting_field['data'][ $value ] ) ) {
4919 $value = $setting_field['data'][ $value ];
4920 } elseif (
4921 (
4922 isset( $setting_field['data'] )
4923 && 'boolean' === $setting_field['data']
4924 )
4925 && (
4926 '1' === $value
4927 || '0' === $value
4928 )
4929 ) {
4930 $value = '1' === $value ? __( 'Yes', 'pods' ) : __( 'No', 'pods' );
4931 }
4932 }
4933
4934 if ( 'unknown' === $value || '' === $value ) {
4935 $value = __( 'Unknown', 'pods' );
4936 }
4937
4938 $info['pods']['fields'][ $setting_key ] = [
4939 'label' => $setting_field['label'],
4940 'value' => $value . ( $value !== $original_value ? ' [' . $setting_name . '=' . $original_value . ']' : '' ),
4941 ];
4942 }
4943
4944 // @todo Later we should add which components are active.
4945
4946 return $info;
4947 }
4948
4949 /**
4950 * Add our site status tests.
4951 *
4952 * @since 2.8.0
4953 *
4954 * @param array $tests The list of status tests.
4955 *
4956 * @return array The list of status tests.
4957 */
4958 public function site_status_tests( $tests ) {
4959 $plugin_search_url = 'plugin-install.php?tab=search&type=term&s=';
4960
4961 if ( is_multisite() && ! is_network_admin() ) {
4962 $plugin_search_url = network_admin_url( $plugin_search_url );
4963 } else {
4964 $plugin_search_url = self_admin_url( $plugin_search_url );
4965 }
4966
4967 if ( ! is_pods_alternative_cache_activated() && ! wp_using_ext_object_cache() ) {
4968 $tests['direct']['pods_alternative_cache'] = [
4969 'label' => __( 'Pods Alternative Cache', 'pods' ),
4970 'test' => static function () use ( $plugin_search_url ) {
4971 return [
4972 'label' => __( 'The Pods Team recommends you install the Pods Alternative Cache plugin', 'pods' ),
4973 'status' => 'recommended',
4974 'badge' => [
4975 'label' => __( 'Performance', 'pods' ),
4976 'color' => 'blue',
4977 ],
4978 'description' => sprintf( '<p>%s</p>', __( 'You are not using an external object cache for this site. Pods Alternative Cache is usually useful for Pods installs that use Shared Hosting with limited Object Cache capabilities.', 'pods' ) ),
4979 'actions' => sprintf( '<p><a href="%s">%s</a></p>', esc_url( $plugin_search_url . urlencode( 'Pods Alternative Cache' ) ), __( 'Install Pods Alternative Cache', 'pods' ) ),
4980 'test' => 'pods_alternative_cache',
4981 ];
4982 },
4983 ];
4984 }
4985
4986 return $tests;
4987 }
4988
4989 /**
4990 * Check whether the requirements were met and maybe display error messages.
4991 *
4992 * @since 2.9.0
4993 *
4994 * @param array $requirements List of requirements.
4995 *
4996 * @return bool Whether the requirements were met.
4997 */
4998 public function check_requirements( array $requirements ) {
4999 foreach ( $requirements as $requirement ) {
5000 // Check if requirement passed.
5001 if ( $requirement['check'] ) {
5002 continue;
5003 }
5004
5005 // Show admin notice if there's a message to be shown.
5006 if ( ! empty( $requirement['message'] ) && $this->should_show_notices() ) {
5007 pods_message( $requirement['message'], 'error' );
5008 }
5009
5010 return false;
5011 }
5012
5013 return true;
5014 }
5015
5016 /**
5017 * Check whether we should show notices.
5018 *
5019 * @since 2.9.0
5020 *
5021 * @return bool Whether we should show notices.
5022 */
5023 public function should_show_notices() {
5024 global $pagenow;
5025
5026 // We only show notices on admin pages.
5027 if ( ! is_admin() ) {
5028 return false;
5029 }
5030
5031 $page = isset( $_GET['page'] ) ? $_GET['page'] : '';
5032
5033 // We only show on the plugins.php page or on Pods Admin pages.
5034 if (
5035 (
5036 'plugins.php' !== $pagenow
5037 && 0 !== strpos( $page, 'pods' )
5038 )
5039 || 0 === strpos( $page, 'pods-manage-' )
5040 ) {
5041 return false;
5042 }
5043
5044 return true;
5045 }
5046
5047 }
5048