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