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