PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.3.7
Pods – Custom Content Types and Fields v3.3.7
trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / components / Pages.php
pods / components Last commit date
I18n 4 months ago Migrate-ACF 4 months ago Migrate-CPTUI 4 months ago Migrate-PHP 4 months ago Migrate-Packages 4 months ago Roles 4 months ago Templates 4 months ago Advanced-Content-Types.php 4 months ago Advanced-Relationships.php 4 months ago Markdown.php 4 months ago Pages.php 4 months ago Table-Storage.php 4 months ago
Pages.php
1937 lines
1 <?php
2 /**
3 * Name: Pages
4 *
5 * Menu Name: Pod Pages
6 *
7 * Description: Creates advanced URL structures using wildcards in order to enable the front-end display of Pods Advanced Content Types. Not recommended for use with other content types.
8 *
9 * Version: 2.3
10 *
11 * Category: Advanced
12 *
13 * Menu Page: edit.php?post_type=_pods_page
14 * Menu Add Page: post-new.php?post_type=_pods_page
15 *
16 * @package Pods\Components
17 * @subpackage Pages
18 */
19
20 // Don't load directly.
21 if ( ! defined( 'ABSPATH' ) ) {
22 die( '-1' );
23 }
24
25 use Pods\Whatsit\Field;
26 use Pods\Whatsit\Page;
27 use Pods\Whatsit\Storage;
28
29 if ( class_exists( 'Pods_Pages' ) ) {
30 return;
31 }
32
33 /**
34 * Class Pods_Pages
35 */
36 class Pods_Pages extends PodsComponent {
37
38 /**
39 * Current Pod Page
40 *
41 * @var array
42 *
43 * @since 2.0.0
44 */
45 public static $exists = null;
46
47 /**
48 * Object type
49 *
50 * @var string
51 *
52 * @since 2.0.0
53 */
54 private $object_type = '_pods_page';
55
56 /**
57 * Whether the page has been checked already
58 *
59 * @var bool
60 *
61 * @since 2.1.0
62 */
63 public static $checked = false;
64
65 /**
66 * Keep track of if pods_content has been called yet
67 *
68 * @var bool
69 *
70 * @since 2.3.0
71 */
72 public static $content_called = false;
73
74 /**
75 * The capability type.
76 *
77 * @link https://codex.wordpress.org/Function_Reference/register_post_type
78 * @var string
79 */
80 private $capability_type = 'pods_page';
81
82 /**
83 * {@inheritdoc}
84 */
85 public function init() {
86 if ( ! did_action( 'init' ) ) {
87 add_action( 'init', [ $this, 'register_config' ] );
88 } else {
89 $this->register_config();
90 }
91
92 add_shortcode( 'pods-content', [ $this, 'shortcode' ] );
93
94 add_filter( 'post_type_link', [ $this, 'post_type_link' ], 10, 2 );
95
96 if ( ! is_admin() ) {
97 add_action( 'load_textdomain', [ $this, 'page_check' ], 12 );
98 } else {
99 add_filter( 'post_updated_messages', [ $this, 'setup_updated_messages' ], 10, 1 );
100
101 add_action( 'add_meta_boxes_' . $this->object_type, [ $this, 'edit_page_form' ] );
102
103 add_filter( 'get_post_metadata', [ $this, 'get_meta' ], 10, 4 );
104 add_filter( 'update_post_metadata', [ $this, 'save_meta' ], 10, 4 );
105
106 add_action( 'pods_meta_save_pre_post__pods_page', [ $this, 'fix_filters' ], 10, 5 );
107 add_action( 'post_updated', [ $this, 'clear_cache' ], 10, 3 );
108 add_action( 'delete_post', [ $this, 'clear_cache' ], 10, 1 );
109 add_filter( 'post_row_actions', [ $this, 'remove_row_actions' ], 10, 2 );
110 add_filter( 'bulk_actions-edit-' . $this->object_type, [ $this, 'remove_bulk_actions' ] );
111
112 add_filter( 'builder_layout_filter_non_layout_post_types', [ $this, 'disable_builder_layout' ] );
113 }
114
115 add_filter( 'members_get_capabilities', [ $this, 'get_capabilities' ] );
116 }
117
118 /**
119 * Register the configuration for this object.
120 *
121 * @since 2.9.9
122 */
123 public function register_config() {
124 $args = [
125 'label' => 'Pod Pages',
126 'labels' => [ 'singular_name' => 'Pod Page' ],
127 'public' => false,
128 'can_export' => false,
129 'show_ui' => true,
130 'show_in_menu' => false,
131 'query_var' => false,
132 'rewrite' => false,
133 'has_archive' => false,
134 'hierarchical' => false,
135 'supports' => [ 'title', 'author', 'revisions' ],
136 'menu_icon' => pods_svg_icon( 'pods' ),
137 'delete_with_user' => false,
138 ];
139
140 if ( ! pods_is_admin() ) {
141 $args['capability_type'] = $this->capability_type;
142 }
143
144 $args = PodsInit::object_label_fix( $args, 'post_type', $this->object_type );
145
146 register_post_type( $this->object_type, apply_filters( 'pods_internal_register_post_type_object_page', $args ) );
147
148 $args = [
149 'internal' => true,
150 'type' => 'post_type',
151 'storage' => 'meta',
152 'name' => $this->object_type,
153 'label' => 'Pod Pages',
154 'label_singular' => 'Pod Page',
155 'description' => '',
156 'public' => 0,
157 'show_ui' => 1,
158 'rest_enable' => 0,
159 'supports_title' => 1,
160 'supports_editor' => 0,
161 'supports_author' => 1,
162 'supports_revisions' => 1,
163 ];
164
165 if ( ! pods_is_admin() ) {
166 $args['capability_type'] = 'custom';
167 $args['capability_type_custom'] = $this->capability_type;
168 }
169
170 pods_register_type( 'post_type', $this->object_type, $args );
171
172 $page_templates = static function () {
173 if ( ! function_exists( 'get_page_templates' ) ) {
174 include_once ABSPATH . 'wp-admin/includes/theme.php';
175 }
176
177 $wp_page_templates = apply_filters( 'pods_page_templates', get_page_templates() );
178
179 $page_templates = [];
180
181 foreach ( $wp_page_templates as $page_template => $file ) {
182 $page_templates[ $page_template . ' - ' . $file ] = $file;
183 }
184
185 $page_templates[ __( '-- Select a WP Page Template --', 'pods' ) ] = '';
186
187 $page_templates[ __( 'Custom (uses only Pod Page content)', 'pods' ) ] = '_custom';
188
189 if ( ! in_array( 'pods.php', $page_templates, true ) && locate_template( [ 'pods.php', false ] ) ) {
190 $page_templates[ __( 'Pods (Pods Default)', 'pods' ) . ' - pods.php' ] = 'pods.php';
191 }
192
193 if ( ! in_array( 'page.php', $page_templates, true ) && locate_template( [ 'page.php', false ] ) ) {
194 $page_templates[ __( 'Page (WP Default)', 'pods' ) . ' - page.php' ] = 'page.php';
195 }
196
197 if ( ! in_array( 'index.php', $page_templates, true ) && locate_template( [ 'index.php', false ] ) ) {
198 $page_templates[ __( 'Index (WP Fallback)', 'pods' ) . ' - index.php' ] = 'index.php';
199 }
200
201 ksort( $page_templates );
202
203 return array_flip( $page_templates );
204 };
205
206 $page_fields = [
207 [
208 'name' => 'page_title',
209 'label' => __( 'Page Title', 'pods' ),
210 'type' => 'text',
211 ],
212 [
213 'name' => 'code_php_notice',
214 'type' => 'html',
215 'html_content' => sprintf(
216 '
217 <div class="pods-ui-notice-admin pods-ui-notice-warning">
218 <p>⚠️&nbsp;&nbsp;%1$s</p>
219 <p><a href="%2$s" target="_blank" rel="noopener noreferrer">%3$s</a> | <a href="%4$s" target="_blank" rel="noopener noreferrer">%5$s</a></p>
220 </div>
221 ',
222 esc_html__( 'PHP detected, this feature is deprecated', 'pods' ),
223 'https://docs.pods.io/displaying-pods/pod-page-template-hierarchy-for-themes/',
224 esc_html__( 'Read more about file-based templates', 'pods' ),
225 admin_url( 'admin.php?page=pods-components' ),
226 esc_html__( 'Switch to file-based Pod Pages using our Migrate PHP into File-based templates component', 'pods' )
227 ),
228 'wildcard-on' => [
229 'code' => [
230 '\?>',
231 '<\?',
232 ],
233 ],
234 ],
235 [
236 'name' => 'code',
237 'label' => __( 'Page Code', 'pods' ),
238 'type' => 'code',
239 'attributes' => [
240 'id' => 'content',
241 ],
242 'label_options' => [
243 'attributes' => [
244 'for' => 'content',
245 ],
246 ],
247 ],
248 [
249 'name' => 'precode_notice',
250 'type' => 'html',
251 'html_content' => sprintf(
252 '
253 <div class="pods-ui-notice-admin pods-ui-notice-warning">
254 <p>⚠️&nbsp;&nbsp;%1$s</p>
255 <p><a href="%2$s" target="_blank" rel="noopener noreferrer">%3$s</a> | <a href="%4$s" target="_blank" rel="noopener noreferrer">%5$s</a></p>
256 </div>
257 ',
258 esc_html__( 'Precode detected, this feature is deprecated', 'pods' ),
259 'https://docs.pods.io/displaying-pods/pod-page-template-hierarchy-for-themes/',
260 esc_html__( 'Read more about file-based templates', 'pods' ),
261 admin_url( 'admin.php?page=pods-components' ),
262 esc_html__( 'Switch to file-based Pod Pages using our Migrate PHP into File-based templates component', 'pods' )
263 ),
264 'excludes-on' => [
265 'precode' => '',
266 ],
267 ],
268 [
269 'name' => 'precode',
270 'label' => __( 'Page Precode', 'pods' ),
271 'type' => 'code',
272 'help' => __( 'Precode will run before your theme outputs the page. It is expected that this value will be a block of PHP. You must open the PHP tag here, as we do not open it for you by default.', 'pods' ),
273 'excludes-on' => [
274 'precode' => '',
275 ],
276 ],
277 [
278 'name' => 'page_template',
279 'label' => __( 'Page Template', 'pods' ),
280 'default' => '',
281 'type' => 'pick',
282 'pick_object' => 'custom-simple',
283 'pick_format_type' => 'single',
284 'pick_format_single' => 'dropdown',
285 'data' => $page_templates,
286 'override_object_field' => true,
287 ],
288 ];
289
290 $associated_pods = static function () {
291 $associated_pods = [
292 0 => __( '-- Select a Pod --', 'pods' ),
293 ];
294
295 $all_pods = pods_api()->load_pods( [ 'labels' => true ] );
296
297 if ( ! empty( $all_pods ) ) {
298 foreach ( $all_pods as $pod_name => $pod_label ) {
299 $associated_pods[ $pod_name ] = $pod_label . ' (' . $pod_name . ')';
300 }
301 } else {
302 $associated_pods[0] = __( 'None Found', 'pods' );
303 }
304
305 return $associated_pods;
306 };
307
308 $association_fields = [
309 [
310 'name' => 'pod',
311 'label' => __( 'Associated Pod', 'pods' ),
312 'default' => 0,
313 'type' => 'pick',
314 'pick_object' => 'custom-simple',
315 'pick_format_type' => 'single',
316 'pick_format_single' => 'dropdown',
317 'placeholder' => __( 'Select Pod', 'pods' ),
318 'data' => $associated_pods,
319 'dependency' => true,
320 ],
321 [
322 'name' => 'pod_slug',
323 'label' => __( 'Wildcard Slug', 'pods' ),
324 'help' => __( 'Setting the Wildcard Slug is an easy way to setup a detail page. You can use the special tag {@url.2} to match the *third* level of the URL of a Pod Page named "first/second/*" part of the pod page. This is functionally the same as using pods_v_sanitized( 2, "url" ) in PHP.', 'pods' ),
325 'type' => 'text',
326 'excludes-on' => [ 'pod' => 0 ],
327 ],
328 ];
329
330 $restrict_fields = [
331 [
332 'name' => 'admin_only',
333 'label' => __( 'Restrict access to Admins', 'pods' ),
334 'default' => 0,
335 'type' => 'boolean',
336 'dependency' => true,
337 ],
338 [
339 'name' => 'restrict_role',
340 'label' => __( 'Restrict access by Role', 'pods' ),
341 'help' => [
342 __( '<h6>Roles</h6> Roles are assigned to users to provide them access to specific functionality in WordPress. Please see the Roles and Capabilities component in Pods for an easy tool to add your own roles and edit existing ones.', 'pods' ),
343 'http://codex.wordpress.org/Roles_and_Capabilities',
344 ],
345 'default' => 0,
346 'type' => 'boolean',
347 'dependency' => true,
348 ],
349 [
350 'name' => 'roles_allowed',
351 'label' => __( 'Role(s) Allowed', 'pods' ),
352 'type' => 'pick',
353 'pick_object' => 'role',
354 'pick_format_type' => 'multi',
355 'pick_format_multi' => 'autocomplete',
356 'pick_ajax' => false,
357 'default' => '',
358 'depends-on' => [
359 'pods_meta_restrict_role' => true,
360 ],
361 ],
362 [
363 'name' => 'restrict_capability',
364 'label' => __( 'Restrict access by Capability', 'pods' ),
365 'help' => [
366 __( '<h6>Capabilities</h6> Capabilities denote access to specific functionality in WordPress, and are assigned to specific User Roles. Please see the Roles and Capabilities component in Pods for an easy tool to add your own capabilities and roles.', 'pods' ),
367 'http://codex.wordpress.org/Roles_and_Capabilities',
368 ],
369 'default' => 0,
370 'type' => 'boolean',
371 'dependency' => true,
372 ],
373 [
374 'name' => 'capability_allowed',
375 'label' => __( 'Capability Allowed', 'pods' ),
376 'type' => 'pick',
377 'pick_object' => 'capability',
378 'pick_format_type' => 'multi',
379 'pick_format_multi' => 'autocomplete',
380 'pick_ajax' => false,
381 'default' => '',
382 'depends-on' => [
383 'pods_meta_restrict_capability' => true,
384 ],
385 ],
386 [
387 'name' => 'restrict_redirect',
388 'label' => __( 'Redirect if Restricted', 'pods' ),
389 'default' => 0,
390 'type' => 'boolean',
391 'dependency' => true,
392 ],
393 [
394 'name' => 'restrict_redirect_login',
395 'label' => __( 'Redirect to WP Login page', 'pods' ),
396 'default' => 0,
397 'type' => 'boolean',
398 'dependency' => true,
399 'depends-on' => [
400 'pods_meta_restrict_redirect' => true,
401 ],
402 ],
403 [
404 'name' => 'restrict_redirect_url',
405 'label' => __( 'Redirect to a Custom URL', 'pods' ),
406 'default' => '',
407 'type' => 'text',
408 'depends-on' => [
409 'pods_meta_restrict_redirect' => true,
410 'pods_meta_restrict_redirect_login' => false,
411 ],
412 ],
413 ];
414
415 pods_register_group(
416 [
417 'name' => 'pod-page',
418 'label' => __( 'Page', 'pods' ),
419 'description' => '',
420 'weight' => 0,
421 'meta_box_context' => 'normal',
422 'meta_box_priority' => 'high',
423 ],
424 $this->object_type,
425 $page_fields
426 );
427
428 pods_register_group(
429 [
430 'name' => 'pod-association',
431 'label' => __( 'Pod Association', 'pods' ),
432 'description' => '',
433 'weight' => 1,
434 'meta_box_context' => 'normal',
435 'meta_box_priority' => 'high',
436 ],
437 $this->object_type,
438 $association_fields
439 );
440
441 pods_register_group(
442 [
443 'name' => 'restrict-content',
444 'label' => __( 'Restrict Content', 'pods' ),
445 'description' => '',
446 'weight' => 2,
447 'meta_box_context' => 'normal',
448 'meta_box_priority' => 'high',
449 ],
450 $this->object_type,
451 $restrict_fields
452 );
453 }
454
455 /**
456 * @param $caps
457 *
458 * @return array
459 */
460 public function get_capabilities( $caps ) {
461
462 $caps = array_merge(
463 $caps, [
464 'edit_' . $this->capability_type,
465 'read_' . $this->capability_type,
466 'delete_' . $this->capability_type,
467 'edit_' . $this->capability_type . 's',
468 'edit_others_' . $this->capability_type . 's',
469 'publish_' . $this->capability_type . 's',
470 'read_private_' . $this->capability_type . 's',
471 'edit_' . $this->capability_type . 's',
472 ]
473 );
474
475 return $caps;
476 }
477
478 /**
479 * Pod Page Content Shortcode support for use anywhere that supports WP Shortcodes
480 *
481 * @param array $tags An associative array of shortcode properties
482 * @param string $content Not currently used
483 *
484 * @return string
485 * @since 2.3.9
486 */
487 public function shortcode( $tags, $content = null ) {
488
489 if ( ! isset( $tags['page'] ) || empty( $tags['page'] ) ) {
490 $tags['page'] = null;
491 }
492
493 $pods_page = self::exists( $tags['page'] );
494
495 if ( empty( $pods_page ) ) {
496 return '<p>Pods Page not found</p>';
497 }
498
499 return self::content( true, $pods_page );
500 }
501
502 /**
503 * Disable this Post Type from appearing in the Builder layouts list
504 *
505 * @param array $post_types
506 *
507 * @return array
508 */
509 public function disable_builder_layout( $post_types ) {
510
511 $post_types[] = $this->object_type;
512
513 return $post_types;
514 }
515
516 /**
517 * Update Post Type messages
518 *
519 * @param array $messages
520 *
521 * @return array
522 * @since 2.0.2
523 */
524 public function setup_updated_messages( $messages ) {
525
526 global $post, $post_ID;
527
528 $post_type = get_post_type_object( $this->object_type );
529
530 $labels = $post_type->labels;
531
532 $messages[ $post_type->name ] = [
533 // translators: %1$s is the singular label, %2$s is the permalink, %3$s is the view item label.
534 1 => sprintf( __( '%1$s updated. <a href="%2$s">%3$s</a>', 'pods' ), $labels->singular_name, esc_url( get_permalink( $post_ID ) ), $labels->view_item ),
535 2 => __( 'Custom field updated.', 'pods' ),
536 3 => __( 'Custom field deleted.', 'pods' ),
537 // translators: %s is the singular label.
538 4 => sprintf( __( '%s updated.', 'pods' ), $labels->singular_name ),
539 /* translators: %s: date and time of the revision */
540 5 => isset( $_GET['revision'] ) ? sprintf( __( '%1$s restored to revision from %2$s', 'pods' ), $labels->singular_name, wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
541 // translators: %1$s is the singular label, %2$s is the permalink, %3$s is the view item label.
542 6 => sprintf( __( '%1$s published. <a href="%2$s">%3$s</a>', 'pods' ), $labels->singular_name, esc_url( get_permalink( $post_ID ) ), $labels->view_item ),
543 // translators: %s is the singular label.
544 7 => sprintf( __( '%s saved.', 'pods' ), $labels->singular_name ),
545 // translators: %1$s is the singular label, %2$s is the preview link, %3$s is the singular label again.
546 8 => sprintf( __( '%1$s submitted. <a target="_blank" rel="noopener noreferrer" href="%2$s">Preview %3$s</a>', 'pods' ), $labels->singular_name, esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ), $labels->singular_name ),
547 9 => sprintf(
548 // translators: %1$s is the singular label, %2$s is the scheduled date, %3$s is the permalink, %4$s is the singular label again.
549 __( '%1$s scheduled for: <strong>%2$s</strong>. <a target="_blank" rel="noopener noreferrer" href="%3$s">Preview %4$s</a>', 'pods' ), $labels->singular_name,
550 // translators: Publish box date format, see http://php.net/date
551 date_i18n( __( 'M j, Y @ G:i', 'pods' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ), $labels->singular_name
552 ),
553 // translators: %1$s is the singular label, %2$s is the preview link, %3$s is the singular label again.
554 10 => sprintf( __( '%1$s draft updated. <a target="_blank" rel="noopener noreferrer" href="%2$s">Preview %3$s</a>', 'pods' ), $labels->singular_name, esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ), $labels->singular_name ),
555 ];
556
557 if ( false === (boolean) $post_type->public ) {
558 // translators: %s is the singular label.
559 $messages[ $post_type->name ][1] = sprintf( __( '%s updated.', 'pods' ), $labels->singular_name );
560 // translators: %s is the singular label.
561 $messages[ $post_type->name ][6] = sprintf( __( '%s published.', 'pods' ), $labels->singular_name );
562 // translators: %s is the singular label.
563 $messages[ $post_type->name ][8] = sprintf( __( '%s submitted.', 'pods' ), $labels->singular_name );
564 $messages[ $post_type->name ][9] = sprintf(
565 // translators: %1$s is the singular label, %2$s is the scheduled date.
566 __( '%1$s scheduled for: <strong>%2$s</strong>.', 'pods' ), $labels->singular_name,
567 // translators: Publish box date format, see http://php.net/date
568 date_i18n( __( 'M j, Y @ G:i', 'pods' ), strtotime( $post->post_date ) )
569 );
570 // translators: %s is the singular label.
571 $messages[ $post_type->name ][10] = sprintf( __( '%s draft updated.', 'pods' ), $labels->singular_name );
572 }
573
574 return $messages;
575 }
576
577 /**
578 * Enqueue styles
579 *
580 * @since 2.0.0
581 */
582 public function admin_assets() {
583 wp_enqueue_script( 'pods-dfv' );
584 wp_enqueue_style( 'pods-styles' );
585 }
586
587 /**
588 * Fix filters, specifically removing balanceTags
589 *
590 * @since 2.0.1
591 *
592 * @param $data
593 * @param null $pod
594 * @param null $id
595 * @param null $groups
596 * @param null $post
597 */
598 public function fix_filters( $data, $pod = null, $id = null, $groups = null, $post = null ) {
599
600 remove_filter( 'content_save_pre', 'balanceTags', 50 );
601 }
602
603 /**
604 * Remove unused row actions
605 *
606 * @since 2.0.5
607 *
608 * @param $actions
609 * @param $post
610 *
611 * @return
612 */
613 public function remove_row_actions( $actions, $post ) {
614
615 global $current_screen;
616
617 if ( ! is_object( $current_screen ) || $this->object_type != $current_screen->post_type ) {
618 return $actions;
619 }
620
621 if ( isset( $actions['view'] ) ) {
622 unset( $actions['view'] );
623 }
624
625 if ( isset( $actions['inline hide-if-no-js'] ) ) {
626 unset( $actions['inline hide-if-no-js'] );
627 }
628
629 // W3 Total Cache
630 if ( isset( $actions['pgcache_purge'] ) ) {
631 unset( $actions['pgcache_purge'] );
632 }
633
634 return $actions;
635 }
636
637 /**
638 * Remove unused bulk actions
639 *
640 * @since 2.0.5
641 *
642 * @param $actions
643 *
644 * @return
645 */
646 public function remove_bulk_actions( $actions ) {
647
648 if ( isset( $actions['edit'] ) ) {
649 unset( $actions['edit'] );
650 }
651
652 return $actions;
653 }
654
655 /**
656 * Clear cache on save
657 *
658 * @since 2.0.0
659 *
660 * @param $data
661 * @param null $pod
662 * @param null $id
663 * @param null $groups
664 * @param null $post
665 */
666 public function clear_cache( $data, $pod = null, $id = null, $groups = null, $post = null ) {
667
668 $old_post = $id;
669
670 if ( ! is_object( $id ) ) {
671 $old_post = null;
672 }
673
674 if ( ! is_array( $data ) && 0 < $data ) {
675 $post = $data;
676 $post = get_post( $post );
677 }
678
679 if ( ! is_object( $post ) || $this->object_type !== $post->post_type ) {
680 return;
681 }
682
683 pods_transient_clear( 'pods_object_pages' );
684
685 if ( $old_post instanceof WP_Post && $this->object_type === $old_post->post_type ) {
686 pods_cache_clear( $old_post->post_title, 'pods_object_page_wildcard' );
687 }
688
689 pods_cache_clear( $post->post_title, 'pods_object_page_wildcard' );
690
691 self::flush_rewrites();
692 }
693
694 /**
695 * Change post title placeholder text
696 *
697 * @since 2.0.0
698 *
699 * @param $text
700 * @param $post
701 *
702 * @return string
703 */
704 public function set_title_text( $text, $post ) {
705 return __( 'Enter URL here', 'pods' );
706 }
707
708 /**
709 * Edit page form
710 *
711 * @since 2.0.0
712 */
713 public function edit_page_form() {
714
715 global $post_type;
716
717 if ( $this->object_type !== $post_type ) {
718 return;
719 }
720
721 add_action( 'admin_enqueue_scripts', [ $this, 'admin_assets' ], 21 );
722 add_filter( 'enter_title_here', [ $this, 'set_title_text' ], 10, 2 );
723
724 $page_code = get_the_content();
725 $pre_code = get_post_meta( get_the_ID(), 'precode', true );
726
727 $has_php = false !== strpos( $page_code, '<?' );
728 $has_precode = ! empty( $pre_code );
729
730 if ( $has_php && pods_eval_show_errors() ) {
731 pods_deprecated( 'Pod Page PHP code has been deprecated, please use WP Page Templates or hook into the pods_content filter instead of embedding PHP.', '2.1' );
732
733 pods_message(
734 sprintf(
735 '
736 <p><strong>%1$s:</strong> %2$s</p>
737 <p><a href="%3$s" target="_blank" rel="noopener noreferrer">%4$s</a> | <a href="%5$s" target="_blank" rel="noopener noreferrer">%6$s</a></p>
738 ',
739 esc_html__( 'Pod Page Error', 'pods' ),
740 esc_html__( 'This Pod Page contains PHP code that will not run due to security restrictions in Pods.', 'pods' ),
741 'https://docs.pods.io/displaying-pods/pod-page-template-hierarchy-for-themes/',
742 esc_html__( 'Read more about file-based templates', 'pods' ),
743 admin_url( 'admin.php?page=pods-components' ),
744 esc_html__( 'Switch to file-based Pod Pages using our Migrate PHP into File-based templates component', 'pods' )
745 ),
746 'error',
747 false,
748 false
749 );
750 }
751
752 if ( $has_precode && pods_eval_show_errors() ) {
753 pods_deprecated( 'Pod Page precode has been deprecated, please use WP Page Templates or hook into the pods_content filter instead of embedding PHP.', '2.1' );
754
755 pods_message(
756 sprintf(
757 '
758 <p><strong>%1$s:</strong> %2$s</p>
759 <p><a href="%3$s" target="_blank" rel="noopener noreferrer">%4$s</a> | <a href="%5$s" target="_blank" rel="noopener noreferrer">%6$s</a></p>
760 ',
761 __( 'Pod Page Error', 'pods' ),
762 __( 'This Pod Page contains precode (deprecated) that will not run due to security restrictions in Pods.', 'pods' ),
763 'https://docs.pods.io/displaying-pods/pod-page-template-hierarchy-for-themes/',
764 esc_html__( 'Read more about file-based templates', 'pods' ),
765 admin_url( 'admin.php?page=pods-components' ),
766 esc_html__( 'Switch to file-based Pod Pages using our Migrate PHP into File-based templates component', 'pods' )
767 ),
768 'error',
769 false,
770 false
771 );
772 }
773
774 }
775
776 /**
777 * Filter permalinks and adjust for pod pages
778 *
779 * @param $post_link
780 * @param $post
781 *
782 * @return mixed
783 */
784 public function post_type_link( $post_link, $post ) {
785
786 if ( empty( $post ) || $this->object_type != $post->post_type ) {
787 return $post_link;
788 }
789
790 $post_link = get_site_url() . '/';
791
792 if ( false === strpos( $post->post_title, '*' ) ) {
793 $post_link .= trim( $post->post_title, '/ ' ) . '/';
794 }
795
796 return $post_link;
797 }
798
799 /**
800 * Get the fields
801 *
802 * @param null $_null
803 * @param int $post_ID
804 * @param string $meta_key
805 * @param bool $single
806 *
807 * @return array|bool|int|mixed|null|string|void
808 */
809 public function get_meta( $_null, $post_ID = null, $meta_key = null, $single = false ) {
810 if ( 'code' !== $meta_key ) {
811 return $_null;
812 }
813
814 $post = get_post( $post_ID );
815
816 if ( ! is_object( $post ) || $this->object_type !== $post->post_type ) {
817 return $_null;
818 }
819
820 return $post->post_content;
821 }
822
823 /**
824 * Save the fields
825 *
826 * @param $_null
827 * @param int $post_ID
828 * @param string $meta_key
829 * @param string $meta_value
830 *
831 * @return bool|int|null
832 */
833 public function save_meta( $_null, $post_ID = null, $meta_key = null, $meta_value = null ) {
834 if ( 'code' !== $meta_key ) {
835 return $_null;
836 }
837
838 $post = get_post( $post_ID );
839
840 if ( ! is_object( $post ) || $this->object_type !== $post->post_type ) {
841 return $_null;
842 }
843
844 $postdata = [
845 'ID' => $post_ID,
846 'post_content' => $meta_value,
847 ];
848
849 remove_filter( current_filter(), [ $this, __FUNCTION__ ] );
850
851 $revisions = false;
852
853 if ( has_action( 'pre_post_update', 'wp_save_post_revision' ) ) {
854 remove_action( 'pre_post_update', 'wp_save_post_revision' );
855
856 $revisions = true;
857 }
858
859 wp_update_post( (object) $postdata );
860
861 // Flush the find posts cache.
862 pods_cache_clear( true, 'pods_post_type_storage_' . $this->object_type );
863
864 // objects will be automatically sanitized
865 if ( $revisions ) {
866 add_action( 'pre_post_update', [ $this, 'save_post_revision_for_post' ] );
867 }
868
869 return true;
870 }
871
872 /**
873 * Save post revision for a post without a return.
874 *
875 * @since 3.2.8
876 *
877 * @param int $post_id The post ID.
878 */
879 public function save_post_revision_for_post( $post_id ) {
880 wp_save_post_revision( $post_id );
881 }
882
883 /**
884 * Flush Pod Page Rewrite cache
885 *
886 * @return array Pod Page Rewrites
887 *
888 * @since 2.3.4
889 */
890 public static function flush_rewrites() {
891
892 $args = [
893 'post_type' => '_pods_page',
894 'nopaging' => true,
895 'posts_per_page' => - 1,
896 'post_status' => 'publish',
897 'order' => 'ASC',
898 'orderby' => 'title',
899 ];
900
901 $pod_pages = get_posts( $args );
902
903 $pod_page_rewrites = [];
904
905 foreach ( $pod_pages as $pod_page ) {
906 $pod_page_rewrites[ $pod_page->ID ] = $pod_page->post_title;
907 }
908
909 uksort( $pod_page_rewrites, 'pods_page_length_sort' );
910
911 pods_transient_set( 'pods_object_page_rewrites', $pod_page_rewrites, WEEK_IN_SECONDS );
912
913 $pod_page_rewrites = array_flip( $pod_page_rewrites );
914
915 return $pod_page_rewrites;
916 }
917
918 /**
919 * Check to see if Pod Page exists and return data
920 *
921 * $uri not required, if NULL then returns REQUEST_URI matching Pod Page
922 *
923 * @param string $uri The Pod Page URI to check if exists
924 *
925 * @return array|bool
926 */
927 public static function exists( $uri = null ) {
928 if ( null === $uri ) {
929 $uri = pods_current_path();
930 }
931
932 if ( empty( $uri ) ) {
933 return false;
934 }
935
936 $uri = explode( '?', (string) $uri );
937 $uri = explode( '#', $uri[0] );
938 $uri = $uri[0];
939
940 $home_path = wp_parse_url( get_home_url(), PHP_URL_PATH );
941
942 if ( ! empty( $home_path ) && '/' !== $home_path ) {
943 $uri = substr( $uri, strlen( $home_path ) );
944 }
945
946 $uri = trim( $uri, '/' );
947 $uri_depth = count( array_filter( explode( '/', $uri ) ) ) - 1;
948
949 $pods_page_exclusions = [
950 'wp-admin',
951 'wp-content',
952 'wp-includes',
953 'index.php',
954 'wp-login.php',
955 'wp-signup.php',
956 ];
957
958 $pods_page_exclusions = apply_filters( 'pods_page_exclusions', $pods_page_exclusions );
959
960 if ( is_admin() || empty( $uri ) ) {
961 return false;
962 }
963
964 foreach ( $pods_page_exclusions as $exclusion ) {
965 if ( 0 === strpos( $uri, $exclusion ) ) {
966 return false;
967 }
968 }
969
970 $object = apply_filters( 'pods_page_exists', false, $uri );
971 if ( ! empty( $object ) ) {
972 return $object;
973 }
974
975 if ( false === strpos( $uri, '*' ) && ! apply_filters( 'pods_page_regex_matching', false ) ) {
976 $object = pods_by_title( $uri, ARRAY_A, '_pods_page', 'publish' );
977 }
978
979 $wildcard = false;
980
981 if ( empty( $object ) ) {
982 if ( false === strpos( $uri, '*' ) ) {
983 $object = pods_cache_get( $uri, 'pods_object_page_wildcard' );
984
985 if ( ! empty( $object ) ) {
986 return $object;
987 }
988 }
989
990 $pod_page_rewrites = pods_transient_get( 'pods_object_page_rewrites' );
991
992 if ( empty( $pod_page_rewrites ) ) {
993 $pod_page_rewrites = self::flush_rewrites();
994 } else {
995 $pod_page_rewrites = array_flip( $pod_page_rewrites );
996 }
997
998 $found_rewrite_page_id = 0;
999
1000 if ( ! empty( $pod_page_rewrites ) ) {
1001 foreach ( $pod_page_rewrites as $pod_page => $pod_page_id ) {
1002 if ( ! apply_filters( 'pods_page_regex_matching', false ) ) {
1003 if ( false === strpos( $pod_page, '*' ) ) {
1004 continue;
1005 }
1006
1007 $depth_check = strlen( $pod_page ) - strlen( str_replace( '/', '', $pod_page ) );
1008
1009 $pod_page = preg_quote( $pod_page, '/' );
1010
1011 $pod_page = str_replace( '\\*', '(.*)', $pod_page );
1012
1013 if ( $uri_depth == $depth_check && preg_match( '/^' . $pod_page . '$/', $uri ) ) {
1014 $found_rewrite_page_id = $pod_page_id;
1015
1016 break;
1017 }
1018 } elseif ( preg_match( '/^' . str_replace( '/', '\\/', $pod_page ) . '$/', $uri ) ) {
1019 $found_rewrite_page_id = $pod_page_id;
1020
1021 break;
1022 }//end if
1023 }//end foreach
1024
1025 if ( ! empty( $found_rewrite_page_id ) ) {
1026 $object = get_post( $found_rewrite_page_id, ARRAY_A );
1027
1028 if ( empty( $object ) || '_pods_page' !== $object['post_type'] ) {
1029 $object = false;
1030 }
1031 }
1032 }//end if
1033
1034 $wildcard = true;
1035 }//end if
1036
1037 if ( ! empty( $object ) ) {
1038 $object = [
1039 'id' => $object['ID'],
1040 'uri' => $object['post_title'],
1041 'code' => $object['post_content'],
1042 'phpcode' => $object['post_content'],
1043 // phpcode is deprecated
1044 'precode' => get_post_meta( $object['ID'], 'precode', true ),
1045 'page_template' => get_post_meta( $object['ID'], 'page_template', true ),
1046 'title' => get_post_meta( $object['ID'], 'page_title', true ),
1047 'options' => [
1048 'admin_only' => (boolean) get_post_meta( $object['ID'], 'admin_only', true ),
1049 'restrict_role' => (boolean) get_post_meta( $object['ID'], 'restrict_role', true ),
1050 'restrict_capability' => (boolean) get_post_meta( $object['ID'], 'restrict_capability', true ),
1051 'roles_allowed' => get_post_meta( $object['ID'], 'roles_allowed', true ),
1052 'capability_allowed' => get_post_meta( $object['ID'], 'capability_allowed', true ),
1053 'restrict_redirect' => (boolean) get_post_meta( $object['ID'], 'restrict_redirect', true ),
1054 'restrict_redirect_login' => (boolean) get_post_meta( $object['ID'], 'restrict_redirect_login', true ),
1055 'restrict_redirect_url' => get_post_meta( $object['ID'], 'restrict_redirect_url', true ),
1056 'pod' => get_post_meta( $object['ID'], 'pod', true ),
1057 'pod_slug' => get_post_meta( $object['ID'], 'pod_slug', true ),
1058 ],
1059 ];
1060
1061 if ( $wildcard ) {
1062 pods_cache_set( $uri, $object, 'pods_object_page_wildcard', 3600 );
1063 }
1064
1065 return $object;
1066 }//end if
1067
1068 return false;
1069 }
1070
1071 /**
1072 * Convert a Page object to a Pod Page data array.
1073 *
1074 * @since 3.2.8
1075 *
1076 * @param Page $object The Pod Page object.
1077 *
1078 * @return array The Pod Page data array.
1079 */
1080 public static function object_to_page( Page $object ): array {
1081 $id = $object->get_id();
1082
1083 return [
1084 'id' => $id,
1085 'name' => $object->get_name(),
1086 'uri' => $object->get_label(),
1087 'code' => $object->get_description(),
1088 'phpcode' => $object->get_description(),
1089 // phpcode is deprecated
1090 'precode' => get_post_meta( $id, 'precode', true ),
1091 'page_template' => get_post_meta( $id, 'page_template', true ),
1092 'title' => get_post_meta( $id, 'page_title', true ),
1093 'options' => [
1094 'admin_only' => (boolean) get_post_meta( $id, 'admin_only', true ),
1095 'restrict_role' => (boolean) get_post_meta( $id, 'restrict_role', true ),
1096 'restrict_capability' => (boolean) get_post_meta( $id, 'restrict_capability', true ),
1097 'roles_allowed' => get_post_meta( $id, 'roles_allowed', true ),
1098 'capability_allowed' => get_post_meta( $id, 'capability_allowed', true ),
1099 'restrict_redirect' => (boolean) get_post_meta( $id, 'restrict_redirect', true ),
1100 'restrict_redirect_login' => (boolean) get_post_meta( $id, 'restrict_redirect_login', true ),
1101 'restrict_redirect_url' => get_post_meta( $id, 'restrict_redirect_url', true ),
1102 'pod' => get_post_meta( $id, 'pod', true ),
1103 'pod_slug' => get_post_meta( $id, 'pod_slug', true ),
1104 ],
1105 ];
1106 }
1107
1108 /**
1109 * Check if a Pod Page exists
1110 */
1111 public function page_check() {
1112
1113 if ( self::$checked ) {
1114 return;
1115 }
1116
1117 global $pods;
1118
1119 // Fix any global confusion wherever this runs
1120 if ( isset( $pods ) && ! isset( $GLOBALS['pods'] ) ) {
1121 $GLOBALS['pods'] =& $pods;
1122 } elseif ( ! isset( $pods ) && isset( $GLOBALS['pods'] ) ) {
1123 $pods =& $GLOBALS['pods'];
1124 }
1125
1126 if ( ! defined( 'PODS_DISABLE_POD_PAGE_CHECK' ) || ! PODS_DISABLE_POD_PAGE_CHECK ) {
1127 if ( null === self::$exists ) {
1128 self::$exists = pod_page_exists();
1129 }
1130
1131 if ( false !== self::$exists ) {
1132 $pods = apply_filters( 'pods_global', $pods, self::$exists );
1133
1134 if ( ! is_wp_error( $pods ) && ( is_object( $pods ) || 404 != $pods ) ) {
1135 add_action( 'template_redirect', [ $this, 'template_redirect' ] );
1136 add_filter( 'redirect_canonical', '__return_false' );
1137 add_action( 'wp_head', [ $this, 'wp_head' ] );
1138 add_filter( 'wp_title', [ $this, 'wp_title' ], 0, 3 );
1139 add_filter( 'body_class', [ $this, 'body_class' ], 0, 1 );
1140 add_filter( 'status_header', [ $this, 'status_header' ] );
1141 add_action( 'after_setup_theme', [ $this, 'precode' ] );
1142 add_action( 'wp', [ $this, 'silence_404' ], 1 );
1143
1144 // Genesis theme integration.
1145 add_action( 'genesis_loop', [ $this, 'pods_page_content' ], 11 );
1146 }
1147 }
1148
1149 self::$checked = true;
1150 }//end if
1151 }
1152
1153 /**
1154 * Output Pdos Page content without return.
1155 *
1156 * @since 3.2.8
1157 */
1158 public function pods_page_content() {
1159 pods_content();
1160 }
1161
1162 /**
1163 * Output Pod Page Content
1164 *
1165 * @param bool $return Whether to return or not (default is to echo)
1166 *
1167 * @param bool $pods_page
1168 *
1169 * @return string|false
1170 */
1171 public static function content( $return = false, $pods_page = false ) {
1172
1173 if ( empty( $pods_page ) ) {
1174 $pods_page = self::$exists;
1175 }
1176
1177 $content = false;
1178
1179 if ( $pods_page == self::$exists && self::$content_called ) {
1180 return $content;
1181 }
1182
1183 if ( ! empty( $pods_page ) ) {
1184 /**
1185 * @var $pods \Pods
1186 */
1187 global $pods;
1188
1189 // Fix any global confusion wherever this runs
1190 if ( isset( $pods ) && ! isset( $GLOBALS['pods'] ) ) {
1191 $GLOBALS['pods'] =& $pods;
1192 } elseif ( ! isset( $pods ) && isset( $GLOBALS['pods'] ) ) {
1193 $pods =& $GLOBALS['pods'];
1194 }
1195
1196 if ( 0 < strlen( trim( $pods_page['code'] ) ) ) {
1197 $content = trim( $pods_page['code'] );
1198 }
1199
1200 ob_start();
1201
1202 do_action( 'pods_content_pre', $pods_page, $content );
1203
1204 $default_templates = self::get_templates_for_pod_page_content( $pods_page );
1205 $template_files_info = self::get_template_files_info( $default_templates );
1206
1207 $template_file = array_key_first( $template_files_info );
1208
1209 if ( $template_file ) {
1210 // Check if we are running this content function from within a Pod Page PHP template already to prevent recursion.
1211 if ( did_action( 'pods_page_loaded_template' ) ) {
1212 $content = '';
1213 } else {
1214 $content = pods_template_part( $template_file, compact( 'pods', 'pods_page' ), true );;
1215
1216 if ( $template_files_info[ $template_file ]['MagicTags'] ) {
1217 if ( is_object( $pods ) && ! empty( $pods->id ) ) {
1218 $content = $pods->do_magic_tags( $content );
1219 } else {
1220 _doing_it_wrong( 'Pods Pages', 'Pod Page template supports magic tags but cannot be processed because an associated Pod is not set in the Pod Page settings', '3.2.8' );
1221
1222 $content = '';
1223 }
1224 }
1225 }
1226
1227 echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1228 } elseif ( $content && 0 < strlen( $content ) ) {
1229 if ( false !== strpos( $content, '<?' ) ) {
1230 /**
1231 * Allow evaluating Pod Pages content by custom code snippet if needed.
1232 *
1233 * @since 3.3.0
1234 *
1235 * @param array $pods_page The Pod Page data.
1236 * @param Pods $pods The Pods instance.
1237 * @param string $content The content of the Pod Page.
1238 */
1239 do_action( 'pods_pages_eval_content', $pods_page, $pods, $content );
1240 } elseif ( is_object( $pods ) && ! empty( $pods->id ) ) {
1241 echo $pods->do_magic_tags( $content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1242 } else {
1243 echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1244 }
1245 }
1246
1247 do_action( 'pods_content_post', $pods_page, $content );
1248
1249 $content = ob_get_clean();
1250
1251 if ( $pods_page == self::$exists ) {
1252 self::$content_called = true;
1253 }
1254 }//end if
1255
1256 $content = apply_filters( 'pods_content', $content, $pods_page );
1257
1258 if ( $return ) {
1259 return $content;
1260 }
1261
1262 echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1263
1264 return '';
1265 }
1266
1267 /**
1268 * Run any precode for current Pod Page
1269 */
1270 public function precode() {
1271
1272 global $pods;
1273
1274 // Fix any global confusion wherever this runs
1275 if ( isset( $pods ) && ! isset( $GLOBALS['pods'] ) ) {
1276 $GLOBALS['pods'] =& $pods;
1277 } elseif ( ! isset( $pods ) && isset( $GLOBALS['pods'] ) ) {
1278 $pods =& $GLOBALS['pods'];
1279 }
1280
1281 if ( false !== self::$exists ) {
1282 $permission = pods_permission( self::$exists );
1283
1284 $permission = (boolean) apply_filters( 'pods_pages_permission', $permission, self::$exists );
1285
1286 if ( $permission ) {
1287 $content = false;
1288
1289 if ( ! is_object( $pods ) && 404 != $pods && 0 < strlen( (string) pods_v( 'pod', self::$exists['options'] ) ) ) {
1290 $slug = pods_v( 'pod_slug', self::$exists['options'], null, null, true );
1291
1292 $has_slug = 0 < strlen( $slug );
1293
1294 // Handle special magic tags
1295 if ( $has_slug ) {
1296 $slug = pods_evaluate_tags( $slug, true );
1297 }
1298
1299 $pods = pods_get_instance( pods_v_sanitized( 'pod', self::$exists['options'] ), $slug );
1300
1301 // Auto 404 handling if item doesn't exist
1302 if ( $has_slug && ( empty( $slug ) || ! $pods->exists() ) && apply_filters( 'pods_pages_auto_404', true, $slug, $pods, self::$exists ) ) {
1303 $pods = 404;
1304 }
1305 }
1306
1307 if ( 0 < strlen( trim( self::$exists['precode'] ) ) ) {
1308 $content = trim( self::$exists['precode'] );
1309 }
1310
1311 do_action( 'pods_page_precode', self::$exists, $pods, $content );
1312 } elseif ( self::$exists['options']['restrict_redirect'] ) {
1313 $redirect_url = '';
1314
1315 if ( self::$exists['options']['restrict_redirect_login'] ) {
1316 $redirect_url = wp_login_url( pods_current_url() );
1317 } elseif ( ! empty( self::$exists['options']['restrict_redirect_url'] ) ) {
1318 $redirect_url = self::$exists['options']['restrict_redirect_url'];
1319 }
1320
1321 if ( ! empty( $redirect_url ) ) {
1322 wp_safe_redirect( $redirect_url );
1323 die();
1324 }
1325 }//end if
1326
1327 if ( ! $permission || ( ! is_object( $pods ) && ( 404 == $pods || is_wp_error( $pods ) ) ) ) {
1328 remove_action( 'template_redirect', [ $this, 'template_redirect' ] );
1329 remove_action( 'wp_head', [ $this, 'wp_head' ] );
1330 remove_filter( 'redirect_canonical', '__return_false' );
1331 remove_filter( 'wp_title', [ $this, 'wp_title' ] );
1332 remove_filter( 'body_class', [ $this, 'body_class' ] );
1333 remove_filter( 'status_header', [ $this, 'status_header' ] );
1334 remove_action( 'wp', [ $this, 'silence_404' ], 1 );
1335 }
1336 }//end if
1337 }
1338
1339 /**
1340 *
1341 */
1342 public function wp_head() {
1343
1344 global $pods;
1345
1346 do_action( 'pods_wp_head' );
1347
1348 if ( ! defined( 'PODS_DISABLE_VERSION_OUTPUT' ) || ! PODS_DISABLE_VERSION_OUTPUT ) {
1349 ?>
1350 <!-- Pods Framework <?php echo esc_html( PODS_VERSION ); ?> -->
1351 <?php
1352 }
1353 if ( ( ! defined( 'PODS_DISABLE_META' ) || ! PODS_DISABLE_META ) && is_object( $pods ) && ! is_wp_error( $pods ) ) {
1354
1355 if ( isset( $pods->meta ) && is_array( $pods->meta ) && ! empty( $pods->meta ) ) {
1356 foreach ( $pods->meta as $name => $content ) {
1357 if ( 'title' === $name ) {
1358 continue;
1359 }
1360 ?>
1361 <meta name="<?php echo esc_attr( $name ); ?>" content="<?php echo esc_attr( $content ); ?>" />
1362 <?php
1363 }
1364 }
1365
1366 if ( isset( $pods->meta_properties ) && is_array( $pods->meta_properties ) && ! empty( $pods->meta_properties ) ) {
1367 foreach ( $pods->meta_properties as $property => $content ) {
1368 ?>
1369 <meta property="<?php echo esc_attr( $property ); ?>"
1370 content="<?php echo esc_attr( $content ); ?>" />
1371 <?php
1372 }
1373 }
1374
1375 if ( isset( $pods->meta_extra ) && 0 < strlen( $pods->meta_extra ) ) {
1376 echo $pods->meta_extra; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1377 }
1378 }//end if
1379 }
1380
1381 /**
1382 * @param $title
1383 * @param $sep
1384 * @param $seplocation
1385 *
1386 * @return mixed|void
1387 */
1388 public function wp_title( $title, $sep, $seplocation ) {
1389
1390 global $pods;
1391
1392 $page_title = trim( self::$exists['title'] );
1393
1394 if ( 0 < strlen( $page_title ) ) {
1395 if ( is_object( $pods ) && ! is_wp_error( $pods ) ) {
1396 $page_title = $pods->do_magic_tags( $page_title );
1397 }
1398
1399 $title = ( 'right' === $seplocation ) ? "{$page_title} {$sep} " : " {$sep} {$page_title}";
1400 } elseif ( strlen( trim( (string) $title ) ) < 1 ) {
1401 $uri = explode( '?', $_SERVER['REQUEST_URI'] );
1402 $uri = preg_replace( '@^([/]?)(.*?)([/]?)$@', '$2', $uri[0] );
1403 $uri = preg_replace( '@(-|_)@', ' ', $uri );
1404 $uri = explode( '/', $uri );
1405
1406 $title = '';
1407
1408 foreach ( $uri as $key => $page_title ) {
1409 $title .= ( 'right' === $seplocation ) ? ucwords( $page_title ) . " {$sep} " : " {$sep} " . ucwords( $page_title );
1410 }
1411 }
1412
1413 if ( ( ! defined( 'PODS_DISABLE_META' ) || ! PODS_DISABLE_META ) && is_object( $pods ) && ! is_wp_error( $pods ) && isset( $pods->meta ) && is_array( $pods->meta ) && isset( $pods->meta['title'] ) ) {
1414 $title = $pods->meta['title'];
1415 }
1416
1417 return apply_filters( 'pods_title', $title, $sep, $seplocation, self::$exists );
1418 }
1419
1420 /**
1421 * @param $classes
1422 *
1423 * @return mixed|void
1424 */
1425 public function body_class( $classes ) {
1426
1427 global $pods;
1428
1429 if ( defined( 'PODS_DISABLE_BODY_CLASSES' ) && PODS_DISABLE_BODY_CLASSES ) {
1430 return $classes;
1431 }
1432
1433 $classes[] = 'pods';
1434
1435 $uri = explode( '?', self::$exists['uri'] );
1436 $uri = explode( '#', $uri[0] );
1437
1438 $class = str_replace( [ '*', '/' ], [ '_w_', '-' ], $uri[0] );
1439 $class = sanitize_title( $class );
1440 $class = str_replace( [ '_', '--', '--' ], '-', $class );
1441 $class = trim( $class, '-' );
1442
1443 $classes[] = 'pod-page-' . $class;
1444
1445 if ( is_object( $pods ) && ! is_wp_error( $pods ) ) {
1446 $class = sanitize_title( $pods->pod );
1447 $class = str_replace( [ '_', '--', '--' ], '-', $class );
1448 $class = trim( $class, '-' );
1449 $classes[] = 'pod-' . $class;
1450 }
1451
1452 if ( is_object( $pods ) && ! is_wp_error( $pods ) && isset( $pods->body_classes ) ) {
1453 $classes[] = $pods->body_classes;
1454 }
1455
1456 return apply_filters( 'pods_body_class', $classes, $uri );
1457 }
1458
1459 /**
1460 * @return string
1461 */
1462 public function status_header() {
1463
1464 return $_SERVER['SERVER_PROTOCOL'] . ' 200 OK';
1465 }
1466
1467 /**
1468 *
1469 */
1470 public function silence_404() {
1471
1472 global $wp_query;
1473
1474 $wp_query->query_vars['error'] = '';
1475 $wp_query->is_404 = false;
1476 }
1477
1478 /**
1479 * Handle overriding the template used for a Pods Page.
1480 *
1481 * @since 2.8.11
1482 *
1483 * @param string $original_template The template to include.
1484 *
1485 * @return string The template to include.
1486 */
1487 public function template_include( $original_template ) {
1488 global $pods;
1489
1490 // Default to original template if pod page was not found.
1491 $template = $original_template;
1492
1493 if ( false !== self::$exists ) {
1494 /*
1495 * Create pods.php in your theme directory, and
1496 * style it to suit your needs. Some helpful functions:
1497 *
1498 * get_header()
1499 * pods_content()
1500 * get_sidebar()
1501 * get_footer()
1502 */
1503 $template = self::$exists['page_template'];
1504 $template = apply_filters( 'pods_page_template', $template, self::$exists );
1505
1506 $render_function = apply_filters( 'pods_template_redirect', null, $template, self::$exists );
1507
1508 if ( '_custom' === $template ) {
1509 pods_content();
1510 die();
1511 } elseif ( null !== $render_function && is_callable( $render_function ) ) {
1512 call_user_func( $render_function, $template, self::$exists );
1513 die();
1514 } elseif ( ( ! defined( 'PODS_DISABLE_DYNAMIC_TEMPLATE' ) || ! PODS_DISABLE_DYNAMIC_TEMPLATE ) && is_object( $pods ) && ! is_wp_error( $pods ) && ! empty( $pods->page_template ) ) {
1515 $template = $pods->page_template;
1516 // found the template and included it, we're good to go!
1517 } elseif ( ! empty( self::$exists['page_template'] ) ) {
1518 $template = self::$exists['page_template'];
1519 // found the template and included it, we're good to go!
1520 } else {
1521 $located_template = apply_filters( 'pods_page_locate_template', $template, self::$exists );
1522
1523 if ( $template !== $located_template ) {
1524 $template = $located_template;
1525 } else {
1526 $default_templates = self::get_templates_for_pod_page( self::$exists );
1527
1528 $template = locate_template( $default_templates );
1529
1530 if ( '' !== $template ) {
1531 /**
1532 * Allow determining whether a Pod Page template was loaded.
1533 *
1534 * @since 3.2.8
1535 *
1536 * @param string $template The template file that was loaded.
1537 * @param array $pod_page The Pods Page data.
1538 */
1539 do_action( 'pods_page_loaded_template', $template, self::$exists );
1540
1541 pods_template_part( $template, compact( 'pods' ) );
1542 } else {
1543 $template = false;
1544
1545 // templates not found in theme, default output
1546 do_action( 'pods_page_default', $template, self::$exists );
1547
1548 get_header();
1549 pods_content();
1550 get_sidebar();
1551 get_footer();
1552 die();
1553 }
1554 }//end if
1555 }//end if
1556 }
1557
1558 /**
1559 * Allow filtering the template to include for a Pods Page.
1560 *
1561 * @since 2.8.11
1562 *
1563 * @param string $template The template to use.
1564 * @param array $exists The Pods Page data.
1565 */
1566 $template = apply_filters( 'pods_page_template_include', $template, self::$exists );
1567
1568 // Attempt to set up a basic WP post object.
1569 if ( $template !== $original_template && function_exists( '\Roots\bootloader' ) && function_exists( 'resource_path' ) ) {
1570 $paths_to_check = [
1571 get_theme_file_path( '/resources/views' ),
1572 get_parent_theme_file_path( '/resources/views' ),
1573 resource_path( 'views' ),
1574 ];
1575
1576 foreach ( $paths_to_check as $path_to_check ) {
1577 $file_path = $path_to_check . DIRECTORY_SEPARATOR . $template;
1578
1579 if ( file_exists( $file_path ) ) {
1580 $template = $file_path;
1581
1582 break;
1583 }
1584 }
1585 }
1586
1587 return $template;
1588 }
1589
1590 /**
1591 *
1592 */
1593 public function template_redirect() {
1594 global $pods;
1595
1596 // Support the Sage theme, eventually we can implement template_include everywhere else after more testing.
1597 if ( function_exists( '\Roots\bootloader' ) ) {
1598 if ( ! empty( $pods ) && 0 < $pods->id() && 'post_type' === $pods->pod_data['type'] ) {
1599 // Set up the post object using the pod.
1600 query_posts( 'p=' . $pods->id() . '&post_type=' . $pods->pod_data['name'] ); // phpcs:ignore WordPress.WP.DiscouragedFunctions.query_posts_query_posts
1601
1602 $pod_post = get_post( $pods->id() );
1603
1604 if ( $pod_post ) {
1605 setup_postdata( $pod_post );
1606 }
1607 } elseif ( null === get_queried_object() ) {
1608 // Maybe set up the post using the front page for now.
1609 $front_page = (int) get_option( 'page_on_front' );
1610
1611 if ( 0 < $front_page ) {
1612 query_posts( 'page_id=' . $front_page ); // phpcs:ignore WordPress.WP.DiscouragedFunctions.query_posts_query_posts
1613
1614 $front_page_post = get_post( $front_page );
1615
1616 if ( $front_page_post ) {
1617 setup_postdata( $front_page_post );
1618 }
1619 }
1620 }
1621
1622 add_filter( 'template_include', [ $this, 'template_include' ] );
1623
1624 return;
1625 }
1626
1627 if ( false !== self::$exists ) {
1628 /*
1629 * Create pods.php in your theme directory, and
1630 * style it to suit your needs. Some helpful functions:
1631 *
1632 * get_header()
1633 * pods_content()
1634 * get_sidebar()
1635 * get_footer()
1636 */
1637 $template = self::$exists['page_template'];
1638 $template = apply_filters( 'pods_page_template', $template, self::$exists );
1639
1640 $render_function = apply_filters( 'pods_template_redirect', null, $template, self::$exists );
1641
1642 do_action( 'pods_page', $template, self::$exists );
1643
1644 if ( '_custom' === $template ) {
1645 pods_content();
1646 } elseif ( null !== $render_function && is_callable( $render_function ) ) {
1647 call_user_func( $render_function, $template, self::$exists );
1648 } elseif ( ( ! defined( 'PODS_DISABLE_DYNAMIC_TEMPLATE' ) || ! PODS_DISABLE_DYNAMIC_TEMPLATE ) && is_object( $pods ) && ! is_wp_error( $pods ) && isset( $pods->page_template ) && ! empty( $pods->page_template ) && '' != locate_template( [ $pods->page_template ], true ) ) {
1649 $template = $pods->page_template;
1650 // found the template and included it, we're good to go!
1651 } elseif ( ! empty( self::$exists['page_template'] ) && '' != locate_template( [ self::$exists['page_template'] ], true ) ) {
1652 $template = self::$exists['page_template'];
1653 // found the template and included it, we're good to go!
1654 } else {
1655 $located_template = apply_filters( 'pods_page_locate_template', $template, self::$exists );
1656
1657 if ( $template !== $located_template ) {
1658 $template = $located_template;
1659 } else {
1660 $default_templates = self::get_templates_for_pod_page( self::$exists );
1661
1662 $template = locate_template( $default_templates );
1663
1664 if ( '' !== $template ) {
1665 /**
1666 * Allow determining whether a Pod Page template was loaded.
1667 *
1668 * @since 3.2.8
1669 *
1670 * @param string $template The template file that was loaded.
1671 * @param array $pod_page The Pods Page data.
1672 */
1673 do_action( 'pods_page_loaded_template', $template, self::$exists );
1674
1675 pods_template_part( $template, compact( 'pods' ) );
1676 } else {
1677 $template = false;
1678
1679 // templates not found in theme, default output
1680 do_action( 'pods_page_default', $template, self::$exists );
1681
1682 get_header();
1683 pods_content();
1684 get_sidebar();
1685 get_footer();
1686 }
1687 }//end if
1688 }//end if
1689
1690 do_action( 'pods_page_end', $template, self::$exists );
1691
1692 exit;
1693 }//end if
1694 }
1695
1696 /**
1697 * Get templates for pod page.
1698 *
1699 * @since 3.2.8
1700 *
1701 * @param array|Page $pod_page The pod page data.
1702 *
1703 * @return array The list of templates for the pod page.
1704 */
1705 public static function get_templates_for_pod_page( $pod_page ): array {
1706 if ( $pod_page instanceof Page ) {
1707 $pod_page = self::object_to_page( $pod_page );
1708 }
1709
1710 $default_templates = [];
1711
1712 if ( ! empty( $pod_page ) ) {
1713 $uri = explode( '?', $pod_page['uri'] );
1714 $uri = explode( '#', $uri[0] );
1715 $uri = $uri[0];
1716
1717 $page_path = explode( '/', $uri );
1718
1719 while ( $last = array_pop( $page_path ) ) {
1720 $file_name = str_replace( '*', '-w-', implode( '/', $page_path ) . '/' . $last );
1721 $file_name = sanitize_title( $file_name );
1722 $file_name = trim( str_replace( '--', '-', $file_name ), ' -' );
1723
1724 $default_templates[] = 'pods/pages/' . $file_name . '.php';
1725 $default_templates[] = 'pods/' . $file_name . '.php';
1726 $default_templates[] = 'pods-' . $file_name . '.php';
1727 }
1728 }
1729
1730 $default_templates[] = 'pods.php';
1731
1732 /**
1733 * Allow filtering the list of default templates.
1734 *
1735 * @since unknown
1736 *
1737 * @param array $default_templates The list of default templates.
1738 * @param array $pod_page The current Pod Page data.
1739 */
1740 return (array) apply_filters( 'pods_page_default_templates', $default_templates, $pod_page );
1741 }
1742
1743 /**
1744 * Get templates for pod page content.
1745 *
1746 * @since 3.2.8
1747 *
1748 * @param array|Page $pod_page The pod page data.
1749 *
1750 * @return array The list of templates for the pod page content.
1751 */
1752 public static function get_templates_for_pod_page_content( $pod_page ): array {
1753 if ( $pod_page instanceof Page ) {
1754 $pod_page = self::object_to_page( $pod_page );
1755 }
1756
1757 $default_templates = [];
1758
1759 if ( ! empty( $pod_page ) ) {
1760 $uri = explode( '?', $pod_page['uri'] );
1761 $uri = explode( '#', $uri[0] );
1762 $uri = $uri[0];
1763
1764 $page_path = explode( '/', $uri );
1765
1766 while ( $last = array_pop( $page_path ) ) {
1767 $file_name = str_replace( '*', '-w-', implode( '/', $page_path ) . '/' . $last );
1768 $file_name = sanitize_title( $file_name );
1769 $file_name = trim( str_replace( '--', '-', $file_name ), ' -' );
1770
1771 $default_templates[] = 'pods/pages/content/' . $file_name . '.php';
1772 }
1773 }
1774
1775 /**
1776 * Allow filtering the list of default templates for Pod Page content.
1777 *
1778 * @since unknown
1779 *
1780 * @param array $default_templates The list of default templates for Pod Page content.
1781 * @param array $pod_page The current Pod Page data.
1782 */
1783 return (array) apply_filters( 'pods_page_content_default_templates', $default_templates, $pod_page );
1784 }
1785
1786 /**
1787 * Get the list of template header information for each of the template files.
1788 *
1789 * @since 3.2.8
1790 *
1791 * @param array<int,string> $template_files The list of template files.
1792 *
1793 * @return array The list of template header information for each of the template files.
1794 */
1795 public static function get_template_files_info( array $template_files ): array {
1796 $template_files_info = [];
1797
1798 foreach ( $template_files as $template_file ) {
1799 $file_path = locate_template( $template_file );
1800
1801 // Skip if template was not found.
1802 if ( '' === $file_path ) {
1803 continue;
1804 }
1805
1806 $data = get_file_data( $file_path, [
1807 'URI' => 'Pod Page URI',
1808 'MagicTags' => 'Magic Tags',
1809 ] );
1810
1811 $data['MagicTags'] = pods_is_truthy( $data['MagicTags'] );
1812
1813 $template_files_info[ $template_file ] = $data;
1814 }
1815
1816 return $template_files_info;
1817 }
1818 }
1819
1820 /**
1821 * Find out if the current page is a Pod Page
1822 *
1823 * @param string $uri The Pod Page URI to check if currently on
1824 *
1825 * @return bool
1826 * @since 1.7.5
1827 */
1828 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1829 function is_pod_page( $uri = null ) {
1830
1831 if ( false !== Pods_Pages::$exists && ( null === $uri || $uri == Pods_Pages::$exists['uri'] || $uri == Pods_Pages::$exists['id'] ) ) {
1832 return true;
1833 }
1834
1835 return false;
1836 }
1837
1838 /**
1839 * Check for a specific page template for the current pod page
1840 *
1841 * @param string $template The theme template file
1842 *
1843 * @return bool
1844 * @since 2.3.7
1845 */
1846 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1847 function is_pod_page_template( $template = null ) {
1848
1849 if ( false !== Pods_Pages::$exists && $template == Pods_Pages::$exists['page_template'] ) {
1850 return true;
1851 }
1852
1853 return false;
1854 }
1855
1856 /**
1857 * Get the current Pod Page URI
1858 *
1859 * @return string|bool
1860 * @since 2.3.3
1861 */
1862 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1863 function get_pod_page_uri() {
1864
1865 $pod_page = Pods_Pages::exists();
1866
1867 if ( ! empty( $pod_page ) ) {
1868 return $pod_page['uri'];
1869 }
1870
1871 return false;
1872 }
1873
1874 /**
1875 * Check to see if Pod Page exists and return data
1876 *
1877 * $uri not required, if NULL then returns REQUEST_URI matching Pod Page
1878 *
1879 * @param string $uri The Pod Page URI to check if exists
1880 *
1881 * @return array
1882 *
1883 * @since 1.7.5
1884 */
1885 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1886 function pod_page_exists( $uri = null ) {
1887 return Pods_Pages::exists( $uri );
1888 }
1889
1890 /**
1891 * Output Pod Page Content
1892 *
1893 * @param bool $return Whether to return or not (default is to echo)
1894 *
1895 * @param bool $pods_page
1896 *
1897 * @return string
1898 * @since 1.7.0
1899 */
1900 function pods_content( $return = false, $pods_page = false ) {
1901
1902 return Pods_Pages::content( $return, $pods_page );
1903 }
1904
1905 /**
1906 * Sort an array by length of items, descending, for use with uksort()
1907 *
1908 * @param string $a First array item
1909 * @param string $b Second array item
1910 *
1911 * @return int Length difference
1912 *
1913 * @since 2.3.4
1914 */
1915 function pods_page_length_sort( $a, $b ) {
1916
1917 return strlen( $b ) - strlen( $a );
1918 }
1919
1920 /**
1921 * Flush Pod Page Rewrite cache
1922 *
1923 * @return array Pod Page Rewrites
1924 *
1925 * @since 2.3.4
1926 */
1927 function pods_page_flush_rewrites() {
1928
1929 return Pods_Pages::flush_rewrites();
1930 }
1931
1932 /*
1933 * Deprecated global variable
1934 */
1935 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
1936 $GLOBALS['pod_page_exists'] =& Pods_Pages::$exists;
1937