PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 2.9.19.5
Pods – Custom Content Types and Fields v2.9.19.5
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 1 day ago fields 1 day ago widgets 1 day ago Pods.php 1 day ago PodsAPI.php 1 day ago PodsAdmin.php 1 day ago PodsArray.php 1 day ago PodsComponent.php 1 day ago PodsComponents.php 1 day ago PodsData.php 1 day ago PodsField.php 1 day ago PodsForm.php 1 day ago PodsI18n.php 1 day ago PodsInit.php 1 day ago PodsMeta.php 1 day ago PodsMigrate.php 1 day ago PodsRESTFields.php 1 day ago PodsRESTHandlers.php 1 day ago PodsTermSplitting.php 1 day ago PodsUI.php 1 day ago PodsView.php 1 day ago
PodsAdmin.php
3547 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', array( $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'], __( 'Add New', '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'], __( 'Add New', 'pods' ) . ' ' . $singular_label );
311 $add_label = pods_v( 'label_add_new', $pod['options'], __( 'Add New', 'pods' ) );
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-settings' => array(
556 'label' => __( 'Settings', 'pods' ),
557 'title' => __( 'Pods Settings', 'pods' ),
558 'function' => array( $this, 'admin_settings' ),
559 'access' => 'pods_settings',
560 ),
561 'pods-help' => array(
562 'label' => __( 'Help', 'pods' ),
563 'title' => __( 'Pods Help', 'pods' ),
564 'function' => array( $this, 'admin_help' ),
565 ),
566 );
567
568 add_filter( 'parent_file', array( $this, 'parent_file' ) );
569 } else {
570 $admin_menus = array(
571 'pods-upgrade' => array(
572 'label' => __( 'Upgrade', 'pods' ),
573 'function' => array( $this, 'admin_upgrade' ),
574 'access' => 'manage_options',
575 ),
576 'pods-settings' => array(
577 'label' => __( 'Settings', 'pods' ),
578 'title' => __( 'Pods Settings', 'pods' ),
579 'function' => array( $this, 'admin_settings' ),
580 'access' => 'pods_settings',
581 ),
582 'pods-help' => array(
583 'label' => __( 'Help', 'pods' ),
584 'title' => __( 'Pods Help', 'pods' ),
585 'function' => array( $this, 'admin_help' ),
586 ),
587 );
588
589 add_action( 'admin_notices', array( $this, 'upgrade_notice' ) );
590 }//end if
591
592 /**
593 * Add or change Pods Admin menu items
594 *
595 * @param array $admin_menus The submenu items in Pods Admin menu.
596 *
597 * @since unknown
598 */
599 $admin_menus = apply_filters( 'pods_admin_menu', $admin_menus );
600
601 $parent = false;
602
603 // PODS_LIGHT disables all Pods components so remove the components menu
604 if ( pods_light() ) {
605 unset( $admin_menus['pods-components'] );
606 }
607
608 if ( ! empty( $admin_menus ) && ( ! defined( 'PODS_DISABLE_ADMIN_MENU' ) || ! PODS_DISABLE_ADMIN_MENU ) ) {
609 foreach ( $admin_menus as $page => $menu_item ) {
610 if ( ! pods_is_admin( pods_v( 'access', $menu_item ) ) ) {
611 continue;
612 }
613
614 // Don't just show the help page
615 if ( false === $parent && 'pods-help' === $page ) {
616 continue;
617 }
618
619 if ( empty( $menu_item['label'] ) ) {
620 $menu_item['label'] = $page;
621 }
622
623 if ( empty( $menu_item['title'] ) ) {
624 $menu_item['title'] = $menu_item['label'];
625 }
626
627 if ( false === $parent ) {
628 $parent = $page;
629
630 $menu = __( 'Pods Admin', 'pods' );
631
632 if ( 'pods-upgrade' === $parent ) {
633 $menu = __( 'Pods Upgrade', 'pods' );
634 }
635
636 add_menu_page( $menu, $menu, 'read', $parent, null, pods_svg_icon( 'pods' ) );
637 }
638
639 add_submenu_page( $parent, $menu_item['title'], $menu_item['label'], 'read', $page, $menu_item['function'] );
640
641 if ( 'pods-components' === $page && is_object( PodsInit::$components ) ) {
642 PodsInit::$components->menu( $parent );
643 }
644 }//end foreach
645 }//end if
646 }
647
648 /**
649 * Set the correct parent_file to highlight the correct top level menu
650 *
651 * @param string $parent_file The parent file.
652 *
653 * @return mixed|string
654 *
655 * @since unknown
656 */
657 public function parent_file( $parent_file ) {
658 global $current_screen, $submenu_file;
659
660 if ( isset( $current_screen ) && ! empty( $current_screen->taxonomy ) ) {
661 $taxonomies = PodsMeta::$taxonomies;
662 if ( ! empty( $taxonomies ) ) {
663 foreach ( (array) $taxonomies as $pod ) {
664 if ( $current_screen->taxonomy !== $pod['name'] ) {
665 continue;
666 }
667
668 $menu_slug = 'edit-tags.php?taxonomy=' . $pod['name'];
669 $menu_location = pods_v( 'menu_location', $pod['options'], 'default' );
670 $menu_location_custom = pods_v( 'menu_location_custom', $pod['options'], '' );
671
672 if ( 'settings' === $menu_location ) {
673 $parent_file = 'options-general.php';
674 } elseif ( 'appearances' === $menu_location ) {
675 $parent_file = 'themes.php';
676 } elseif ( 'objects' === $menu_location ) {
677 $parent_file = $menu_slug;
678 } elseif ( 'top' === $menu_location ) {
679 $parent_file = $menu_slug;
680 } elseif ( 'submenu' === $menu_location && ! empty( $menu_location_custom ) ) {
681 $parent_file = $menu_location_custom;
682 }
683
684 break;
685 }//end foreach
686 }//end if
687 }//end if
688
689 if ( isset( $current_screen ) && ! empty( $current_screen->post_type ) && is_object( PodsInit::$components ) ) {
690 $components_menu_items = PodsInit::$components->components_menu_items;
691
692 foreach ( $components_menu_items as $menu_item ) {
693 if ( empty( $menu_item['menu_page'] ) || $parent_file !== $menu_item['menu_page'] ) {
694 continue;
695 }
696
697 $parent_file = 'pods';
698
699 // @codingStandardsIgnoreLine
700 $submenu_file = $menu_item['menu_page'];
701
702 break;
703 }
704 }
705
706 return $parent_file;
707 }
708
709 /**
710 * Show upgrade notice.
711 */
712 public function upgrade_notice() {
713
714 echo '<div class="error fade"><p>';
715 // @codingStandardsIgnoreLine
716 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' ) ) );
717 echo '</p></div>';
718 }
719
720 /**
721 * Create PodsUI content for the administration pages
722 */
723 public function admin_content() {
724
725 // @codingStandardsIgnoreLine
726 $pod_name = str_replace( array( 'pods-manage-', 'pods-add-new-' ), '', $_GET['page'] );
727
728 $pod = pods_get_instance( $pod_name, pods_v( 'id', 'get', null, true ) );
729
730 if ( ! $pod->pod_data->has_fields() ) {
731 pods_message( __( 'This Pod does not have any fields defined.', 'pods' ), 'error' );
732 return;
733 }
734
735 // @codingStandardsIgnoreLine
736 if ( false !== strpos( $_GET['page'], 'pods-add-new-' ) ) {
737 // @codingStandardsIgnoreLine
738 $_GET['action'] = pods_v( 'action', 'get', 'add' );
739 }
740
741 $pod->ui();
742 }
743
744 /**
745 * Create PodsUI content for the settings administration pages
746 */
747 public function admin_content_settings() {
748
749 // @codingStandardsIgnoreLine
750 $pod_name = str_replace( 'pods-settings-', '', $_GET['page'] );
751
752 $pod = pods_get_instance( $pod_name );
753
754 if ( 'custom' !== pods_v( 'ui_style', $pod->pod_data['options'], 'settings', true ) ) {
755 $actions_disabled = array(
756 'manage' => 'manage',
757 'add' => 'add',
758 'delete' => 'delete',
759 'duplicate' => 'duplicate',
760 'view' => 'view',
761 'export' => 'export',
762 );
763
764 // @codingStandardsIgnoreLine
765 $_GET['action'] = 'edit';
766
767 $page_title = pods_v( 'label', $pod->pod_data, ucwords( str_replace( '_', ' ', $pod->pod_data['name'] ) ), true );
768 $page_title = apply_filters( 'pods_admin_menu_page_title', $page_title, $pod->pod_data );
769
770 $ui = array(
771 'pod' => $pod,
772 'fields' => array(
773 'edit' => $pod->pod_data->get_fields(),
774 ),
775 'header' => array(
776 'edit' => $page_title,
777 ),
778 'label' => array(
779 'edit' => __( 'Save Changes', 'pods' ),
780 ),
781 'style' => pods_v( 'ui_style', $pod->pod_data['options'], 'settings', true ),
782 'icon' => pods_evaluate_tags( pods_v( 'menu_icon', $pod->pod_data['options'] ), true ),
783 'actions_disabled' => $actions_disabled,
784 );
785
786 $pod_pod_name = $pod->pod;
787
788 $ui = apply_filters( "pods_admin_ui_{$pod_pod_name}", apply_filters( 'pods_admin_ui', $ui, $pod->pod, $pod ), $pod->pod, $pod );
789
790 // Force disabled actions, do not pass go, do not collect $two_hundred
791 $ui['actions_disabled'] = $actions_disabled;
792
793 pods_ui( $ui );
794 } else {
795 $pod_pod_name = $pod->pod;
796 do_action( 'pods_admin_ui_custom', $pod );
797 do_action( "pods_admin_ui_custom_{$pod_pod_name}", $pod );
798 }//end if
799 }
800
801 /**
802 * Add media button for Pods shortcode
803 *
804 * @param string $context Media button context.
805 *
806 * @return string
807 */
808 public function media_button( $context = null ) {
809 if ( ! empty( $_GET['action'] ) && 'elementor' === $_GET['action'] ) {
810 return '';
811 }
812
813 // If shortcodes are disabled don't show the button
814 if ( defined( 'PODS_DISABLE_SHORTCODE' ) && PODS_DISABLE_SHORTCODE ) {
815 return '';
816 }
817
818 /**
819 * Filter to remove Pods shortcode button from the post editor.
820 *
821 * @param bool $show_button Set to false to block the shortcode button from appearing.
822 * @param string $context Media button context.
823 *
824 * @since 2.3.19
825 */
826 if ( ! apply_filters( 'pods_admin_media_button', true, $context ) ) {
827 return '';
828 }
829
830 $current_page = basename( $_SERVER['PHP_SELF'] );
831 $current_page = explode( '?', $current_page );
832 $current_page = explode( '#', $current_page[0] );
833 $current_page = $current_page[0];
834
835 // Only show the button on post type pages
836 if ( ! in_array(
837 $current_page, array(
838 'post-new.php',
839 'post.php',
840 ), true
841 ) ) {
842 return '';
843 }
844
845 add_action( 'admin_footer', array( $this, 'mce_popup' ) );
846
847 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>';
848 }
849
850 /**
851 * Enqueue assets for Media Library Popup
852 */
853 public function register_media_assets() {
854
855 if ( 'pods_media_attachment' === pods_v( 'inlineId' ) ) {
856 wp_enqueue_style( 'pods-styles' );
857 }
858 }
859
860 /**
861 * Output Pods shortcode popup window
862 */
863 public function mce_popup() {
864
865 pods_view( PODS_DIR . 'ui/admin/shortcode.php', compact( array_keys( get_defined_vars() ) ) );
866 }
867
868 /**
869 * Handle main Pods Setup area for managing Pods and Fields
870 */
871 public function admin_setup() {
872 $api = pods_api();
873
874 $pods = $api->load_pods( array( 'fields' => false ) );
875
876 $view = pods_v( 'view', 'get', 'all', true );
877
878 // @codingStandardsIgnoreLine
879 if ( empty( $pods ) && ! isset( $_GET['action'] ) ) {
880 // @codingStandardsIgnoreLine
881 $_GET['action'] = 'add';
882 }
883
884 if ( 'pods' === $_GET['page'] && empty( $pods ) ) {
885 pods_message( __( 'You do not have any Pods set up yet. You can set up your very first Pod below.', 'pods ' ) );
886 }
887
888 // @codingStandardsIgnoreLine
889 if ( 'pods-add-new' === $_GET['page'] || empty( $pods ) ) {
890 // @codingStandardsIgnoreLine
891 if ( isset( $_GET['action'] ) && 'add' !== $_GET['action'] ) {
892 pods_redirect(
893 pods_query_arg(
894 array(
895 'page' => 'pods',
896 // @codingStandardsIgnoreLine
897 'action' => $_GET['action'],
898 )
899 )
900 );
901 } else {
902 // @codingStandardsIgnoreLine
903 $_GET['action'] = 'add';
904 }
905 // @codingStandardsIgnoreLine
906 } elseif ( isset( $_GET['action'] ) && 'add' === $_GET['action'] ) {
907 pods_redirect(
908 pods_query_arg(
909 array(
910 'page' => 'pods-add-new',
911 'action' => '',
912 'id' => '',
913 'do' => '',
914 '_wpnonce' => '',
915 )
916 )
917 );
918 }//end if
919
920 $pod_types = $api->get_pod_types();
921 $storage_types = $api->get_storage_types();
922
923 $row = false;
924
925 $pod_types_found = [];
926 $sources_found = [];
927 $source_types = [];
928
929 $include_row_counts = filter_var( pods_v( 'pods_include_row_counts' ), FILTER_VALIDATE_BOOLEAN );
930 $include_row_counts_refresh = filter_var( pods_v( 'pods_include_row_counts_refresh' ), FILTER_VALIDATE_BOOLEAN );
931
932 $fields = [
933 'label' => [
934 'label' => __( 'Label', 'pods' ),
935 ],
936 'name' => [
937 'label' => __( 'Name', 'pods' ),
938 ],
939 'type' => [
940 'label' => __( 'Type', 'pods' ),
941 ],
942 'source' => [
943 'label' => __( 'Source', 'pods' ),
944 'width' => '10%',
945 'type' => 'raw',
946 ],
947 'storage' => [
948 'label' => __( 'Storage Type', 'pods' ),
949 'width' => '10%',
950 ],
951 'group_count' => [
952 'label' => __( 'Groups', 'pods' ),
953 'width' => '8%',
954 ],
955 'field_count' => [
956 'label' => __( 'Fields', 'pods' ),
957 'width' => '8%',
958 ],
959 ];
960
961 if ( $include_row_counts ) {
962 $fields['row_count'] = [
963 'label' => __( 'Data Rows', 'pods' ),
964 'width' => '8%',
965 ];
966
967 $fields['row_meta_count'] = [
968 'label' => __( 'Meta Rows', 'pods' ),
969 'width' => '8%',
970 ];
971
972 $fields['podsrel_count'] = [
973 // translators: "PodsRel" references the name of the Pods relationships table in the database.
974 'label' => __( 'PodsRel Rows', 'pods' ),
975 'width' => '10%',
976 ];
977 }
978
979 $total_groups = 0;
980 $total_fields = 0;
981 $total_rows = 0;
982 $total_row_meta = 0;
983 $total_podsrel_rows = 0;
984
985 /**
986 * Filters whether to extend internal Pods.
987 *
988 * @since 2.8.0
989 *
990 * @param bool $extend_internal Whether to extend internal Pods.
991 */
992 $extend_internal = apply_filters( 'pods_admin_setup_extend_pods_internal', false );
993
994 $pod_list = array();
995
996 $is_tableless = pods_tableless();
997
998 $has_source = false;
999 $has_storage_type = false;
1000
1001 foreach ( $pods as $k => $pod ) {
1002 $pod_type = $pod['type'];
1003 $pod_type_label = null;
1004 $pod_storage = $pod['storage'];
1005
1006 if ( empty( $pod_type ) || ! is_string( $pod_type ) ) {
1007 $pod_type = 'post_type';
1008 }
1009
1010 if ( empty( $pod_storage ) || ! is_string( $pod_storage ) ) {
1011 $pod_storage = 'meta';
1012 }
1013
1014 $show_meta_count = 'meta' === $pod_storage || in_array( $pod['type'], [ 'post_type', 'taxonomy', 'user', 'comment' ], true );
1015
1016 if ( ! empty( $pod['internal'] ) ) {
1017 // Don't show internal if we aren't extending them.
1018 if ( ! $extend_internal ) {
1019 continue;
1020 }
1021
1022 $pod_type = 'internal';
1023 $pod_storage = 'meta';
1024 }
1025
1026 if ( 'settings' === $pod_type ) {
1027 $pod_storage = 'option';
1028 }
1029
1030 if ( 'meta' !== $pod_storage ) {
1031 $has_storage_type = true;
1032 }
1033
1034 if ( isset( $pod_types[ $pod_type ] ) ) {
1035 $pod_type_label = $pod_types[ $pod_type ];
1036 }
1037
1038 $pod_real_type = $pod_type;
1039
1040 $storage_type_label = ucwords( $pod_storage );
1041
1042 if ( isset( $storage_types[ $pod_storage ] ) ) {
1043 $storage_type_label = $storage_types[ $pod_storage ];
1044 }
1045
1046 if ( null !== $pod_type_label ) {
1047 if ( ! $pod->is_extended() && in_array( $pod_type, array(
1048 'post_type',
1049 'taxonomy',
1050 ), true ) ) {
1051 if ( 'post_type' === $pod_type ) {
1052 $pod_type = 'cpt';
1053 } else {
1054 $pod_type = 'ct';
1055 }
1056
1057 if ( isset( $pod_types[ $pod_type ] ) ) {
1058 $pod_type_label = $pod_types[ $pod_type ];
1059 }
1060 }
1061
1062 if ( ! isset( $pod_types_found[ $pod_type ] ) ) {
1063 $pod_types_found[ $pod_type ] = 1;
1064 } else {
1065 $pod_types_found[ $pod_type ] ++;
1066 }
1067
1068 if ( 'all' !== $view && $view !== $pod_type ) {
1069 continue;
1070 }
1071
1072 $pod_real_type = $pod_type;
1073 $pod_type = $pod_type_label;
1074 } elseif ( 'all' !== $view ) {
1075 continue;
1076 }//end if
1077
1078 $group_count = 0;
1079 $field_count = 0;
1080
1081 if ( ! pods_is_types_only( false, $pod->get_name() ) ) {
1082 $group_count = $pod->count_groups();
1083 $field_count = $pod->count_fields();
1084 }
1085
1086 if ( $include_row_counts ) {
1087 $count_transient_prefix = 'pods_admin_' . $pod['type'] . '_' . $pod['name'] . '_';
1088
1089 $row_counts = [
1090 'row_count' => false,
1091 'row_meta_count' => false,
1092 'podsrel_count' => false,
1093 ];
1094
1095 if ( ! $include_row_counts_refresh ) {
1096 $row_counts['row_count'] = pods_transient_get( $count_transient_prefix . 'row_count' );
1097 $row_counts['row_meta_count'] = pods_transient_get( $count_transient_prefix . 'row_meta_count' );
1098 $row_counts['podsrel_count'] = pods_transient_get( $count_transient_prefix . 'podsrel_count' );
1099 }
1100
1101 if ( ! is_numeric( $row_counts['row_count'] ) ) {
1102 $row_counts['row_count'] = $pod->count_rows();
1103
1104 pods_transient_set( $count_transient_prefix . 'row_count', $row_counts['row_count'], HOUR_IN_SECONDS * 3 );
1105 }
1106
1107 if ( $show_meta_count && ! is_numeric( $row_counts['row_meta_count'] ) ) {
1108 $row_counts['row_meta_count'] = $pod->count_row_meta();
1109
1110 pods_transient_set( $count_transient_prefix . 'row_meta_count', $row_counts['row_meta_count'], HOUR_IN_SECONDS * 3 );
1111 }
1112
1113 if ( ! $is_tableless && ! is_numeric( $row_counts['podsrel_count'] ) ) {
1114 $row_counts['podsrel_count'] = $pod->count_podsrel_rows();
1115
1116 pods_transient_set( $count_transient_prefix . 'podsrel_count', $row_counts['podsrel_count'], HOUR_IN_SECONDS * 3 );
1117 }
1118 }
1119
1120 $object_storage_type = $pod->get_object_storage_type();
1121 $source = $pod->get_object_storage_type_label();
1122
1123 if ( $source ) {
1124 $source_types[ $object_storage_type ] = $source;
1125
1126 if ( ! isset( $sources_found[ $object_storage_type ] ) ) {
1127 $sources_found[ $object_storage_type ] = 1;
1128 } else {
1129 $sources_found[ $object_storage_type ] ++;
1130 }
1131 }
1132
1133 $source = esc_html( $source );
1134
1135 if ( 'post_type' !== $object_storage_type ) {
1136 $has_source = true;
1137
1138 if ( 'file' === $object_storage_type ) {
1139 $file_source = $pod->get_arg( '_pods_file_source' );
1140
1141 if ( $file_source ) {
1142 if ( 0 === strpos( $file_source, ABSPATH ) ) {
1143 $file_source = str_replace( ABSPATH, '', $file_source );
1144 }
1145
1146 ob_start();
1147
1148 pods_help(
1149 sprintf(
1150 '<strong>%s:</strong> %s',
1151 esc_html__( 'File source', 'pods' ),
1152 esc_html( $file_source )
1153 ),
1154 null,
1155 '.pods-admin-container'
1156 );
1157
1158 $source .= ' ' . ob_get_clean();
1159 }
1160 } elseif ( 'collection' === $object_storage_type ) {
1161 $code_source = $pod->get_arg( '_pods_code_source' );
1162
1163 if ( $code_source ) {
1164 if ( 0 === strpos( $code_source, ABSPATH ) ) {
1165 $code_source = str_replace( ABSPATH, '', $code_source );
1166 }
1167
1168 ob_start();
1169
1170 pods_help(
1171 sprintf(
1172 '<strong>%s:</strong> %s',
1173 esc_html__( 'Code source', 'pods' ),
1174 esc_html( $code_source )
1175 ),
1176 null,
1177 '.pods-admin-container'
1178 );
1179
1180 $source .= ' ' . ob_get_clean();
1181 }
1182 }
1183 }
1184
1185 $pod = [
1186 'id' => $pod['id'],
1187 'label' => $pod['label'],
1188 'name' => $pod['name'],
1189 'object' => $pod['object'],
1190 'type' => $pod_type,
1191 'real_type' => $pod_real_type,
1192 'storage' => $storage_type_label,
1193 'source' => $source,
1194 'pod_object' => $pod,
1195 ];
1196
1197 if ( ! pods_is_types_only( false, $pod['name'] ) ) {
1198 $pod['group_count'] = number_format_i18n( $group_count );
1199 $pod['field_count'] = number_format_i18n( $field_count );
1200
1201 $total_groups += $group_count;
1202 $total_fields += $field_count;
1203 }
1204
1205 if ( $include_row_counts ) {
1206 $pod['row_count'] = number_format_i18n( $row_counts['row_count'] );
1207
1208 $total_rows += $row_counts['row_count'];
1209
1210 $pod['row_meta_count'] = 'n/a';
1211 $pod['podsrel_count'] = 'n/a';
1212
1213 if ( $show_meta_count ) {
1214 $pod['row_meta_count'] = number_format_i18n( $row_counts['row_meta_count'] );
1215
1216 $total_row_meta += $row_counts['row_meta_count'];
1217 }
1218
1219 if ( ! $is_tableless ) {
1220 $pod['podsrel_count'] = number_format_i18n( $row_counts['podsrel_count'] );
1221
1222 $total_podsrel_rows += $row_counts['podsrel_count'];
1223 }
1224 }
1225
1226 // @codingStandardsIgnoreLine
1227 if ( 'manage' !== pods_v( 'action' ) ) {
1228 $found_id = (int) pods_v( 'id' );
1229 $found_name = pods_v( 'name' );
1230
1231 if (
1232 (
1233 $found_id
1234 && $pod['id'] === $found_id
1235 )
1236 || (
1237 $found_name
1238 && $pod['name'] === $found_name
1239 )
1240 ) {
1241 $row = $pod;
1242 }
1243 }
1244
1245 $pod_list[] = $pod;
1246 }//end foreach
1247
1248 if ( ! $has_storage_type ) {
1249 unset( $fields['storage'] );
1250 }
1251
1252 if ( ! $has_source ) {
1253 unset( $fields['source'] );
1254 }
1255
1256 if (
1257 (
1258 0 === $total_groups
1259 && 0 === $total_fields
1260 )
1261 || pods_is_types_only()
1262 ) {
1263 unset( $fields['group_count'], $fields['field_count'] );
1264 }
1265
1266 if ( false === $row && 0 < pods_v( 'id' ) && 'delete' !== pods_v( 'action' ) ) {
1267 pods_message( 'Pod not found', 'error' );
1268
1269 // @codingStandardsIgnoreLine
1270 unset( $_GET['id'], $_GET['action'] );
1271 }
1272
1273 $total_pods = count( $pod_list );
1274
1275 $extra_total_text = '';
1276
1277 if ( ! pods_is_types_only() ) {
1278 $extra_total_text .= sprintf(
1279 ', %1$s %2$s, %3$s %4$s',
1280 number_format_i18n( $total_groups ),
1281 _n( 'group', 'groups', $total_groups, 'pods' ),
1282 number_format_i18n( $total_fields ),
1283 _n( 'field', 'fields', $total_fields, 'pods' )
1284 );
1285 }
1286
1287 if ( $include_row_counts ) {
1288 $extra_total_text .= sprintf(
1289 ', %1$s %2$s, %3$s %4$s, %5$s %6$s',
1290 number_format_i18n( $total_rows ),
1291 _n( 'data row', 'data rows', $total_rows, 'pods' ),
1292 number_format_i18n( $total_row_meta ),
1293 _n( 'meta row', 'meta rows', $total_row_meta, 'pods' ),
1294 number_format_i18n( $total_podsrel_rows ),
1295 // translators: "podsrel" references the name of the Pods relationships table in the database.
1296 _n( 'podsrel row', 'podsrel rows', $total_podsrel_rows, 'pods' )
1297 );
1298 }
1299
1300 $pod_list = wp_list_sort( $pod_list, 'label', 'ASC', true );
1301
1302 $ui = [
1303 'data' => $pod_list,
1304 'row' => $row,
1305 'total' => $total_pods,
1306 'total_found' => $total_pods,
1307 'items' => 'Pods',
1308 'item' => 'Pod',
1309 'fields' => [
1310 'manage' => $fields,
1311 ],
1312 'sql' => [
1313 'field_id' => 'id',
1314 'field_index' => 'label',
1315 ],
1316 'actions_disabled' => [ 'view', 'export', 'delete', 'duplicate' ],
1317 'actions_custom' => [
1318 'add' => [ $this, 'admin_setup_add' ],
1319 'edit' => [
1320 'callback' => [ $this, 'admin_setup_edit' ],
1321 'restrict_callback' => [ $this, 'admin_setup_edit_restrict' ],
1322 ],
1323 'duplicate_pod' => [
1324 'label' => __( 'Duplicate', 'pods' ),
1325 'callback' => [ $this, 'admin_setup_duplicate' ],
1326 'restrict_callback' => [ $this, 'admin_setup_duplicate_restrict' ],
1327 'nonce' => true,
1328 ],
1329 'delete_pod' => [
1330 'label' => __( 'Delete', 'pods' ),
1331 'confirm' => __( 'Are you sure you want to delete this Pod?', 'pods' )
1332 . "\n\n"
1333 . __( 'All of the content and items will remain in the database.', 'pods' )
1334 . "\n\n"
1335 . __( 'You may want to go to Pods Admin > Settings > Cleanup & Reset > "Delete all content for a Pod" first.', 'pods' ),
1336 'callback' => [ $this, 'admin_setup_delete' ],
1337 'restrict_callback' => [ $this, 'admin_setup_delete_restrict' ],
1338 'nonce' => true,
1339 'span_class' => 'delete',
1340 ],
1341 ],
1342 'action_links' => [
1343 'add' => pods_query_arg( [
1344 'page' => 'pods-add-new',
1345 'action' => '',
1346 'id' => '',
1347 'do' => '',
1348 '_wpnonce' => '',
1349 ] ),
1350 'duplicate_pod' => pods_query_arg( [
1351 'action' => 'duplicate_pod',
1352 'id' => '{@id}',
1353 'name' => '{@name}',
1354 ] ),
1355 ],
1356 'search' => false,
1357 'searchable' => false,
1358 'sortable' => true,
1359 'pagination' => false,
1360 'extra' => [
1361 'total' => $extra_total_text,
1362 ],
1363 ];
1364
1365 if ( 1 < count( $pod_types_found ) ) {
1366 $ui['views'] = [ 'all' => __( 'All', 'pods' ) . ' (' . $total_pods . ')' ];
1367 $ui['view'] = $view;
1368 $ui['heading'] = [ 'views' => __( 'Type', 'pods' ) ];
1369 $ui['filters_enhanced'] = true;
1370
1371 foreach ( $pod_types_found as $pod_type => $number_found ) {
1372 $ui['views'][ $pod_type ] = sprintf(
1373 '%1$s (%2$s)',
1374 $pod_types[ $pod_type ],
1375 number_format_i18n( $number_found )
1376 );
1377 }
1378
1379 if ( $has_source && 1 < count( $sources_found ) ) {
1380 foreach ( $sources_found as $source_type => $number_found ) {
1381 $ui['views'][ 'source/' . $source_type ] = sprintf(
1382 '%1$s: %2$s (%3$s)',
1383 __( 'Source', 'pods' ),
1384 $source_types[ $source_type ],
1385 $number_found
1386 );
1387 }
1388 }
1389 }
1390
1391 // Add our custom callouts.
1392 $this->handle_callouts_updates();
1393
1394 add_filter( 'pods_ui_manage_custom_container_classes', array( $this, 'admin_manage_container_class' ) );
1395 add_action( 'pods_ui_manage_after_container', array( $this, 'admin_manage_callouts' ) );
1396
1397 pods_ui( $ui );
1398 }
1399
1400 /**
1401 * Get list of callouts to show.
1402 *
1403 * @since 2.7.17
1404 *
1405 * @return array List of callouts.
1406 */
1407 public function get_callouts() {
1408 // Demo mode always bypasses callouts.
1409 if ( pods_is_demo() ) {
1410 return [];
1411 }
1412
1413 $force_callouts = false;
1414
1415 $page = pods_v( 'page' );
1416
1417 if ( in_array( $page, array( 'pods-settings', 'pods-help' ), true ) ) {
1418 $force_callouts = true;
1419 }
1420
1421 $callouts = get_option( 'pods_callouts' );
1422
1423 if ( ! $callouts ) {
1424 $callouts = array(
1425 'friends_2022_30' => 1,
1426 );
1427 }
1428
1429 // Handle Friends of Pods callout logic.
1430 $callouts['friends_2022_30'] = ! isset( $callouts['friends_2022_30'] ) || $callouts['friends_2022_30'] || $force_callouts ? 1 : 0;
1431
1432 /**
1433 * Allow hooking into whether or not the specific callouts should show.
1434 *
1435 * @since 2.7.17
1436 *
1437 * @param array List of callouts to enable.
1438 */
1439 $callouts = apply_filters( 'pods_admin_callouts', $callouts );
1440
1441 return $callouts;
1442 }
1443
1444 /**
1445 * Handle callouts update logic.
1446 *
1447 * @since 2.7.17
1448 */
1449 public function handle_callouts_updates() {
1450 // Don't show callouts right now until Pods 3.0.
1451 return;
1452
1453 $callouts = get_option( 'pods_callouts' );
1454
1455 if ( ! $callouts ) {
1456 $callouts = array();
1457 }
1458
1459 $callout_dismiss = pods_v( 'pods_callout_dismiss' );
1460
1461 // Demo mode will auto-update the option for future loads.
1462 $is_demo = pods_is_demo();
1463
1464 // Disable Friends of Pods callout.
1465 if ( $is_demo || 'friends_2022_30' === $callout_dismiss ) {
1466 $callouts['friends_2022_30'] = 0;
1467
1468 update_option( 'pods_callouts', $callouts );
1469 } elseif ( 'reset' === $callout_dismiss ) {
1470 $callouts = array();
1471
1472 update_option( 'pods_callouts', $callouts );
1473 }
1474 }
1475
1476 /**
1477 * Add class to container if we have callouts to show.
1478 *
1479 * @since 2.7.17
1480 *
1481 * @param array $classes List of classes to use.
1482 *
1483 * @return array List of classes to use.
1484 */
1485 public function admin_manage_container_class( $classes ) {
1486 $callouts = $this->get_callouts();
1487
1488 // Only get enabled callouts.
1489 $callouts = array_filter( $callouts );
1490
1491 if ( ! empty( $callouts ) ) {
1492 $classes[] = 'pods-admin--flex';
1493 }
1494
1495 return $classes;
1496 }
1497
1498 /**
1499 * Add callouts to let admins know about certain things.
1500 *
1501 * @since 2.7.17
1502 */
1503 public function admin_manage_callouts() {
1504 $force_callouts = false;
1505
1506 $page = pods_v( 'page' );
1507
1508 if ( in_array( $page, array( 'pods-settings', 'pods-help' ), true ) ) {
1509 $force_callouts = true;
1510 }
1511
1512 $callouts = $this->get_callouts();
1513
1514 if ( ! empty( $callouts['friends_2022_30'] ) ) {
1515 pods_view( PODS_DIR . 'ui/admin/callouts/friends_2022_30.php', compact( array_keys( get_defined_vars() ) ) );
1516 }
1517 }
1518
1519 /**
1520 * Get the add page of an object
1521 *
1522 * @param PodsUI $obj PodsUI object.
1523 */
1524 public function admin_setup_add( $obj ) {
1525 pods_view( PODS_DIR . 'ui/admin/setup-add.php', compact( array_keys( get_defined_vars() ) ) );
1526 }
1527
1528 /**
1529 * Get the edit page of an object
1530 *
1531 * @param boolean $duplicate Whether the screen is for duplicating.
1532 * @param PodsUI $obj PodsUI object.
1533 */
1534 public function admin_setup_edit( $duplicate, $obj ) {
1535 $api = pods_api();
1536
1537 $pod = $obj->row['pod_object'];
1538
1539 if ( ! $pod instanceof Pod ) {
1540 $obj->id = null;
1541 $obj->row = [];
1542 $obj->action = 'manage';
1543
1544 $obj->error( __( 'Invalid Pod configuration detected.', 'pods' ) );
1545 $obj->manage();
1546
1547 return null;
1548 }
1549
1550 if ( 'post_type' !== $pod->get_object_storage_type() ) {
1551 $obj->id = null;
1552 $obj->row = [];
1553 $obj->action = 'manage';
1554
1555 // translators: %s: The pod label.
1556 $obj->error( sprintf( __( 'Unable to edit the "%s" Pod configuration.', 'pods' ), $pod->get_label() ) );
1557 $obj->manage();
1558
1559 return null;
1560 }
1561
1562 $original_field_count = 0;
1563
1564 foreach ( $obj->data as $row ) {
1565 if ( (int) $row['id'] === (int) $obj->id ) {
1566 if ( ! isset( $row['field_count'] ) ) {
1567 $row['field_count'] = 0;
1568 }
1569
1570 $original_field_count = (int) $row['field_count'];
1571
1572 break;
1573 }
1574 }
1575
1576 $find_orphan_fields = (
1577 1 === (int) pods_v( 'pods_debug_find_orphan_fields', 'get', 0 )
1578 && pods_is_admin( array( 'pods' ) )
1579 );
1580
1581 $migrated = false;
1582
1583 if ( $find_orphan_fields || 1 !== (int) $pod->get_arg( '_migrated_28' ) ) {
1584 $pod = $this->maybe_migrate_pod_fields_into_group( $pod );
1585
1586 $migrated = true;
1587
1588 // Maybe redirect the page to reload it fresh.
1589 if ( $find_orphan_fields ) {
1590 pods_redirect( pods_query_arg( [ 'pods_debug_find_orphan_fields' => null ] ) );
1591 die();
1592 }
1593
1594 // Check again in case the pod migrated wrong.
1595 if ( ! $pod instanceof Pod ) {
1596 $obj->id = null;
1597 $obj->row = [];
1598 $obj->action = 'manage';
1599
1600 $obj->error( __( 'Invalid Pod configuration detected.', 'pods' ) );
1601 $obj->manage();
1602
1603 return null;
1604 }
1605 }
1606
1607 $current_pod = $pod->export( [
1608 'include_groups' => true,
1609 'include_group_fields' => true,
1610 'include_fields' => false,
1611 ] );
1612
1613 $group_field_count = wp_list_pluck( $current_pod['groups'], 'fields' );
1614 $group_field_count = array_map( 'count', $group_field_count );
1615 $group_field_count = array_sum( $group_field_count );
1616
1617 // Detect if there may be a migration/repair needed.
1618 if ( $original_field_count !== $group_field_count ) {
1619 if ( ! $migrated ) {
1620 $pod = $this->maybe_migrate_pod_fields_into_group( $pod );
1621
1622 // Check again in case the pod migrated wrong.
1623 if ( ! $pod instanceof Pod ) {
1624 $obj->id = null;
1625 $obj->row = [];
1626 $obj->action = 'manage';
1627
1628 $obj->error( __( 'Invalid Pod configuration detected.', 'pods' ) );
1629 $obj->manage();
1630
1631 return null;
1632 }
1633
1634 $current_pod = $pod->export( [
1635 'include_groups' => true,
1636 'include_group_fields' => true,
1637 'include_fields' => false,
1638 ] );
1639 } else {
1640 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' ) );
1641 }
1642 }
1643
1644 $config = [
1645 'currentPod' => $current_pod,
1646 'global' => $this->get_global_config( $pod ),
1647 'fieldTypes' => PodsForm::field_types(),
1648 'relatedObjects' => $this->get_field_related_objects(),
1649 'podTypes' => $api->get_pod_types(),
1650 'storageTypes' => $api->get_storage_types(),
1651 // @todo SKC: Remove these below and replace any references to podsDFVConfig
1652 'wp_locale' => $GLOBALS['wp_locale'],
1653 'userLocale' => str_replace( '_', '-', get_user_locale() ),
1654 'currencies' => PodsField_Currency::data_currencies(),
1655 'datetime' => [
1656 'start_of_week' => (int) get_option( 'start_of_week', 0 ),
1657 'gmt_offset' => (int) get_option( 'gmt_offset', 0 ),
1658 ],
1659 ];
1660
1661 $config['currentPod']['podType'] = [
1662 'name' => $config['currentPod']['type'],
1663 ];
1664
1665 $config['currentPod']['storageType'] = [
1666 'name' => $config['currentPod']['storage'],
1667 ];
1668
1669 if ( ! empty( $config['currentPod']['internal'] ) ) {
1670 $config['currentPod']['podType']['name'] = 'internal';
1671 } elseif ( ! $pod->is_extended() ) {
1672 if ( 'post_type' === $config['currentPod']['type'] ) {
1673 $config['currentPod']['podType']['name'] = 'cpt';
1674 } elseif ( 'taxonomy' === $config['currentPod']['type'] ) {
1675 $config['currentPod']['podType']['name'] = 'ct';
1676 }
1677 }
1678
1679 $config['currentPod']['podType']['label'] = ucwords( str_replace( '_', ' ', $config['currentPod']['podType']['name'] ) );
1680
1681 if ( ! empty( $config['podTypes'][ $config['currentPod']['podType']['name'] ] ) ) {
1682 $config['currentPod']['podType']['label'] = $config['podTypes'][ $config['currentPod']['podType']['name'] ];
1683 }
1684
1685 if ( 'settings' === $config['currentPod']['type'] ) {
1686 $config['currentPod']['storageType']['name'] = 'option';
1687 }
1688
1689 $config['currentPod']['storageType']['label'] = ucwords( $config['currentPod']['storageType']['name'] );
1690
1691 if ( ! empty( $config['storageTypes'][ $config['currentPod']['storageType']['name'] ] ) ) {
1692 $config['currentPod']['storageType']['label'] = $config['storageTypes'][ $config['currentPod']['storageType']['name'] ];
1693 }
1694
1695 /**
1696 * Allow filtering the admin config data.
1697 *
1698 * @since 2.8.0
1699 *
1700 * @param array $config The admin config data.
1701 * @param Pod $pod The pod object.
1702 * @param PodsUI $obj The PodsUI object.
1703 */
1704 $config = apply_filters( 'pods_admin_setup_edit_pod_config', $config, $pod, $obj );
1705
1706 wp_localize_script( 'pods-dfv', 'podsAdminConfig', $config );
1707
1708 pods_view( PODS_DIR . 'ui/admin/setup-edit.php', compact( array_keys( get_defined_vars() ) ) );
1709 }
1710
1711 /**
1712 * Restrict Edit action.
1713 *
1714 * @param bool $restricted Whether action is restricted.
1715 * @param array $restrict Restriction array.
1716 * @param string $action Current action.
1717 * @param array $row Item data row.
1718 * @param PodsUI $obj PodsUI object.
1719 *
1720 * @since 2.3.10
1721 *
1722 * @return bool
1723 */
1724 public function admin_setup_edit_restrict( $restricted, $restrict, $action, $row, $obj ) {
1725 if ( __( 'DB', 'pods' ) !== $row['source'] ) {
1726 $restricted = true;
1727 }
1728
1729 return $restricted;
1730 }
1731
1732 /**
1733 * Get list of field related objects.
1734 *
1735 * @since 2.8.0
1736 *
1737 * @return array List of field related objects.
1738 */
1739 protected function get_field_related_objects() {
1740 $related_object_groups = PodsForm::field_method( 'pick', 'related_objects', true );
1741
1742 $related_objects = [];
1743
1744 foreach ( $related_object_groups as $group => $group_objects ) {
1745 foreach ( $group_objects as $name => $label ) {
1746 $related_objects[ $name ] = [
1747 'name' => $name,
1748 'label' => $label,
1749 ];
1750 }
1751 }
1752
1753 return $related_objects;
1754 }
1755
1756 /**
1757 * Maybe migrate pod fields into a group (if they have no group).
1758 *
1759 * @since 2.8.0
1760 *
1761 * @param Pod $pod The pod object.
1762 *
1763 * @return Pod The pod object.
1764 */
1765 public function maybe_migrate_pod_fields_into_group( $pod ) {
1766 $tool = pods_container( Repair::class );
1767
1768 $results = $tool->repair_groups_and_fields_for_pod( $pod, 'upgrade' );
1769
1770 if ( '' !== $results['message_html'] ) {
1771 if ( 'pods' === pods_v( 'page' ) && 'edit' === pods_v( 'action' ) && 'create' === pods_v( 'do' ) ) {
1772 // Refresh the page if we just added the Pod.
1773 pods_redirect();
1774 } else {
1775 pods_message( $results['message_html'] );
1776 }
1777 }
1778
1779 return $results['upgraded_pod'];
1780 }
1781
1782 /**
1783 * Get the global config for Pods admin.
1784 *
1785 * @param null|\Pods\Whatsit $current_pod
1786 *
1787 * @return array Global config array.
1788 *@since 2.8.0
1789 *
1790 */
1791 public function get_global_config( $current_pod = null ) {
1792 $config_pod = pods_container( Config_Pod::class );
1793 $config_group = pods_container( Config_Group::class );
1794 $config_field = pods_container( Config_Field::class );
1795
1796 // Pod: Backwards compatible configs and hooks.
1797 $pod_tabs = $config_pod->get_tabs( $current_pod);
1798 $pod_tab_options = $config_pod->get_fields( $current_pod, $pod_tabs );
1799
1800 $this->backcompat_convert_tabs_to_groups( $pod_tabs, $pod_tab_options, 'pod/_pods_pod' );
1801
1802 // If not types-only mode, handle groups/fields configs.
1803 if ( ! pods_is_types_only( false, $current_pod->get_name() ) ) {
1804 // Group: Backwards compatible methods and hooks.
1805 $group_tabs = $config_group->get_tabs( $current_pod);
1806 $group_tab_options = $config_group->get_fields( $current_pod, $group_tabs );
1807
1808 $this->backcompat_convert_tabs_to_groups( $group_tabs, $group_tab_options, 'pod/_pods_group' );
1809
1810 // Field: Backwards compatible methods and hooks.
1811 $field_tabs = $config_field->get_tabs( $current_pod);
1812 $field_tab_options = $config_field->get_fields( $current_pod, $field_tabs );
1813
1814 $this->backcompat_convert_tabs_to_groups( $field_tabs, $field_tab_options, 'pod/_pods_field' );
1815 }
1816
1817 $object_collection = Pods\Whatsit\Store::get_instance();
1818
1819 /** @var Pods\Whatsit\Storage $storage */
1820 $storage = $object_collection->get_storage_object( 'collection' );
1821
1822 // Get objects from storage.
1823 $pod_object = $storage->get( [
1824 'object_type' => 'pod',
1825 'name' => '_pods_pod',
1826 ] );
1827
1828 $group_object = $storage->get( [
1829 'object_type' => 'pod',
1830 'name' => '_pods_group',
1831 ] );
1832
1833 $field_object = $storage->get( [
1834 'object_type' => 'pod',
1835 'name' => '_pods_field',
1836 ] );
1837
1838 $global_config = [
1839 'showFields' => ! pods_is_types_only( false, $current_pod->get_name() ),
1840 'pod' => $pod_object->export( [
1841 'include_groups' => true,
1842 'include_group_fields' => true,
1843 'include_fields' => false,
1844 'include_field_data' => true,
1845 ] ),
1846 'group' => $group_object->export( [
1847 'include_groups' => true,
1848 'include_group_fields' => true,
1849 'include_fields' => false,
1850 'include_field_data' => true,
1851 ] ),
1852 'field' => $field_object->export( [
1853 'include_groups' => true,
1854 'include_group_fields' => true,
1855 'include_fields' => false,
1856 'include_field_data' => true,
1857 ] ),
1858 ];
1859
1860 /**
1861 * Allow hooking into the global config setup for a Pod.
1862 *
1863 * @param array $global_config The global config object.
1864 * @param null|\Pods\Whatsit $current_pod The Pod object.
1865 */
1866 $global_config = apply_filters( 'pods_admin_setup_global_config', $global_config, $current_pod );
1867
1868 return $global_config;
1869 }
1870
1871 /**
1872 * Convert the tabs and their options to groups/fields in the collection storage.
1873 *
1874 * @since 2.8.0
1875 *
1876 * @param array $tabs List of registered tabs.
1877 * @param array $options List of tab options.
1878 * @param string $parent The parent object to register to.
1879 *
1880 * @return array Global config array.
1881 */
1882 protected function backcompat_convert_tabs_to_groups( array $tabs, array $options, $parent ) {
1883 $object_collection = Pods\Whatsit\Store::get_instance();
1884
1885 /** @var Pods\Whatsit\Storage\Collection $storage */
1886 $storage = $object_collection->get_storage_object( 'collection' );
1887
1888 $groups = [];
1889 $fields = [];
1890
1891 foreach ( $tabs as $group_name => $group_label ) {
1892 if ( empty( $options[ $group_name ] ) ) {
1893 continue;
1894 }
1895
1896 if ( is_array( $group_label ) ) {
1897 $group_args = $group_label;
1898 } else {
1899 $group_args = [
1900 'name' => $group_name,
1901 'label' => $group_label,
1902 ];
1903 }
1904
1905 $group_args['parent'] = $parent;
1906
1907 $group = new \Pods\Whatsit\Group( $group_args );
1908
1909 $groups[] = $storage->add( $group );
1910
1911 $group_fields = $options[ $group_name ];
1912
1913 $sections = false;
1914
1915 foreach ( $group_fields as $field_name => $field_options ) {
1916 // Support sections.
1917 if ( ! isset( $field_options['label'] ) ) {
1918 $sections = true;
1919 }
1920
1921 break;
1922 }
1923
1924 $group_sections = $group_fields;
1925
1926 // Store the same whether it's a section or not.
1927 if ( ! $sections ) {
1928 $group_sections = [
1929 $group_fields,
1930 ];
1931 }
1932
1933 foreach ( $group_sections as $section_label => $section_fields ) {
1934 // Add section field (maybe).
1935 if ( ! is_int( $section_label ) ) {
1936 $field_args = [
1937 'name' => sanitize_title( $section_label ),
1938 'label' => $section_label,
1939 'type' => 'heading',
1940 'parent' => $parent,
1941 'group' => 'group/' . $parent . '/' . $group_name,
1942 ];
1943
1944 $field = new \Pods\Whatsit\Field( $field_args );
1945
1946 $fields[] = $storage->add( $field );
1947 }
1948
1949 if ( ! is_array( $section_fields ) ) {
1950 continue;
1951 }
1952
1953 // Add fields for section.
1954 foreach ( $section_fields as $field_name => $field_options ) {
1955 $boolean_group = [];
1956
1957 // Handle auto-formatting from shorthand.
1958 if ( ! empty( $field_options['boolean_group'] ) ) {
1959 $boolean_group = $field_options['boolean_group'];
1960
1961 foreach ( $boolean_group as $bgf_key => $boolean_group_field ) {
1962 // Make sure each field has a field name.
1963 if ( is_string( $bgf_key ) ) {
1964 $boolean_group[ $bgf_key ]['name'] = $bgf_key;
1965 }
1966 }
1967
1968 $boolean_group = array_values( $boolean_group );
1969
1970 $field_options['boolean_group'] = $boolean_group;
1971 }
1972
1973 if ( empty( $field_options['type'] ) ) {
1974 continue;
1975 }
1976
1977 // Set a unique field name for boolean group headings.
1978 if ( ! empty( $boolean_group ) ) {
1979 $field_options['name'] = $field_name . '_' . md5( json_encode( $boolean_group ) );
1980 }
1981
1982 $field = $this->backcompat_convert_tabs_to_groups_setup_field( [
1983 'field_name' => $field_name,
1984 'field_options' => $field_options,
1985 'parent' => $parent,
1986 'group_name' => $group_name,
1987 ] );
1988
1989 $fields[] = $storage->add( $field );
1990 }
1991 }
1992 }
1993
1994 return compact( 'groups', 'fields' );
1995 }
1996
1997 /**
1998 * Setup field for backwards compatibility tabs to groups layer.
1999 *
2000 * @since 2.8.0
2001 *
2002 * @param array $args {
2003 * The field arguments.
2004 *
2005 * @type string $field_name The field name.
2006 * @type array $field_options The field options.
2007 * @type string|int $parent The parent group.
2008 * @type string $group_name The group name.
2009 * }
2010 *
2011 * @return \Pods\Whatsit\Field The field object.
2012 */
2013 public function backcompat_convert_tabs_to_groups_setup_field( $args ) {
2014 $field_name = $args['field_name'];
2015 $field_options = $args['field_options'];
2016 $parent = $args['parent'];
2017 $group_name = $args['group_name'];
2018
2019 $field_args = $field_options;
2020
2021 if ( ! isset( $field_args['name'] ) ) {
2022 $field_args['name'] = $field_name;
2023 }
2024
2025 $field_args['parent'] = $parent;
2026 $field_args['group'] = 'group/' . $parent . '/' . $group_name;
2027
2028 $dfv_args = (object) [
2029 'id' => 0,
2030 'name' => $field_args['name'],
2031 'value' => '',
2032 'pod' => null,
2033 'type' => pods_v( 'type', $field_args ),
2034 'options' => array_merge( [
2035 'id' => 0,
2036 ], $field_args )
2037 ];
2038
2039 if ( ! empty( $dfv_args->type ) ) {
2040 $field_args = PodsForm::field_method( $dfv_args->type, 'build_dfv_field_options', $field_args, $dfv_args );
2041 }
2042
2043 return new \Pods\Whatsit\Field( $field_args );
2044 }
2045
2046 /**
2047 * Duplicate a pod
2048 *
2049 * @param PodsUI $obj PodsUI object.
2050 */
2051 public function admin_setup_duplicate( $obj ) {
2052 $new_id = pods_api()->duplicate_pod( array( 'name' => $obj->row['name'] ) );
2053
2054 if ( 0 < $new_id ) {
2055 pods_redirect(
2056 pods_query_arg(
2057 array(
2058 'action' => 'edit',
2059 'id' => $new_id,
2060 'do' => 'duplicate',
2061 'name' => null,
2062 )
2063 )
2064 );
2065
2066 return;
2067 }
2068
2069 $obj->error( __( 'An error occurred, the Pod was not duplicated.', 'pods' ) );
2070 }
2071
2072 /**
2073 * Restrict Duplicate action to custom types, not extended
2074 *
2075 * @param bool $restricted Whether action is restricted.
2076 * @param array $restrict Restriction array.
2077 * @param string $action Current action.
2078 * @param array $row Item data row.
2079 * @param PodsUI $obj PodsUI object.
2080 *
2081 * @since 2.3.10
2082 *
2083 * @return bool
2084 */
2085 public function admin_setup_duplicate_restrict( $restricted, $restrict, $action, $row, $obj ) {
2086 if ( in_array(
2087 $row['real_type'], array(
2088 'user',
2089 'media',
2090 'comment',
2091 ), true
2092 ) ) {
2093 $restricted = true;
2094 }
2095
2096 return $restricted;
2097 }
2098
2099 /**
2100 * Delete a pod
2101 *
2102 * @param PodsUI $obj PodsUI object.
2103 * @param int|string $id Item ID.
2104 *
2105 * @return mixed
2106 */
2107 public function admin_setup_delete( $obj, $id ) {
2108
2109 $pod = pods_api()->load_pod( array( 'id' => $id ), false );
2110
2111 if ( empty( $pod ) ) {
2112 return $obj->error( __( 'Pod not found.', 'pods' ) );
2113 }
2114
2115 pods_api()->delete_pod( array( 'id' => $id ) );
2116
2117 foreach ( $obj->data as $key => $data_pod ) {
2118 if ( (int) $id === (int) $data_pod['id'] ) {
2119 unset( $obj->data[ $key ] );
2120 }
2121 }
2122
2123 $obj->total = count( $obj->data );
2124 $obj->total_found = count( $obj->data );
2125
2126 $obj->message( __( 'Pod deleted successfully.', 'pods' ) );
2127
2128 $obj->manage();
2129 }
2130
2131 /**
2132 * Restrict Delete action.
2133 *
2134 * @param bool $restricted Whether action is restricted.
2135 * @param array $restrict Restriction array.
2136 * @param string $action Current action.
2137 * @param array $row Item data row.
2138 * @param PodsUI $obj PodsUI object.
2139 *
2140 * @since 2.3.10
2141 *
2142 * @return bool
2143 */
2144 public function admin_setup_delete_restrict( $restricted, $restrict, $action, $row, $obj ) {
2145 if ( __( 'DB', 'pods' ) !== $row['source'] ) {
2146 $restricted = true;
2147 }
2148
2149 return $restricted;
2150 }
2151
2152 /**
2153 * Get advanced administration view.
2154 */
2155 public function admin_advanced() {
2156
2157 pods_view( PODS_DIR . 'ui/admin/advanced.php', compact( array_keys( get_defined_vars() ) ) );
2158 }
2159
2160 /**
2161 * Get settings administration view
2162 */
2163 public function admin_settings() {
2164 $hide_notice = filter_var( get_option( 'pods_tmp_hide_notice_31', false ), FILTER_VALIDATE_BOOLEAN );
2165
2166 if ( ! $hide_notice ) {
2167 if (
2168 ! empty( $_GET['hide_notice_31'] )
2169 && ! empty( $_GET['hide_notice_31_nonce'] )
2170 && wp_verify_nonce( $_GET['hide_notice_31_nonce'], 'hide_notice_31' )
2171 ) {
2172 update_option( 'pods_tmp_hide_notice_31', 1, 'no' );
2173 } else {
2174 pods_message(
2175 sprintf(
2176 '⚠️ %s <a href="%s">%s</a>',
2177 __( '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' ),
2178 esc_url( add_query_arg( [ 'hide_notice_31' => 1, 'hide_notice_31_nonce' => wp_create_nonce( 'hide_notice_31' ) ] ) ),
2179 __( 'Hide this notice', 'pods' )
2180 ),
2181 'error'
2182 );
2183 }
2184 }
2185
2186 $this->maybe_handle_display_callback_notice_dismiss();
2187
2188 /**
2189 * Allow hooking into our settings page to set up hooks.
2190 *
2191 * @since 2.8.0
2192 */
2193 do_action( 'pods_admin_settings_init' );
2194
2195 add_action( 'pods_admin_before_settings', array( $this, 'show_display_callback_notice' ) );
2196
2197 // Add our custom callouts.
2198 add_action( 'pods_admin_after_settings', array( $this, 'admin_manage_callouts' ) );
2199
2200 pods_view( PODS_DIR . 'ui/admin/settings.php', compact( array_keys( get_defined_vars() ) ) );
2201 }
2202
2203 /**
2204 * Clear the cached disallowed display callbacks when the notice is dismissed.
2205 *
2206 * @since 3.3.9.2
2207 */
2208 public function maybe_handle_display_callback_notice_dismiss() {
2209 $dismiss = pods_v( 'pods_dismiss_display_callback_notice' );
2210 $nonce = pods_v( 'pods_dismiss_display_callback_notice_nonce' );
2211
2212 if ( ! $dismiss || ! $nonce ) {
2213 return;
2214 }
2215
2216 if ( false === wp_verify_nonce( $nonce, 'pods_dismiss_display_callback_notice' ) ) {
2217 return;
2218 }
2219
2220 if ( ! pods_is_admin( 'pods_settings' ) ) {
2221 return;
2222 }
2223
2224 pods_access_clear_disallowed_display_callbacks();
2225 }
2226
2227 /**
2228 * Show an admin notice on the Pods Settings page listing detected disallowed display callbacks.
2229 *
2230 * @since 3.3.9.2
2231 */
2232 public function show_display_callback_notice() {
2233 if ( ! pods_is_truthy( pods_get_setting( 'show_display_callback_notices', '1' ) ) ) {
2234 return;
2235 }
2236
2237 $callbacks = pods_get_disallowed_display_callbacks();
2238
2239 if ( empty( $callbacks ) ) {
2240 return;
2241 }
2242
2243 $escaped_callbacks = array_map( 'esc_html', $callbacks );
2244
2245 $dismiss_link = add_query_arg( array(
2246 'pods_dismiss_display_callback_notice' => '1',
2247 'pods_dismiss_display_callback_notice_nonce' => wp_create_nonce( 'pods_dismiss_display_callback_notice' ),
2248 ) );
2249
2250 pods_message(
2251 wpautop(
2252 esc_html__( 'Disallowed display callbacks were detected on this site. These callbacks were blocked and were not run.', 'pods' )
2253 . "\n\n" . '<strong>' . esc_html__( 'Disallowed callbacks:', 'pods' ) . '</strong> ' . implode( ', ', $escaped_callbacks )
2254 . "\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' )
2255 . "\n\n" . '<a href="' . esc_url( $dismiss_link ) . '" class="button">' . esc_html__( 'Dismiss and clear list', 'pods' ) . '</a>'
2256 ),
2257 'warning',
2258 false,
2259 false
2260 );
2261 }
2262
2263 /**
2264 * Get components administration UI
2265 */
2266 public function admin_components() {
2267
2268 if ( ! is_object( PodsInit::$components ) ) {
2269 return;
2270 }
2271
2272 $components = PodsInit::$components->components;
2273
2274 $view = pods_v( 'view', 'get', 'all', true );
2275
2276 $recommended = array(
2277 'advanced-relationships',
2278 'advanced-content-types',
2279 'migrate-packages',
2280 'roles-and-capabilities',
2281 'pages',
2282 'table-storage',
2283 'templates',
2284 );
2285
2286 foreach ( $components as $component => &$component_data ) {
2287 if ( ! in_array(
2288 $view, array(
2289 'all',
2290 'recommended',
2291 'dev',
2292 ), true
2293 ) && ( ! isset( $component_data['Category'] ) || sanitize_title( $component_data['Category'] ) !== $view ) ) {
2294 unset( $components[ $component ] );
2295
2296 continue;
2297 } elseif ( 'recommended' === $view && ! in_array( $component_data['ID'], $recommended, true ) ) {
2298 unset( $components[ $component ] );
2299
2300 continue;
2301 } elseif ( 'dev' === $view && pods_developer() && ! pods_v( 'DeveloperMode', $component_data, false ) ) {
2302 unset( $components[ $component ] );
2303
2304 continue;
2305 } elseif ( pods_v( 'DeveloperMode', $component_data, false ) && ! pods_developer() ) {
2306 unset( $components[ $component ] );
2307
2308 continue;
2309 } elseif ( ! pods_v( 'TablelessMode', $component_data, false ) && pods_tableless() ) {
2310 unset( $components[ $component ] );
2311
2312 continue;
2313 }//end if
2314
2315 $component_data['Name'] = strip_tags( $component_data['Name'] );
2316
2317 if ( pods_v( 'DeveloperMode', $component_data, false ) ) {
2318 $component_data['Name'] .= ' <em style="font-weight: normal; color:#333;">(Developer Preview)</em>';
2319 }
2320
2321 $meta = array();
2322
2323 if ( ! empty( $component_data['Version'] ) ) {
2324 $meta[] = sprintf( __( 'Version %s', 'pods' ), $component_data['Version'] );
2325 }
2326
2327 if ( empty( $component_data['Author'] ) ) {
2328 $component_data['Author'] = 'Pods Framework Team';
2329 $component_data['AuthorURI'] = 'https://pods.io/';
2330 }
2331
2332 if ( ! empty( $component_data['AuthorURI'] ) ) {
2333 $component_data['Author'] = '<a href="' . $component_data['AuthorURI'] . '">' . $component_data['Author'] . '</a>';
2334 }
2335
2336 $meta[] = sprintf( __( 'by %s', 'pods' ), $component_data['Author'] );
2337
2338 if ( ! empty( $component_data['URI'] ) ) {
2339 $meta[] = '<a href="' . $component_data['URI'] . '">' . __( 'Visit component site', 'pods' ) . '</a>';
2340 }
2341
2342 if ( pods_is_truthy( pods_v( 'Deprecated', $component_data, false ) ) ) {
2343 $deprecated = __( 'Deprecated', 'pods' );
2344
2345 $component_data['Name'] .= sprintf(
2346 ' <em style="font-weight: normal; color:#333;">(%s)</em>',
2347 $deprecated
2348 );
2349
2350 $deprecated_in_version = pods_v( 'DeprecatedInVersion', $component_data );
2351 $deprecated_removal_version = pods_v( 'DeprecatedRemovalVersion', $component_data );
2352
2353 if ( empty( $deprecated_removal_version ) ) {
2354 // translators: TBD means To Be Determined.
2355 $deprecated_removal_version = __( 'TBD', 'pods' );
2356 }
2357
2358 if ( $deprecated_in_version ) {
2359 $deprecated = sprintf(
2360 // translators: %1$s is the version the deprecation starts and %2$s is the version the code will be removed.
2361 __( 'Deprecated in %1$s, will be removed in %2$s', 'pods' ),
2362 $deprecated_in_version,
2363 $deprecated_removal_version
2364 );
2365 }
2366
2367 $meta[] = $deprecated;
2368 }
2369
2370 $component_data['Description'] = wpautop( trim( make_clickable( strip_tags( $component_data['Description'], 'em,strong' ) ) ) );
2371
2372 if ( ! empty( $meta ) ) {
2373 $description_style = '';
2374
2375 if ( ! empty( $component_data['Description'] ) ) {
2376 $description_style = ' style="padding:8px 0 4px;"';
2377 }
2378
2379 $component_data['Description'] .= '<div class="pods-component-meta" ' . $description_style . '>' . implode( '&nbsp;&nbsp;|&nbsp;&nbsp;', $meta ) . '</div>';
2380 }
2381
2382 $component_data = array(
2383 'id' => $component_data['ID'],
2384 'name' => $component_data['Name'],
2385 'category' => $component_data['Category'],
2386 'version' => '',
2387 'description' => $component_data['Description'],
2388 'mustuse' => pods_v( 'MustUse', $component_data, false ),
2389 'toggle' => 0,
2390 );
2391
2392 if ( ! empty( $component_data['category'] ) ) {
2393 $category_url = pods_query_arg(
2394 array(
2395 'view' => sanitize_title( $component_data['category'] ),
2396 'pg' => '',
2397 // @codingStandardsIgnoreLine
2398 'page' => $_GET['page'],
2399 )
2400 );
2401
2402 $component_data['category'] = '<a href="' . esc_url( $category_url ) . '">' . $component_data['category'] . '</a>';
2403 }
2404
2405 if ( isset( PodsInit::$components->settings['components'][ $component_data['id'] ] ) && 0 !== PodsInit::$components->settings['components'][ $component_data['id'] ] ) {
2406 $component_data['toggle'] = 1;
2407 } elseif ( $component_data['mustuse'] ) {
2408 $component_data['toggle'] = 1;
2409 }
2410 }//end foreach
2411
2412 $ui = array(
2413 'sql' => array(
2414 'field_id' => 'id',
2415 ),
2416 'data' => $components,
2417 'total' => count( $components ),
2418 'total_found' => count( $components ),
2419 'items' => __( 'Components', 'pods' ),
2420 'item' => __( 'Component', 'pods' ),
2421 'fields' => array(
2422 'manage' => array(
2423 'name' => array(
2424 'label' => __( 'Name', 'pods' ),
2425 'width' => '30%',
2426 'type' => 'text',
2427 'options' => array(
2428 'text_allow_html' => true,
2429 ),
2430 ),
2431 'category' => array(
2432 'label' => __( 'Category', 'pods' ),
2433 'width' => '10%',
2434 'type' => 'text',
2435 'options' => array(
2436 'text_allow_html' => true,
2437 ),
2438 ),
2439 'description' => array(
2440 'label' => __( 'Description', 'pods' ),
2441 'width' => '60%',
2442 'type' => 'text',
2443 'options' => array(
2444 'text_allow_html' => true,
2445 'text_allowed_html_tags' => 'strong em a ul ol li b i br div',
2446 ),
2447 ),
2448 ),
2449 ),
2450 'actions_disabled' => array( 'duplicate', 'view', 'export', 'add', 'edit', 'delete' ),
2451 'actions_custom' => array(
2452 'toggle' => array(
2453 'callback' => array( $this, 'admin_components_toggle' ),
2454 'nonce' => true,
2455 ),
2456 ),
2457 'filters_enhanced' => true,
2458 'views' => array(
2459 'all' => __( 'All', 'pods' ),
2460 // 'recommended' => __( 'Recommended', 'pods' ),
2461 'field-types' => __( 'Field Types', 'pods' ),
2462 'tools' => __( 'Tools', 'pods' ),
2463 'integration' => __( 'Integration', 'pods' ),
2464 'migration' => __( 'Migration', 'pods' ),
2465 'advanced' => __( 'Advanced', 'pods' ),
2466 ),
2467 'view' => $view,
2468 'heading' => array(
2469 'views' => __( 'Category', 'pods' ),
2470 ),
2471 'search' => false,
2472 'searchable' => false,
2473 'sortable' => false,
2474 'pagination' => false,
2475 );
2476
2477 if ( pods_developer() ) {
2478 $ui['views']['dev'] = __( 'Developer Preview', 'pods' );
2479 }
2480
2481 // Add our custom callouts.
2482 $this->handle_callouts_updates();
2483
2484 add_filter( 'pods_ui_manage_custom_container_classes', array( $this, 'admin_manage_container_class' ) );
2485 add_action( 'pods_ui_manage_after_container', array( $this, 'admin_manage_callouts' ) );
2486
2487 pods_ui( $ui );
2488 }
2489
2490 /**
2491 * Toggle a component on or off
2492 *
2493 * @param PodsUI $ui PodsUI object.
2494 *
2495 * @return bool
2496 */
2497 public function admin_components_toggle( $ui ) {
2498
2499 // @codingStandardsIgnoreLine
2500 $component = $_GET['id'];
2501
2502 if ( ! empty( PodsInit::$components->components[ $component ]['PluginDependency'] ) ) {
2503 $dependency = explode( '|', PodsInit::$components->components[ $component ]['PluginDependency'] );
2504
2505 if ( ! pods_is_plugin_active( $dependency[1] ) ) {
2506 $website = 'http://wordpress.org/extend/plugins/' . dirname( $dependency[1] ) . '/';
2507
2508 if ( isset( $dependency[2] ) ) {
2509 $website = $dependency[2];
2510 }
2511
2512 if ( ! empty( $website ) ) {
2513 $website = ' ' . sprintf( __( 'You can find it at %s', 'pods' ), '<a href="' . $website . '" target="_blank" rel="noopener noreferrer">' . $website . '</a>' );
2514 }
2515
2516 $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;
2517
2518 $ui->error( $message );
2519
2520 $ui->manage();
2521
2522 return;
2523 }
2524 }//end if
2525
2526 if ( ! empty( PodsInit::$components->components[ $component ]['ThemeDependency'] ) ) {
2527 $dependency = explode( '|', PodsInit::$components->components[ $component ]['ThemeDependency'] );
2528
2529 $check = strtolower( $dependency[1] );
2530
2531 if ( strtolower( get_template() ) !== $check && strtolower( get_stylesheet() ) !== $check ) {
2532 $website = '';
2533
2534 if ( isset( $dependency[2] ) ) {
2535 $website = ' ' . sprintf( __( 'You can find it at %s', 'pods' ), '<a href="' . $dependency[2] . '" target="_blank" rel="noopener noreferrer">' . $dependency[2] . '</a>' );
2536 }
2537
2538 $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;
2539
2540 $ui->error( $message );
2541
2542 $ui->manage();
2543
2544 return;
2545 }
2546 }//end if
2547
2548 if ( ! empty( PodsInit::$components->components[ $component ]['MustUse'] ) ) {
2549 $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'] );
2550
2551 $ui->error( $message );
2552
2553 $ui->manage();
2554
2555 return;
2556 }
2557
2558 if ( 1 === (int) pods_v( 'toggled' ) ) {
2559 $toggle = PodsInit::$components->toggle( $component );
2560
2561 if ( true === $toggle ) {
2562 $ui->message( PodsInit::$components->components[ $component ]['Name'] . ' ' . __( 'Component enabled', 'pods' ) );
2563 } elseif ( false === $toggle ) {
2564 $ui->message( PodsInit::$components->components[ $component ]['Name'] . ' ' . __( 'Component disabled', 'pods' ) );
2565 }
2566
2567 $components = PodsInit::$components->components;
2568
2569 foreach ( $components as $component => &$component_data ) {
2570 $toggle = 0;
2571
2572 if ( isset( PodsInit::$components->settings['components'][ $component_data['ID'] ] ) ) {
2573 if ( 0 !== PodsInit::$components->settings['components'][ $component_data['ID'] ] ) {
2574 $toggle = 1;
2575 }
2576 }
2577 if ( true === $component_data['DeveloperMode'] ) {
2578 if ( ! pods_developer() ) {
2579 unset( $components[ $component ] );
2580 continue;
2581 }
2582 }
2583
2584 $component_data = array(
2585 'id' => $component_data['ID'],
2586 'name' => $component_data['Name'],
2587 'description' => make_clickable( $component_data['Description'] ),
2588 'version' => $component_data['Version'],
2589 'author' => $component_data['Author'],
2590 'toggle' => $toggle,
2591 );
2592 }//end foreach
2593
2594 $ui->data = $components;
2595
2596 pods_transient_clear( 'pods_components' );
2597
2598 $url = pods_query_arg( array( 'toggled' => null ) );
2599
2600 pods_redirect( $url );
2601 } elseif ( 1 === (int) pods_v( 'toggle' ) ) {
2602 $ui->message( PodsInit::$components->components[ $component ]['Name'] . ' ' . __( 'Component enabled', 'pods' ) );
2603 } else {
2604 $ui->message( PodsInit::$components->components[ $component ]['Name'] . ' ' . __( 'Component disabled', 'pods' ) );
2605 }//end if
2606
2607 $ui->manage();
2608 }
2609
2610 /**
2611 * Get the admin upgrade page
2612 */
2613 public function admin_upgrade() {
2614
2615 foreach ( PodsInit::$upgrades as $old_version => $new_version ) {
2616 if ( version_compare( $old_version, PodsInit::$version_last, '<=' ) && version_compare( PodsInit::$version_last, $new_version, '<' ) ) {
2617 $new_version = str_replace( '.', '_', $new_version );
2618
2619 pods_view( PODS_DIR . 'ui/admin/upgrade/upgrade_' . $new_version . '.php', compact( array_keys( get_defined_vars() ) ) );
2620
2621 break;
2622 }
2623 }
2624 }
2625
2626 /**
2627 * Get the admin help page
2628 */
2629 public function admin_help() {
2630 // Add our custom callouts.
2631 $this->handle_callouts_updates();
2632
2633 add_action( 'pods_admin_after_help', array( $this, 'admin_manage_callouts' ) );
2634
2635 pods_view( PODS_DIR . 'ui/admin/help.php', compact( array_keys( get_defined_vars() ) ) );
2636 }
2637
2638 /**
2639 * Add pods specific capabilities.
2640 *
2641 * @param array $capabilities List of extra capabilities to add.
2642 *
2643 * @return array
2644 */
2645 public function admin_capabilities( $capabilities ) {
2646
2647 $pods = pods_api()->load_pods(
2648 array(
2649 'type' => array(
2650 'settings',
2651 'post_type',
2652 'taxonomy',
2653 ),
2654 )
2655 );
2656
2657 $other_pods = pods_api()->load_pods(
2658 array(
2659 'type' => array(
2660 'pod',
2661 'table',
2662 ),
2663 )
2664 );
2665
2666 $pods = array_merge( $pods, $other_pods );
2667
2668 $capabilities[] = 'pods';
2669 $capabilities[] = 'pods_content';
2670 $capabilities[] = 'pods_settings';
2671 $capabilities[] = 'pods_components';
2672
2673 foreach ( $pods as $pod ) {
2674 if ( 'settings' === $pod['type'] ) {
2675 $capabilities[] = 'pods_edit_' . $pod['name'];
2676 } elseif ( 'post_type' === $pod['type'] ) {
2677 $capability_type = pods_v_sanitized( 'capability_type_custom', $pod['options'], pods_v( 'name', $pod ) );
2678
2679 if ( 'custom' === pods_v( 'capability_type', $pod['options'] ) && is_string( $capability_type ) && 0 < strlen( $capability_type ) ) {
2680 $capabilities[] = 'read_' . $capability_type;
2681 $capabilities[] = 'edit_' . $capability_type;
2682 $capabilities[] = 'delete_' . $capability_type;
2683
2684 if ( 1 === (int) pods_v( 'capability_type_extra', $pod['options'], 1 ) ) {
2685 $capability_type_plural = $capability_type . 's';
2686
2687 $capabilities[] = 'read_private_' . $capability_type_plural;
2688 $capabilities[] = 'edit_' . $capability_type_plural;
2689 $capabilities[] = 'edit_others_' . $capability_type_plural;
2690 $capabilities[] = 'edit_private_' . $capability_type_plural;
2691 $capabilities[] = 'edit_published_' . $capability_type_plural;
2692 $capabilities[] = 'publish_' . $capability_type_plural;
2693 $capabilities[] = 'delete_' . $capability_type_plural;
2694 $capabilities[] = 'delete_private_' . $capability_type_plural;
2695 $capabilities[] = 'delete_published_' . $capability_type_plural;
2696 $capabilities[] = 'delete_others_' . $capability_type_plural;
2697 }
2698 }
2699 } elseif ( 'taxonomy' === $pod['type'] ) {
2700 if ( 'custom' === pods_v( 'capability_type', $pod['options'], 'terms' ) ) {
2701 $capability_type = pods_v_sanitized( 'capability_type_custom', $pod['options'], pods_v( 'name', $pod ) . 's' );
2702
2703 $capability_type .= '_term';
2704 $capability_type_plural = $capability_type . 's';
2705
2706 // Singular
2707 $capabilities[] = 'edit_' . $capability_type;
2708 $capabilities[] = 'delete_' . $capability_type;
2709 $capabilities[] = 'assign_' . $capability_type;
2710 // Plural
2711 $capabilities[] = 'manage_' . $capability_type_plural;
2712 $capabilities[] = 'edit_' . $capability_type_plural;
2713 $capabilities[] = 'delete_' . $capability_type_plural;
2714 $capabilities[] = 'assign_' . $capability_type_plural;
2715 }
2716 } else {
2717 $capabilities[] = 'pods_add_' . $pod['name'];
2718 $capabilities[] = 'pods_edit_' . $pod['name'];
2719 $capabilities[] = 'pods_delete_' . $pod['name'];
2720
2721 if ( $pod instanceof Pod ) {
2722 $author_field = $pod->get_field( 'author', null, false );
2723 } else {
2724 $author_field = pods_v( 'author', $pod['fields'] );
2725 }
2726
2727 if ( $author_field && 'pick' === $author_field['type'] && 'user' === $author_field['pick_object'] ) {
2728 $capabilities[] = 'pods_edit_others_' . $pod['name'];
2729 $capabilities[] = 'pods_delete_others_' . $pod['name'];
2730 }
2731
2732 $actions_enabled = pods_v( 'ui_actions_enabled', $pod['options'] );
2733
2734 if ( ! empty( $actions_enabled ) ) {
2735 $actions_enabled = (array) $actions_enabled;
2736 } else {
2737 $actions_enabled = array();
2738 }
2739
2740 $available_actions = array(
2741 'add',
2742 'edit',
2743 'duplicate',
2744 'delete',
2745 'reorder',
2746 'export',
2747 );
2748
2749 if ( ! empty( $actions_enabled ) ) {
2750 $actions_disabled = array(
2751 'view' => 'view',
2752 );
2753
2754 foreach ( $available_actions as $action ) {
2755 if ( ! in_array( $action, $actions_enabled, true ) ) {
2756 $actions_disabled[ $action ] = $action;
2757 }
2758 }
2759
2760 if ( ! in_array( 'export', $actions_disabled, true ) ) {
2761 $capabilities[] = 'pods_export_' . $pod['name'];
2762 }
2763
2764 if ( ! in_array( 'reorder', $actions_disabled, true ) ) {
2765 $capabilities[] = 'pods_reorder_' . $pod['name'];
2766 }
2767 } elseif ( 1 === (int) pods_v( 'ui_export', $pod['options'], 0 ) ) {
2768 $capabilities[] = 'pods_export_' . $pod['name'];
2769 }//end if
2770 }//end if
2771 }//end foreach
2772
2773 return $capabilities;
2774 }
2775
2776 /**
2777 * Handle ajax calls for the administration
2778 */
2779 public function admin_ajax() {
2780
2781 if ( false === headers_sent() ) {
2782 pods_session_start();
2783
2784 header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ) );
2785 }
2786
2787 // Sanitize input
2788 // @codingStandardsIgnoreLine
2789 $params = pods_unslash( (array) $_POST );
2790
2791 foreach ( $params as $key => $value ) {
2792 if ( 'action' === $key ) {
2793 continue;
2794 }
2795
2796 // Fixup $_POST data @codingStandardsIgnoreLine
2797 $_POST[ str_replace( '_podsfix_', '', $key ) ] = $_POST[ $key ];
2798
2799 // Fixup $params with unslashed data
2800 $params[ str_replace( '_podsfix_', '', $key ) ] = $value;
2801
2802 // Unset the _podsfix_* keys
2803 unset( $params[ $key ] );
2804 }
2805
2806 $params = (object) $params;
2807
2808 $methods = array(
2809 'add_pod' => array( 'priv' => true ),
2810 'save_pod' => array( 'priv' => true ),
2811 'load_sister_fields' => array( 'priv' => true ),
2812 'process_form' => array( 'custom_nonce' => true ),
2813 // priv handled through nonce
2814 'upgrade' => array( 'priv' => true ),
2815 'migrate' => array( 'priv' => true ),
2816 );
2817
2818 /**
2819 * AJAX Callbacks in field editor
2820 *
2821 * @since unknown
2822 *
2823 * @param array $methods Callback methods.
2824 * @param PodsAdmin $obj PodsAdmin object.
2825 */
2826 $methods = apply_filters( 'pods_admin_ajax_methods', $methods, $this );
2827
2828 if ( ! isset( $params->method ) || ! isset( $methods[ $params->method ] ) ) {
2829 return pods_error( __( 'Invalid AJAX request method', 'pods' ), $this );
2830 }
2831
2832 $defaults = array(
2833 'priv' => null,
2834 'name' => $params->method,
2835 'custom_nonce' => null,
2836 );
2837
2838 $method = (object) array_merge( $defaults, (array) $methods[ $params->method ] );
2839
2840 if ( empty( $method->priv ) && empty( $method->custom_nonce ) ) {
2841 return pods_error( __( 'Invalid AJAX request nonce handling', 'pods' ), $this );
2842 }
2843
2844 if (
2845 true !== $method->custom_nonce
2846 && (
2847 ! is_user_logged_in()
2848 || ! isset( $params->_wpnonce )
2849 || false === wp_verify_nonce( $params->_wpnonce, 'pods-' . $params->method )
2850 )
2851 ) {
2852 return pods_error( __( 'Unauthorized form request', 'pods' ), $this );
2853 }
2854
2855 // Cleaning up $params
2856 unset( $params->action );
2857 unset( $params->method );
2858
2859 if ( true !== $method->custom_nonce ) {
2860 unset( $params->_wpnonce );
2861 }
2862
2863 // Check permissions (convert to array to support multiple)
2864 if ( ! empty( $method->priv ) && ! pods_is_admin( array( 'pods' ) ) ) {
2865 if ( true !== $method->priv && pods_is_admin( $method->priv ) ) {
2866 // They have access to the custom priv.
2867 } else {
2868 // They do not have access.
2869 return pods_error( __( 'Access denied', 'pods' ), $this );
2870 }
2871 }
2872
2873 $params->method = $method->name;
2874
2875 $method_name = $method->name;
2876
2877 $params = apply_filters( "pods_api_{$method_name}", $params, $method );
2878
2879 $api = pods_api();
2880
2881 $api->display_errors = false;
2882
2883 if ( 'upgrade' === $method->name ) {
2884 $output = (string) pods_upgrade( $params->version )->ajax( $params );
2885 } elseif ( 'migrate' === $method->name ) {
2886 $output = (string) apply_filters( 'pods_api_migrate_run', $params );
2887 } else {
2888 if ( ! method_exists( $api, $method->name ) ) {
2889 return pods_error( __( 'API method does not exist', 'pods' ), $this );
2890 } elseif ( 'save_pod' === $method->name ) {
2891 if ( isset( $params->field_data_json ) && is_array( $params->field_data_json ) ) {
2892 $params->fields = $params->field_data_json;
2893
2894 unset( $params->field_data_json );
2895
2896 foreach ( $params->fields as $k => $v ) {
2897 if ( empty( $v ) ) {
2898 unset( $params->fields[ $k ] );
2899 } elseif ( ! is_array( $v ) ) {
2900 $params->fields[ $k ] = (array) @json_decode( $v, true );
2901 }
2902 }
2903 }
2904 }
2905
2906 // Dynamically call the API method
2907 $params = (array) $params;
2908
2909 $output = call_user_func( array( $api, $method->name ), $params );
2910 }//end if
2911
2912 // Output in json format
2913 if ( false !== $output ) {
2914
2915 /**
2916 * Pods Admin AJAX request was successful
2917 *
2918 * @since 2.6.8
2919 *
2920 * @param array $params AJAX parameters.
2921 * @param array|object|string $output Output for AJAX request.
2922 */
2923 do_action( "pods_admin_ajax_success_{$method->name}", $params, $output );
2924
2925 if ( is_array( $output ) || is_object( $output ) ) {
2926 wp_send_json( $output );
2927 } else {
2928 // @codingStandardsIgnoreLine
2929 echo $output;
2930 }
2931 } else {
2932 return pods_error( __( 'There was a problem with your request.', 'pods' ) );
2933 }//end if
2934
2935 die();
2936 // KBAI!
2937 }
2938
2939 /**
2940 * Profiles the Pods configuration
2941 *
2942 * @param null|string|array $pod Which Pod(s) to get configuration for. Can be a the name
2943 * of one Pod, or an array of names of Pods, or null, which is the
2944 * default, to profile all Pods.
2945 * @param bool $full_field_info If true all info about each field is returned. If false,
2946 * which is the default only name and type, will be returned.
2947 *
2948 * @return array
2949 *
2950 * @since 2.7.0
2951 * @deprecated 2.8.0
2952 */
2953 public function configuration( $pod = null, $full_field_info = false ) {
2954 pods_deprecated( 'PodsAdmin::configuration', '2.8' );
2955
2956 $api = pods_api();
2957
2958 if ( null === $pod ) {
2959 $the_pods = $api->load_pods();
2960 } elseif ( is_array( $pod ) ) {
2961 foreach ( $pod as $p ) {
2962 $the_pods[] = $api->load_pod( $p );
2963 }
2964 } else {
2965 $the_pods[] = $api->load_pod( $pod );
2966 }
2967
2968 foreach ( $the_pods as $the_pod ) {
2969 $configuration[ $the_pod['name'] ] = array(
2970 'name' => $the_pod['name'],
2971 'ID' => $the_pod['id'],
2972 'storage' => $the_pod['storage'],
2973 'fields' => $the_pod['fields'],
2974 );
2975 }
2976
2977 if ( ! $full_field_info ) {
2978 foreach ( $the_pods as $the_pod ) {
2979 $fields = $configuration[ $the_pod['name'] ]['fields'];
2980
2981 unset( $configuration[ $the_pod['name'] ]['fields'] );
2982
2983 foreach ( $fields as $field ) {
2984 $info = array(
2985 'name' => $field['name'],
2986 'type' => $field['type'],
2987 );
2988
2989 if ( 'pick' === $info['type'] ) {
2990 $info['pick_object'] = $field['pick_object'];
2991
2992 if ( isset( $field['pick_val'] ) && '' !== $field['pick_val'] ) {
2993 $info['pick_val'] = $field['pick_val'];
2994 }
2995 }
2996
2997 if ( is_array( $info ) ) {
2998 $configuration[ $the_pod['name'] ]['fields'][ $field['name'] ] = $info;
2999 }
3000
3001 unset( $info );
3002
3003 }//end foreach
3004 }//end foreach
3005 }//end if
3006
3007 if ( is_array( $configuration ) ) {
3008 return $configuration;
3009 }
3010
3011 }
3012
3013 /**
3014 * Build UI for extending REST API, if makes sense to do so.
3015 *
3016 * @since 2.6.0
3017 *
3018 * @access protected
3019 */
3020 protected function rest_admin() {
3021
3022 if ( function_exists( 'register_rest_field' ) ) {
3023 add_filter(
3024 'pods_admin_setup_edit_field_options', array(
3025 $this,
3026 'add_rest_fields_to_field_editor',
3027 ), 12, 2
3028 );
3029 add_filter( 'pods_admin_setup_edit_field_tabs', array( $this, 'add_rest_field_tab' ), 12, 2 );
3030 }
3031
3032 add_filter( 'pods_admin_setup_edit_tabs', array( $this, 'add_rest_settings_tab' ), 12, 2 );
3033 add_filter( 'pods_admin_setup_edit_options', array( $this, 'add_rest_settings_tab_fields' ), 12, 2 );
3034
3035 }
3036
3037 /**
3038 * Check if Pod type <em>could</em> extend core REST API response
3039 *
3040 * @since 2.5.6
3041 *
3042 * @access protected
3043 *
3044 * @param array $pod Pod options.
3045 *
3046 * @return bool
3047 */
3048 protected function restable_pod( $pod ) {
3049
3050 $type = $pod['type'];
3051
3052 $restable_types = array(
3053 'post_type',
3054 'user',
3055 'taxonomy',
3056 'media',
3057 );
3058
3059 return in_array( $type, $restable_types, true );
3060
3061 }
3062
3063 /**
3064 * Add a rest api tab.
3065 *
3066 * @since 2.6.0
3067 *
3068 * @param array $tabs Tab array.
3069 * @param array $pod Pod options.
3070 *
3071 * @return array
3072 */
3073 public function add_rest_settings_tab( $tabs, $pod ) {
3074 if ( ! $this->restable_pod( $pod ) ) {
3075 return $tabs;
3076 }
3077
3078 $tabs['rest-api'] = __( 'REST API', 'pods' );
3079
3080 return $tabs;
3081
3082 }
3083
3084 /**
3085 * Populate REST API tab.
3086 *
3087 * @since 0.1.0
3088 *
3089 * @param array $options Tab options.
3090 * @param array $pod Pod options.
3091 *
3092 * @return array
3093 */
3094 public function add_rest_settings_tab_fields( $options, $pod ) {
3095 if ( ! $this->restable_pod( $pod ) ) {
3096 return $options;
3097 }
3098
3099 $options['rest-api'] = [
3100 'rest_enable' => [
3101 'label' => __( 'Enable', 'pods' ),
3102 'help' => __( 'Add REST API support for this Pod.', 'pods' ),
3103 'type' => 'boolean',
3104 'default' => '',
3105 'dependency' => true,
3106 ],
3107 'rest_base' => [
3108 'label' => __( 'REST Base (if any)', 'pods' ),
3109 'help' => __( 'This will form the url for the route. Default / empty value here will use the pod name.', 'pods' ),
3110 'type' => 'text',
3111 'default' => '',
3112 'depends-on' => [ 'rest_enable' => true ],
3113 ],
3114 'rest_namespace' => [
3115 'label' => __( 'REST API namespace', 'pods' ),
3116 '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' ),
3117 'type' => 'text',
3118 'default' => '',
3119 'placeholder' => 'wp/v2',
3120 'depends-on' => [ 'rest_enable' => true ],
3121 ],
3122 'read_all' => [
3123 'label' => __( 'Show All Fields (read-only)', 'pods' ),
3124 'help' => __( 'Show all fields in REST API. If unchecked fields must be enabled on a field by field basis.', 'pods' ),
3125 'type' => 'boolean',
3126 'default' => '',
3127 'depends-on' => [ 'rest_enable' => true ],
3128 'dependency' => true,
3129 ],
3130 'write_all' => [
3131 'label' => __( 'Allow All Fields To Be Updated', 'pods' ),
3132 'help' => __( 'Allow all fields to be updated via the REST API. If unchecked fields must be enabled on a field by field basis.', 'pods' ),
3133 'type' => 'boolean',
3134 'default' => pods_v( 'name', $pod ),
3135 'depends-on' => [ 'rest_enable' => true, 'read_all' => true ],
3136 ],
3137 'rest_api_field_mode' => [
3138 'label' => __( 'Field Mode', 'pods' ),
3139 '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' ),
3140 'type' => 'pick',
3141 'pick_format_single' => 'dropdown',
3142 'default' => 'value',
3143 'depends-on' => [ 'rest_enable' => true ],
3144 'data' => [
3145 'value' => __( 'Raw values', 'pods' ),
3146 'render' => __( 'Rendered values', 'pods' ),
3147 'value_and_render' => __( 'Both raw and rendered values {value: raw_value, rendered: rendered_value}', 'pods' ),
3148 ],
3149 ],
3150 ];
3151
3152 return $options;
3153 }
3154
3155 /**
3156 * Add a REST API section to advanced tab of field editor.
3157 *
3158 * @since 2.5.6
3159 *
3160 * @param array $options Tab options.
3161 * @param array $pod Pod options.
3162 *
3163 * @return array
3164 */
3165 public function add_rest_fields_to_field_editor( $options, $pod ) {
3166 if ( ! $this->restable_pod( $pod ) ) {
3167 return $options;
3168 }
3169
3170 $options['rest'][ __( 'Read/ Write', 'pods' ) ] = [
3171 'rest_read' => [
3172 'label' => __( 'Read via REST API', 'pods' ),
3173 'help' => __( 'Should this field be readable via the REST API? You must enable REST API support for this Pod.', 'pods' ),
3174 'type' => 'boolean',
3175 'default' => '',
3176 ],
3177 'rest_write' => [
3178 'label' => __( 'Write via REST API', 'pods' ),
3179 'help' => __( 'Should this field be writeable via the REST API? You must enable REST API support for this Pod.', 'pods' ),
3180 'type' => 'boolean',
3181 'default' => '',
3182 ],
3183 ];
3184
3185 $options['rest'][ __( 'Relationship Field Options', 'pods' ) ] = [
3186 'rest_pick_response' => [
3187 'label' => __( 'Response Type', 'pods' ),
3188 'help' => __( 'This will determine what amount of data for the related items will be returned.', 'pods' ),
3189 'type' => 'pick',
3190 'pick_format_single' => 'dropdown',
3191 'default' => 'array',
3192 'depends-on' => [
3193 'type' => 'pick',
3194 ],
3195 'dependency' => true,
3196 'data' => [
3197 'array' => __( 'All fields', 'pods' ),
3198 'id' => __( 'ID only', 'pods' ),
3199 'name' => __( 'Name only', 'pods' ),
3200 'custom' => __( 'Custom return (specify field to return)', 'pods' ),
3201 ],
3202 ],
3203 'rest_pick_depth' => [
3204 'label' => __( 'Depth', 'pods' ),
3205 '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' ),
3206 'type' => 'number',
3207 'default' => '1',
3208 'depends-on' => [
3209 'type' => 'pick',
3210 'rest_pick_response' => 'array',
3211 ],
3212 ],
3213 'rest_pick_custom' => [
3214 'label' => __( 'Custom return', 'pods' ),
3215 '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' ),
3216 'type' => 'text',
3217 'default' => '',
3218 'placeholder' => 'this_field_name.ID',
3219 'depends-on' => [
3220 'type' => 'pick',
3221 'rest_pick_response' => 'custom',
3222 ],
3223 ],
3224 'rest_pick_notice' => [
3225 'label' => 'Relationship Options',
3226 'type' => 'html',
3227 'html_content' => __( 'If you have a relationship field, you will see additional options to customize here.', 'pods' ),
3228 'excludes-on' => [ 'type' => 'pick' ],
3229 ],
3230 ];
3231
3232 return $options;
3233 }
3234
3235 /**
3236 * Add REST field tab
3237 *
3238 * @since 2.5.6
3239 *
3240 * @param array $tabs Tab list.
3241 * @param array $pod The ood object.
3242 *
3243 * @return array
3244 */
3245 public function add_rest_field_tab( $tabs, $pod ) {
3246 if ( ! $this->restable_pod( $pod ) ) {
3247 return $tabs;
3248 }
3249
3250 $tabs['rest'] = __( 'REST API', 'pods' );
3251
3252 return $tabs;
3253 }
3254
3255 /**
3256 * Add Pods-specific debug info to Site Info debug area.
3257 *
3258 * @since 2.7.13
3259 *
3260 * @param array $info Debug info.
3261 *
3262 * @return array Debug info with Pods-specific debug info added.
3263 */
3264 public function add_debug_information( $info ) {
3265 $auto_start = pods_session_auto_start();
3266
3267 if ( 'auto' !== $auto_start ) {
3268 // Turn boolean into 0/1.
3269 $auto_start = (int) $auto_start;
3270 }
3271
3272 // Turn into a string.
3273 $auto_start = (string) $auto_start;
3274
3275 $settings = pods_container( Settings::class );
3276
3277 $fields = $settings->get_setting_fields();
3278
3279 $settings_values = $settings->get_settings();
3280
3281 $auto_start = pods_v( $auto_start, $fields['session_auto_start']['data'], __( 'Unknown', 'pods' ) );
3282
3283 global $wpdb;
3284
3285 $info['pods'] = [
3286 'label' => 'Pods',
3287 'description' => __( 'Debug information for Pods installations.', 'pods' ),
3288 'fields' => [
3289 'pods-server-software' => [
3290 'label' => __( 'Server Software', 'pods' ),
3291 'value' => ! empty( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : 'N/A',
3292 ],
3293 'pods-user-agent' => [
3294 'label' => __( 'Your User Agent', 'pods' ),
3295 'value' => ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : 'N/A',
3296 ],
3297 'pods-session-save-path' => [
3298 'label' => __( 'Session Save Path', 'pods' ),
3299 'value' => session_save_path(),
3300 ],
3301 'pods-session-save-path-exists' => [
3302 'label' => __( 'Session Save Path Exists', 'pods' ),
3303 'value' => file_exists( session_save_path() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3304 ],
3305 'pods-session-save-path-writable' => [
3306 'label' => __( 'Session Save Path Writeable', 'pods' ),
3307 'value' => is_writable( session_save_path() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3308 ],
3309 'pods-session-max-lifetime' => [
3310 'label' => __( 'Session Max Lifetime', 'pods' ),
3311 'value' => ini_get( 'session.gc_maxlifetime' ),
3312 ],
3313 'pods-opcode-cache-apc' => [
3314 'label' => __( 'Opcode Cache: Apc', 'pods' ),
3315 'value' => function_exists( 'apc_cache_info' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3316 ],
3317 'pods-opcode-cache-memcached' => [
3318 'label' => __( 'Opcode Cache: Memcached', 'pods' ),
3319 'value' => class_exists( 'eaccelerator_put' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3320 ],
3321 'pods-opcode-cache-opcache' => [
3322 'label' => __( 'Opcode Cache: OPcache', 'pods' ),
3323 'value' => function_exists( 'opcache_get_status' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3324 ],
3325 'pods-opcode-cache-redis' => [
3326 'label' => __( 'Opcode Cache: Redis', 'pods' ),
3327 'value' => class_exists( 'xcache_set' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3328 ],
3329 'pods-object-cache-apc' => [
3330 'label' => __( 'Object Cache: APC', 'pods' ),
3331 'value' => function_exists( 'apc_cache_info' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3332 ],
3333 'pods-object-cache-apcu' => [
3334 'label' => __( 'Object Cache: APCu', 'pods' ),
3335 'value' => function_exists( 'apcu_cache_info' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3336 ],
3337 'pods-object-cache-memcache' => [
3338 'label' => __( 'Object Cache: Memcache', 'pods' ),
3339 'value' => class_exists( 'Memcache' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3340 ],
3341 'pods-object-cache-memcached' => [
3342 'label' => __( 'Object Cache: Memcached', 'pods' ),
3343 'value' => class_exists( 'Memcached' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3344 ],
3345 'pods-object-cache-redis' => [
3346 'label' => __( 'Object Cache: Redis', 'pods' ),
3347 'value' => class_exists( 'Redis' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3348 ],
3349 'pods-memory-current-usage' => [
3350 'label' => __( 'Current Memory Usage', 'pods' ),
3351 'value' => number_format_i18n( memory_get_usage() / 1024 / 1024, 3 ) . 'M' . ( defined( 'WP_MEMORY_LIMIT' ) ? ' / ' . WP_MEMORY_LIMIT : '' ),
3352 ],
3353 'pods-memory-current-usage-real' => [
3354 'label' => __( 'Current Memory Usage (real)', 'pods' ),
3355 'value' => number_format_i18n( memory_get_usage( true ) / 1024 / 1024, 3 ) . 'M',
3356 ],
3357 'pods-network-wide' => [
3358 'label' => __( 'Pods Network-Wide Activated', 'pods' ),
3359 'value' => is_plugin_active_for_network( basename( PODS_DIR ) . '/init.php' ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3360 ],
3361 'pods-install-location' => [
3362 'label' => __( 'Pods Install Location', 'pods' ),
3363 'value' => str_replace( ABSPATH, '/', PODS_DIR ),
3364 ],
3365 'pods-developer' => [
3366 'label' => __( 'Pods Developer Activated' ),
3367 'value' => ( pods_developer() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3368 ],
3369 'pods-tableless-mode' => [
3370 'label' => __( 'Pods Tableless Mode Activated', 'pods' ),
3371 'value' => ( pods_tableless() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3372 ],
3373 'pods-relationship-table-enabled' => [
3374 'label' => __( 'Pods Relationship Table Enabled', 'pods' ),
3375 'value' => ( pods_podsrel_enabled() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3376 ],
3377 'pods-relationship-table-status' => [
3378 'label' => __( 'Pods Relationship Table Count' ),
3379 'value' => ( ! pods_tableless() ? number_format( (float) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}podsrel" ) ) : 'No table' ),
3380 ],
3381 'pods-light-mode' => [
3382 'label' => __( 'Pods Light Mode Activated', 'pods' ),
3383 'value' => ( pods_light() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3384 ],
3385 'pods-strict' => [
3386 'label' => __( 'Pods Strict Activated' ),
3387 'value' => ( pods_strict( false ) ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3388 ],
3389 'pods-allow-deprecated' => [
3390 'label' => __( 'Pods Allow Deprecated' ),
3391 'value' => ( pods_allow_deprecated() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3392 ],
3393 'pods-api-cache' => [
3394 'label' => __( 'Pods API Cache Activated' ),
3395 'value' => ( pods_api_cache() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3396 ],
3397 'pods-shortcode-allow-evaluate-tags' => [
3398 'label' => __( 'Pods Shortcode Allow Evaluate Tags' ),
3399 'value' => ( pods_shortcode_allow_evaluate_tags() ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3400 ],
3401 'pods-sessions' => [
3402 'label' => __( 'Pods Sessions' ),
3403 'value' => $auto_start,
3404 ],
3405 'pods-can-use-sessions' => [
3406 'label' => __( 'Pods Can Use Sessions' ),
3407 'value' => ( pods_can_use_sessions( true ) ) ? __( 'Yes', 'pods' ) : __( 'No', 'pods' ),
3408 ],
3409 ],
3410 ];
3411
3412 $settings_to_show = [
3413 'types_only' => __( 'Setting: Types only', 'pods' ),
3414 'watch_changed_fields' => __( 'Setting: Watch Changed fields', 'pods' ),
3415 'metadata_integration' => __( 'Setting: Watch WP Metadata calls', 'pods' ),
3416 'metadata_override_get' => __( 'Setting: Override WP Metadata values', 'pods' ),
3417 ];
3418
3419 foreach ( $settings_to_show as $setting => $label ) {
3420 $setting_key = 'pods-settings-' . sanitize_title_with_dashes( $setting );
3421
3422 $value = ucwords(
3423 str_replace(
3424 [ '_', '-' ],
3425 ' ',
3426 (string) pods_v( $setting, $settings_values, __( 'Unknown', 'pods' )
3427 )
3428 )
3429 );
3430
3431 if ( '0' === $value ) {
3432 $value = __( 'No', 'pods' );
3433 } elseif ( '1' === $value ) {
3434 $value = __( 'Yes', 'pods' );
3435 }
3436
3437 $info['pods']['fields'][ $setting_key ] = [
3438 'label' => $label,
3439 'value' => $value,
3440 ];
3441 }
3442
3443 // @todo Later we should add which components are active.
3444
3445 return $info;
3446 }
3447
3448 /**
3449 * Add our site status tests.
3450 *
3451 * @since 2.8.0
3452 *
3453 * @param array $tests The list of status tests.
3454 *
3455 * @return array The list of status tests.
3456 */
3457 public function site_status_tests( $tests ) {
3458 $plugin_search_url = 'plugin-install.php?tab=search&type=term&s=';
3459
3460 if ( is_multisite() && ! is_network_admin() ) {
3461 $plugin_search_url = network_admin_url( $plugin_search_url );
3462 } else {
3463 $plugin_search_url = self_admin_url( $plugin_search_url );
3464 }
3465
3466 if ( ! is_pods_alternative_cache_activated() && ! wp_using_ext_object_cache() ) {
3467 $tests['direct']['pods_alternative_cache'] = [
3468 'label' => __( 'Pods Alternative Cache', 'pods' ),
3469 'test' => static function () use ( $plugin_search_url ) {
3470 return [
3471 'label' => __( 'The Pods Team recommends you install the Pods Alternative Cache plugin', 'pods' ),
3472 'status' => 'recommended',
3473 'badge' => [
3474 'label' => __( 'Performance', 'pods' ),
3475 'color' => 'blue',
3476 ],
3477 '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' ) ),
3478 'actions' => sprintf( '<p><a href="%s">%s</a></p>', esc_url( $plugin_search_url . urlencode( 'Pods Alternative Cache' ) ), __( 'Install Pods Alternative Cache', 'pods' ) ),
3479 'test' => 'pods_alternative_cache',
3480 ];
3481 },
3482 ];
3483 }
3484
3485 return $tests;
3486 }
3487
3488 /**
3489 * Check whether the requirements were met and maybe display error messages.
3490 *
3491 * @since 2.9.0
3492 *
3493 * @param array $requirements List of requirements.
3494 *
3495 * @return bool Whether the requirements were met.
3496 */
3497 public function check_requirements( array $requirements ) {
3498 foreach ( $requirements as $requirement ) {
3499 // Check if requirement passed.
3500 if ( $requirement['check'] ) {
3501 continue;
3502 }
3503
3504 // Show admin notice if there's a message to be shown.
3505 if ( ! empty( $requirement['message'] ) && $this->should_show_notices() ) {
3506 pods_message( $requirement['message'], 'error' );
3507 }
3508
3509 return false;
3510 }
3511
3512 return true;
3513 }
3514
3515 /**
3516 * Check whether we should show notices.
3517 *
3518 * @since 2.9.0
3519 *
3520 * @return bool Whether we should show notices.
3521 */
3522 public function should_show_notices() {
3523 global $pagenow;
3524
3525 // We only show notices on admin pages.
3526 if ( ! is_admin() ) {
3527 return false;
3528 }
3529
3530 $page = isset( $_GET['page'] ) ? $_GET['page'] : '';
3531
3532 // We only show on the plugins.php page or on Pods Admin pages.
3533 if (
3534 (
3535 'plugins.php' !== $pagenow
3536 && 0 !== strpos( $page, 'pods' )
3537 )
3538 || 0 === strpos( $page, 'pods-manage-' )
3539 ) {
3540 return false;
3541 }
3542
3543 return true;
3544 }
3545
3546 }
3547