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