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