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