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