Issues (2873)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

components/Pages.php (49 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 26 and the first side effect is on line 20.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Name: Pages
4
 *
5
 * Description: Creates advanced URL structures using wildcards in order to enable the front-end display of Pods
6
 * Advanced Content Types. Not recommended for use with other content types.
7
 *
8
 * Version: 2.3
9
 *
10
 * Category: Advanced
11
 *
12
 * Menu Page: edit.php?post_type=_pods_page
13
 * Menu Add Page: post-new.php?post_type=_pods_page
14
 *
15
 * @package    Pods\Components
16
 * @subpackage Pages
17
 */
18
19
if ( class_exists( 'Pods_Pages' ) ) {
20
	return;
21
}
22
23
/**
24
 * Class Pods_Pages
25
 */
26
class Pods_Pages extends PodsComponent {
27
28
	/**
29
	 * Current Pod Page
30
	 *
31
	 * @var array
32
	 *
33
	 * @since 2.0
34
	 */
35
	public static $exists = null;
36
37
	/**
38
	 * Object type
39
	 *
40
	 * @var string
41
	 *
42
	 * @since 2.0
43
	 */
44
	private $object_type = '_pods_page';
45
46
	/**
47
	 * Whether the page has been checked already
48
	 *
49
	 * @var bool
50
	 *
51
	 * @since 2.1
52
	 */
53
	public static $checked = false;
54
55
	/**
56
	 * Keep track of if pods_content has been called yet
57
	 *
58
	 * @var bool
59
	 *
60
	 * @since 2.3
61
	 */
62
	public static $content_called = false;
63
64
	/**
65
	 * The capability type.
66
	 *
67
	 * @link https://codex.wordpress.org/Function_Reference/register_post_type
68
	 * @var string
69
	 */
70
	private $capability_type = 'pods_page';
71
72
	/**
73
	 * {@inheritdoc}
74
	 */
75
	public function init() {
76
77
		add_shortcode( 'pods-content', array( $this, 'shortcode' ) );
78
79
		$args = array(
80
			'label'        => 'Pod Pages',
81
			'labels'       => array( 'singular_name' => 'Pod Page' ),
82
			'public'       => false,
83
			'can_export'   => false,
84
			'show_ui'      => true,
85
			'show_in_menu' => false,
86
			'query_var'    => false,
87
			'rewrite'      => false,
88
			'has_archive'  => false,
89
			'hierarchical' => false,
90
			'supports'     => array( 'title', 'author', 'revisions' ),
91
			'menu_icon'    => 'dashicons-pods',
92
		);
93
94
		if ( ! pods_is_admin() ) {
95
			$args['capability_type'] = $this->capability_type;
96
		}
97
98
		$args = PodsInit::object_label_fix( $args, 'post_type' );
99
100
		register_post_type( $this->object_type, apply_filters( 'pods_internal_register_post_type_object_page', $args ) );
101
102
		add_filter( 'post_type_link', array( $this, 'post_type_link' ), 10, 2 );
103
104
		if ( ! is_admin() ) {
105
			add_action( 'load_textdomain', array( $this, 'page_check' ), 12 );
106
		} else {
107
			add_filter( 'post_updated_messages', array( $this, 'setup_updated_messages' ), 10, 1 );
108
109
			add_action( 'dbx_post_advanced', array( $this, 'edit_page_form' ) );
110
111
			add_action( 'pods_meta_groups', array( $this, 'add_meta_boxes' ) );
112
			add_filter( 'get_post_metadata', array( $this, 'get_meta' ), 10, 4 );
113
			add_filter( 'update_post_metadata', array( $this, 'save_meta' ), 10, 4 );
114
115
			add_action( 'pods_meta_save_pre_post__pods_page', array( $this, 'fix_filters' ), 10, 5 );
116
			add_action( 'post_updated', array( $this, 'clear_cache' ), 10, 3 );
117
			add_action( 'delete_post', array( $this, 'clear_cache' ), 10, 1 );
118
			add_filter( 'post_row_actions', array( $this, 'remove_row_actions' ), 10, 2 );
119
			add_filter( 'bulk_actions-edit-' . $this->object_type, array( $this, 'remove_bulk_actions' ) );
120
121
			add_filter( 'builder_layout_filter_non_layout_post_types', array( $this, 'disable_builder_layout' ) );
122
		}
123
124
		add_filter( 'members_get_capabilities', array( $this, 'get_capabilities' ) );
125
	}
126
127
	/**
128
	 * @param $caps
129
	 *
130
	 * @return array
0 ignored issues
show
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
131
	 */
132
	public function get_capabilities( $caps ) {
133
134
		$caps = array_merge(
135
			$caps, array(
136
				'edit_' . $this->capability_type,
137
				'read_' . $this->capability_type,
138
				'delete_' . $this->capability_type,
139
				'edit_' . $this->capability_type . 's',
140
				'edit_others_' . $this->capability_type . 's',
141
				'publish_' . $this->capability_type . 's',
142
				'read_private_' . $this->capability_type . 's',
143
				'edit_' . $this->capability_type . 's',
144
			)
145
		);
146
147
		return $caps;
148
	}
149
150
	/**
151
	 * Pod Page Content Shortcode support for use anywhere that supports WP Shortcodes
152
	 *
153
	 * @param array  $tags    An associative array of shortcode properties
154
	 * @param string $content Not currently used
0 ignored issues
show
Should the type for parameter $content not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
155
	 *
156
	 * @return string
157
	 * @since 2.3.9
158
	 */
159
	public function shortcode( $tags, $content = null ) {
160
161
		if ( ! isset( $tags['page'] ) || empty( $tags['page'] ) ) {
162
			$tags['page'] = null;
163
		}
164
165
		$pods_page = self::exists( $tags['page'] );
166
167
		if ( empty( $pods_page ) ) {
168
			return '<p>Pods Page not found</p>';
169
		}
170
171
		return self::content( true, $pods_page );
172
	}
173
174
	/**
175
	 * Disable this Post Type from appearing in the Builder layouts list
176
	 *
177
	 * @param array $post_types
178
	 *
179
	 * @return array
0 ignored issues
show
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
180
	 */
181
	public function disable_builder_layout( $post_types ) {
182
183
		$post_types[] = $this->object_type;
184
185
		return $post_types;
186
	}
187
188
	/**
189
	 * Update Post Type messages
190
	 *
191
	 * @param array $messages
192
	 *
193
	 * @return array
0 ignored issues
show
Consider making the return type a bit more specific; maybe use array<*,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
194
	 * @since 2.0.2
195
	 */
196
	public function setup_updated_messages( $messages ) {
197
198
		global $post, $post_ID;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
199
200
		$post_type = get_post_type_object( $this->object_type );
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
201
202
		$labels = $post_type->labels;
203
204
		$messages[ $post_type->name ] = array(
205
			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 ),
206
			2  => __( 'Custom field updated.', 'pods' ),
207
			3  => __( 'Custom field deleted.', 'pods' ),
208
			4  => sprintf( __( '%s updated.', 'pods' ), $labels->singular_name ),
209
			/* translators: %s: date and time of the revision */
210
			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,
211
			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 ),
212
			7  => sprintf( __( '%s saved.', 'pods' ), $labels->singular_name ),
213
			8  => sprintf( __( '%1$s submitted. <a target="_blank" 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 ),
214
			9  => sprintf(
215
				__( '%s scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview %s</a>', 'pods' ), $labels->singular_name,
216
				// translators: Publish box date format, see http://php.net/date
217
				date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ), $labels->singular_name
218
			),
219
			10 => sprintf( __( '%1$s draft updated. <a target="_blank" 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 ),
220
		);
221
222
		if ( false === (boolean) $post_type->public ) {
223
			$messages[ $post_type->name ][1] = sprintf( __( '%s updated.', 'pods' ), $labels->singular_name );
224
			$messages[ $post_type->name ][6] = sprintf( __( '%s published.', 'pods' ), $labels->singular_name );
225
			$messages[ $post_type->name ][8] = sprintf( __( '%s submitted.', 'pods' ), $labels->singular_name );
226
			$messages[ $post_type->name ][9] = sprintf(
227
				__( '%s scheduled for: <strong>%1$s</strong>.', 'pods' ), $labels->singular_name,
228
				// translators: Publish box date format, see http://php.net/date
229
				date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) )
230
			);
231
			$messages[ $post_type->name ][10] = sprintf( __( '%s draft updated.', 'pods' ), $labels->singular_name );
232
		}
233
234
		return $messages;
235
	}
236
237
	/**
238
	 * Enqueue styles
239
	 *
240
	 * @since 2.0
241
	 */
242
	public function admin_assets() {
243
244
		wp_enqueue_style( 'pods-styles' );
245
	}
246
247
	/**
248
	 * Fix filters, specifically removing balanceTags
249
	 *
250
	 * @since 2.0.1
251
	 *
252
	 * @param      $data
253
	 * @param null $pod
254
	 * @param null $id
255
	 * @param null $groups
256
	 * @param null $post
257
	 */
258
	public function fix_filters( $data, $pod = null, $id = null, $groups = null, $post = null ) {
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
259
260
		remove_filter( 'content_save_pre', 'balanceTags', 50 );
261
	}
262
263
	/**
264
	 * Remove unused row actions
265
	 *
266
	 * @since 2.0.5
267
	 *
268
	 * @param $actions
269
	 * @param $post
270
	 *
271
	 * @return
272
	 */
273
	public function remove_row_actions( $actions, $post ) {
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
274
275
		global $current_screen;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
276
277
		if ( ! is_object( $current_screen ) || $this->object_type != $current_screen->post_type ) {
278
			return $actions;
279
		}
280
281
		if ( isset( $actions['view'] ) ) {
282
			unset( $actions['view'] );
283
		}
284
285
		if ( isset( $actions['inline hide-if-no-js'] ) ) {
286
			unset( $actions['inline hide-if-no-js'] );
287
		}
288
289
		// W3 Total Cache
290
		if ( isset( $actions['pgcache_purge'] ) ) {
291
			unset( $actions['pgcache_purge'] );
292
		}
293
294
		return $actions;
295
	}
296
297
	/**
298
	 * Remove unused bulk actions
299
	 *
300
	 * @since 2.0.5
301
	 *
302
	 * @param $actions
303
	 *
304
	 * @return
305
	 */
306
	public function remove_bulk_actions( $actions ) {
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
307
308
		if ( isset( $actions['edit'] ) ) {
309
			unset( $actions['edit'] );
310
		}
311
312
		return $actions;
313
	}
314
315
	/**
316
	 * Clear cache on save
317
	 *
318
	 * @since 2.0
319
	 *
320
	 * @param      $data
321
	 * @param null $pod
322
	 * @param null $id
323
	 * @param null $groups
324
	 * @param null $post
325
	 */
326
	public function clear_cache( $data, $pod = null, $id = null, $groups = null, $post = null ) {
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
327
328
		$old_post = $id;
329
330
		if ( ! is_object( $id ) ) {
331
			$old_post = null;
332
		}
333
334
		if ( is_object( $post ) && $this->object_type != $post->post_type ) {
335
			return;
336
		}
337
338
		if ( ! is_array( $data ) && 0 < $data ) {
339
			$post = $data;
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
340
			$post = get_post( $post );
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
341
		}
342
343
		if ( $this->object_type == $post->post_type ) {
344
			pods_transient_clear( 'pods_object_pages' );
345
346
			if ( is_object( $old_post ) && $this->object_type == $old_post->post_type ) {
347
				pods_cache_clear( $old_post->post_title, 'pods_object_page_wildcard' );
348
			}
349
350
			pods_cache_clear( $post->post_title, 'pods_object_page_wildcard' );
351
352
			self::flush_rewrites();
353
		}
354
	}
355
356
	/**
357
	 * Change post title placeholder text
358
	 *
359
	 * @since 2.0
360
	 *
361
	 * @param $text
362
	 * @param $post
363
	 *
364
	 * @return string|void
365
	 */
366
	public function set_title_text( $text, $post ) {
367
368
		return __( 'Enter URL here', 'pods' );
369
	}
370
371
	/**
372
	 * Edit page form
373
	 *
374
	 * @since 2.0
375
	 */
376
	public function edit_page_form() {
377
378
		global $post_type;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
379
380
		if ( $this->object_type != $post_type ) {
381
			return;
382
		}
383
384
		add_filter( 'enter_title_here', array( $this, 'set_title_text' ), 10, 2 );
385
	}
386
387
	/**
388
	 * Filter permalinks and adjust for pod pages
389
	 *
390
	 * @param $post_link
391
	 * @param $post
392
	 *
393
	 * @return mixed
394
	 */
395
	public function post_type_link( $post_link, $post ) {
396
397
		if ( empty( $post ) || $this->object_type != $post->post_type ) {
398
			return $post_link;
399
		}
400
401
		$post_link = get_site_url() . '/';
402
403
		if ( false === strpos( $post->post_title, '*' ) ) {
404
			$post_link .= trim( $post->post_title, '/ ' ) . '/';
405
		}
406
407
		return $post_link;
408
	}
409
410
	/**
411
	 * Add meta boxes to the page
412
	 *
413
	 * @since 2.0
414
	 */
415
	public function add_meta_boxes() {
416
417
		$pod = array(
418
			'name' => $this->object_type,
419
			'type' => 'post_type',
420
		);
421
422
		if ( isset( PodsMeta::$post_types[ $pod['name'] ] ) ) {
423
			return;
424
		}
425
426
		if ( ! function_exists( 'get_page_templates' ) ) {
427
			include_once ABSPATH . 'wp-admin/includes/theme.php';
428
		}
429
430
		$page_templates = apply_filters( 'pods_page_templates', get_page_templates() );
431
432
		$page_templates[ __( '-- Page Template --', 'pods' ) ] = '';
433
434
		$page_templates[ __( 'Custom (uses only Pod Page content)', 'pods' ) ] = '_custom';
435
436
		if ( ! in_array( 'pods.php', $page_templates, true ) && locate_template( array( 'pods.php', false ) ) ) {
437
			$page_templates[ __( 'Pods (Pods Default)', 'pods' ) ] = 'pods.php';
438
		}
439
440
		if ( ! in_array( 'page.php', $page_templates, true ) && locate_template( array( 'page.php', false ) ) ) {
441
			$page_templates[ __( 'Page (WP Default)', 'pods' ) ] = 'page.php';
442
		}
443
444
		if ( ! in_array( 'index.php', $page_templates, true ) && locate_template( array( 'index.php', false ) ) ) {
445
			$page_templates[ __( 'Index (WP Fallback)', 'pods' ) ] = 'index.php';
446
		}
447
448
		ksort( $page_templates );
449
450
		$page_templates = array_flip( $page_templates );
451
452
		$fields = array(
453
			array(
454
				'name'  => 'page_title',
455
				'label' => __( 'Page Title', 'pods' ),
456
				'type'  => 'text',
457
			),
458
			array(
459
				'name'          => 'code',
460
				'label'         => __( 'Page Code', 'pods' ),
461
				'type'          => 'code',
462
				'attributes'    => array(
463
					'id' => 'content',
464
				),
465
				'label_options' => array(
466
					'attributes' => array(
467
						'for' => 'content',
468
					),
469
				),
470
			),
471
			array(
472
				'name'  => 'precode',
473
				'label' => __( 'Page Precode', 'pods' ),
474
				'type'  => 'code',
475
				'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' ),
476
			),
477
			array(
478
				'name'  => 'page_template',
479
				'label' => __( 'Page Template', 'pods' ),
480
				'type'  => 'pick',
481
				'data'  => $page_templates,
482
			),
483
		);
484
485
		pods_group_add( $pod, __( 'Page', 'pods' ), $fields, 'normal', 'high' );
486
487
		$associated_pods = array(
488
			0 => __( '-- Select a Pod --', 'pods' ),
489
		);
490
491
		$all_pods = pods_api()->load_pods( array( 'names' => true ) );
492
493
		if ( ! empty( $all_pods ) ) {
494
			foreach ( $all_pods as $pod_name => $pod_label ) {
0 ignored issues
show
The expression $all_pods of type array|object|integer|double|string|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
495
				$associated_pods[ $pod_name ] = $pod_label . ' (' . $pod_name . ')';
496
			}
497
		} else {
498
			$associated_pods[0] = __( 'None Found', 'pods' );
499
		}
500
501
		$fields = array(
502
			array(
503
				'name'       => 'pod',
504
				'label'      => __( 'Associated Pod', 'pods' ),
505
				'default'    => 0,
506
				'type'       => 'pick',
507
				'data'       => $associated_pods,
508
				'dependency' => true,
509
			),
510
			array(
511
				'name'        => 'pod_slug',
512
				'label'       => __( 'Wildcard Slug', 'pods' ),
513
				'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' ),
514
				'type'        => 'text',
515
				'excludes-on' => array( 'pod' => 0 ),
516
			),
517
		);
518
519
		pods_group_add( $pod, __( 'Pod Association', 'pods' ), $fields, 'normal', 'high' );
520
521
		$fields = array(
522
			array(
523
				'name'       => 'admin_only',
524
				'label'      => __( 'Restrict access to Admins?', 'pods' ),
525
				'default'    => 0,
526
				'type'       => 'boolean',
527
				'dependency' => true,
528
			),
529
			array(
530
				'name'       => 'restrict_role',
531
				'label'      => __( 'Restrict access by Role?', 'pods' ),
532
				'help'       => array(
533
					__( '<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' ),
534
					'http://codex.wordpress.org/Roles_and_Capabilities',
535
				),
536
				'default'    => 0,
537
				'type'       => 'boolean',
538
				'dependency' => true,
539
			),
540
			array(
541
				'name'              => 'roles_allowed',
542
				'label'             => __( 'Role(s) Allowed', 'pods' ),
543
				'type'              => 'pick',
544
				'pick_object'       => 'role',
545
				'pick_format_type'  => 'multi',
546
				'pick_format_multi' => 'autocomplete',
547
				'pick_ajax'         => false,
548
				'default'           => '',
549
				'depends-on'        => array(
550
					'restrict_role' => true,
551
				),
552
			),
553
			array(
554
				'name'       => 'restrict_capability',
555
				'label'      => __( 'Restrict access by Capability?', 'pods' ),
556
				'help'       => array(
557
					__( '<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' ),
558
					'http://codex.wordpress.org/Roles_and_Capabilities',
559
				),
560
				'default'    => 0,
561
				'type'       => 'boolean',
562
				'dependency' => true,
563
			),
564
			array(
565
				'name'              => 'capability_allowed',
566
				'label'             => __( 'Capability Allowed', 'pods' ),
567
				'type'              => 'pick',
568
				'pick_object'       => 'capability',
569
				'pick_format_type'  => 'multi',
570
				'pick_format_multi' => 'autocomplete',
571
				'pick_ajax'         => false,
572
				'default'           => '',
573
				'depends-on'        => array(
574
					'restrict_capability' => true,
575
				),
576
			),
577
			array(
578
				'name'       => 'restrict_redirect',
579
				'label'      => __( 'Redirect if Restricted?', 'pods' ),
580
				'default'    => 0,
581
				'type'       => 'boolean',
582
				'dependency' => true,
583
			),
584
			array(
585
				'name'       => 'restrict_redirect_login',
586
				'label'      => __( 'Redirect to WP Login page', 'pods' ),
587
				'default'    => 0,
588
				'type'       => 'boolean',
589
				'dependency' => true,
590
				'depends-on' => array(
591
					'restrict_redirect' => true,
592
				),
593
			),
594
			array(
595
				'name'       => 'restrict_redirect_url',
596
				'label'      => __( 'Redirect to a Custom URL', 'pods' ),
597
				'default'    => '',
598
				'type'       => 'text',
599
				'depends-on' => array(
600
					'restrict_redirect'       => true,
601
					'restrict_redirect_login' => false,
602
				),
603
			),
604
		);
605
606
		pods_group_add( $pod, __( 'Restrict Access', 'pods' ), $fields, 'normal', 'high' );
607
	}
608
609
	/**
610
	 * Get the fields
611
	 *
612
	 * @param null   $_null
613
	 * @param int    $post_ID
0 ignored issues
show
Should the type for parameter $post_ID not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
614
	 * @param string $meta_key
0 ignored issues
show
Should the type for parameter $meta_key not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
615
	 * @param bool   $single
616
	 *
617
	 * @return array|bool|int|mixed|null|string|void
618
	 */
619
	public function get_meta( $_null, $post_ID = null, $meta_key = null, $single = false ) {
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
620
621
		if ( 'code' === $meta_key ) {
622
			$post = get_post( $post_ID );
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
623
624
			if ( is_object( $post ) && $this->object_type == $post->post_type ) {
625
				return $post->post_content;
626
			}
627
		}
628
629
		return $_null;
630
	}
631
632
	/**
633
	 * Save the fields
634
	 *
635
	 * @param        $_null
636
	 * @param int    $post_ID
0 ignored issues
show
Should the type for parameter $post_ID not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
637
	 * @param string $meta_key
0 ignored issues
show
Should the type for parameter $meta_key not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
638
	 * @param null   $meta_value
639
	 *
640
	 * @return bool|int|null
641
	 */
642
	public function save_meta( $_null, $post_ID = null, $meta_key = null, $meta_value = null ) {
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
643
644
		if ( 'code' === $meta_key ) {
645
			$post = get_post( $post_ID );
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
646
647
			if ( is_object( $post ) && $this->object_type == $post->post_type ) {
648
				$postdata = array(
649
					'ID'           => $post_ID,
650
					'post_content' => $meta_value,
651
				);
652
653
				remove_filter( current_filter(), array( $this, __FUNCTION__ ) );
654
655
				$revisions = false;
656
657
				if ( has_action( 'pre_post_update', 'wp_save_post_revision' ) ) {
658
					remove_action( 'pre_post_update', 'wp_save_post_revision' );
659
660
					$revisions = true;
661
				}
662
663
				wp_update_post( (object) $postdata );
664
				// objects will be automatically sanitized
665
				if ( $revisions ) {
666
					add_action( 'pre_post_update', 'wp_save_post_revision' );
667
				}
668
669
				return true;
670
			}//end if
671
		}//end if
672
673
		return $_null;
674
	}
675
676
	/**
677
	 * Flush Pod Page Rewrite cache
678
	 *
679
	 * @return array Pod Page Rewrites
680
	 *
681
	 * @since 2.3.4
682
	 */
683
	public static function flush_rewrites() {
684
685
		$args = array(
686
			'post_type'      => '_pods_page',
687
			'nopaging'       => true,
0 ignored issues
show
Disabling pagination is prohibited in VIP context, do not set nopaging to true ever.
Loading history...
688
			'posts_per_page' => - 1,
689
			'post_status'    => 'publish',
690
			'order'          => 'ASC',
691
			'orderby'        => 'title',
692
		);
693
694
		$pod_pages = get_posts( $args );
695
696
		$pod_page_rewrites = array();
697
698
		foreach ( $pod_pages as $pod_page ) {
699
			$pod_page_rewrites[ $pod_page->ID ] = $pod_page->post_title;
700
		}
701
702
		uksort( $pod_page_rewrites, 'pods_page_length_sort' );
703
704
		pods_transient_set( 'pods_object_page_rewrites', $pod_page_rewrites );
705
706
		$pod_page_rewrites = array_flip( $pod_page_rewrites );
707
708
		return $pod_page_rewrites;
709
	}
710
711
	/**
712
	 * Check to see if Pod Page exists and return data
713
	 *
714
	 * $uri not required, if NULL then returns REQUEST_URI matching Pod Page
715
	 *
716
	 * @param string $uri The Pod Page URI to check if exists
0 ignored issues
show
Should the type for parameter $uri not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
717
	 *
718
	 * @return array|bool
719
	 */
720
	public static function exists( $uri = null ) {
721
722
		if ( null === $uri ) {
723
			$uri = parse_url( pods_current_url() );
724
			$uri = $uri['path'];
725
		} else {
726
			$uri = explode( '?', $uri );
727
			$uri = explode( '#', $uri[0] );
728
			$uri = $uri[0];
729
		}
730
731
		$home = parse_url( get_home_url() );
732
733
		if ( ! empty( $home ) && isset( $home['path'] ) && '/' !== $home['path'] ) {
734
			$uri = substr( $uri, strlen( $home['path'] ) );
735
		}
736
737
		$uri       = trim( $uri, '/' );
738
		$uri_depth = count( array_filter( explode( '/', $uri ) ) ) - 1;
739
740
		$pods_page_exclusions = array(
741
			'wp-admin',
742
			'wp-content',
743
			'wp-includes',
744
			'index.php',
745
			'wp-login.php',
746
			'wp-signup.php',
747
		);
748
749
		$pods_page_exclusions = apply_filters( 'pods_page_exclusions', $pods_page_exclusions );
750
751
		if ( is_admin() || empty( $uri ) ) {
752
			return false;
753
		}
754
755
		foreach ( $pods_page_exclusions as $exclusion ) {
756
			if ( 0 === strpos( $uri, $exclusion ) ) {
757
				return false;
758
			}
759
		}
760
761
		$object = apply_filters( 'pods_page_exists', false, $uri );
762
		if ( ! empty( $object ) ) {
763
			return $object;
764
		}
765
766
		if ( false === strpos( $uri, '*' ) && ! apply_filters( 'pods_page_regex_matching', false ) ) {
767
			$object = pods_by_title( $uri, ARRAY_A, '_pods_page', 'publish' );
768
		}
769
770
		$wildcard = false;
771
772
		if ( empty( $object ) ) {
773
			if ( false === strpos( $uri, '*' ) ) {
774
				$object = pods_cache_get( $uri, 'pods_object_page_wildcard' );
775
776
				if ( ! empty( $object ) ) {
777
					return $object;
778
				}
779
			}
780
781
			$pod_page_rewrites = pods_transient_get( 'pods_object_page_rewrites' );
782
783
			if ( empty( $pod_page_rewrites ) ) {
784
				$pod_page_rewrites = self::flush_rewrites();
785
			} else {
786
				$pod_page_rewrites = array_flip( $pod_page_rewrites );
787
			}
788
789
			$found_rewrite_page_id = 0;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $found_rewrite_page_id exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
790
791
			if ( ! empty( $pod_page_rewrites ) ) {
792
				foreach ( $pod_page_rewrites as $pod_page => $pod_page_id ) {
793
					if ( ! apply_filters( 'pods_page_regex_matching', false ) ) {
794
						if ( false === strpos( $pod_page, '*' ) ) {
795
							continue;
796
						}
797
798
						$depth_check = strlen( $pod_page ) - strlen( str_replace( '/', '', $pod_page ) );
799
800
						$pod_page = preg_quote( $pod_page, '/' );
801
802
						$pod_page = str_replace( '\\*', '(.*)', $pod_page );
803
804
						if ( $uri_depth == $depth_check && preg_match( '/^' . $pod_page . '$/', $uri ) ) {
805
							$found_rewrite_page_id = $pod_page_id;
806
807
							break;
808
						}
809
					} elseif ( preg_match( '/^' . str_replace( '/', '\\/', $pod_page ) . '$/', $uri ) ) {
810
						$found_rewrite_page_id = $pod_page_id;
811
812
						break;
813
					}//end if
814
				}//end foreach
815
816
				if ( ! empty( $found_rewrite_page_id ) ) {
817
					$object = get_post( $found_rewrite_page_id, ARRAY_A );
818
819
					if ( empty( $object ) || '_pods_page' !== $object['post_type'] ) {
820
						$object = false;
821
					}
822
				}
823
			}//end if
824
825
			$wildcard = true;
826
		}//end if
827
828
		if ( ! empty( $object ) ) {
829
			$object = array(
830
				'id'            => $object['ID'],
831
				'uri'           => $object['post_title'],
832
				'code'          => $object['post_content'],
833
				'phpcode'       => $object['post_content'],
834
				// phpcode is deprecated
835
				'precode'       => get_post_meta( $object['ID'], 'precode', true ),
836
				'page_template' => get_post_meta( $object['ID'], 'page_template', true ),
837
				'title'         => get_post_meta( $object['ID'], 'page_title', true ),
838
				'options'       => array(
839
					'admin_only'              => (boolean) get_post_meta( $object['ID'], 'admin_only', true ),
840
					'restrict_role'           => (boolean) get_post_meta( $object['ID'], 'restrict_role', true ),
841
					'restrict_capability'     => (boolean) get_post_meta( $object['ID'], 'restrict_capability', true ),
842
					'roles_allowed'           => get_post_meta( $object['ID'], 'roles_allowed', true ),
843
					'capability_allowed'      => get_post_meta( $object['ID'], 'capability_allowed', true ),
844
					'restrict_redirect'       => (boolean) get_post_meta( $object['ID'], 'restrict_redirect', true ),
845
					'restrict_redirect_login' => (boolean) get_post_meta( $object['ID'], 'restrict_redirect_login', true ),
846
					'restrict_redirect_url'   => get_post_meta( $object['ID'], 'restrict_redirect_url', true ),
847
					'pod'                     => get_post_meta( $object['ID'], 'pod', true ),
848
					'pod_slug'                => get_post_meta( $object['ID'], 'pod_slug', true ),
849
				),
850
			);
851
852
			if ( $wildcard ) {
853
				pods_cache_set( $uri, $object, 'pods_object_page_wildcard', 3600 );
854
			}
855
856
			return $object;
857
		}//end if
858
859
		return false;
860
	}
861
862
	/**
863
	 * Check if a Pod Page exists
864
	 */
865
	public function page_check() {
866
867
		if ( self::$checked ) {
868
			return;
869
		}
870
871
		global $pods;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
872
873
		// Fix any global confusion wherever this runs
874
		if ( isset( $pods ) && ! isset( $GLOBALS['pods'] ) ) {
875
			$GLOBALS['pods'] =& $pods;
876
		} elseif ( ! isset( $pods ) && isset( $GLOBALS['pods'] ) ) {
877
			$pods =& $GLOBALS['pods'];
878
		}
879
880
		if ( ! defined( 'PODS_DISABLE_POD_PAGE_CHECK' ) || ! PODS_DISABLE_POD_PAGE_CHECK ) {
881
			if ( null === self::$exists ) {
882
				self::$exists = pod_page_exists();
883
			}
884
885
			if ( false !== self::$exists ) {
886
				$pods = apply_filters( 'pods_global', $pods, self::$exists );
887
888
				if ( ! is_wp_error( $pods ) && ( is_object( $pods ) || 404 != $pods ) ) {
889
					add_action( 'template_redirect', array( $this, 'template_redirect' ) );
890
					add_filter( 'redirect_canonical', '__return_false' );
891
					add_action( 'wp_head', array( $this, 'wp_head' ) );
892
					add_filter( 'wp_title', array( $this, 'wp_title' ), 0, 3 );
893
					add_filter( 'body_class', array( $this, 'body_class' ), 0, 1 );
894
					add_filter( 'status_header', array( $this, 'status_header' ) );
895
					add_action( 'after_setup_theme', array( $this, 'precode' ) );
896
					add_action( 'wp', array( $this, 'silence_404' ), 1 );
897
898
					// Genesis theme integration
899
					add_action( 'genesis_loop', 'pods_content', 11 );
900
				}
901
			}
902
903
			self::$checked = true;
904
		}//end if
905
	}
906
907
	/**
908
	 * Output Pod Page Content
909
	 *
910
	 * @param bool $return Whether to return or not (default is to echo)
911
	 *
912
	 * @param bool $pods_page
913
	 *
914
	 * @return string
915
	 */
916
	public static function content( $return = false, $pods_page = false ) {
917
918
		if ( empty( $pods_page ) ) {
919
			$pods_page = self::$exists;
920
		}
921
922
		$content = false;
923
924
		if ( $pods_page == self::$exists && self::$content_called ) {
925
			return $content;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $content; (false) is incompatible with the return type documented by Pods_Pages::content of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
926
		}
927
928
		if ( ! empty( $pods_page ) ) {
929
			/**
930
			 * @var $pods \Pods
931
			 */
932
			global $pods;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
933
934
			// Fix any global confusion wherever this runs
935
			if ( isset( $pods ) && ! isset( $GLOBALS['pods'] ) ) {
936
				$GLOBALS['pods'] =& $pods;
937
			} elseif ( ! isset( $pods ) && isset( $GLOBALS['pods'] ) ) {
938
				$pods =& $GLOBALS['pods'];
939
			}
940
941
			if ( 0 < strlen( trim( $pods_page['code'] ) ) ) {
942
				$content = trim( $pods_page['code'] );
943
			}
944
945
			ob_start();
946
947
			do_action( 'pods_content_pre', $pods_page, $content );
948
949
			if ( 0 < strlen( $content ) ) {
950
				if ( false !== strpos( $content, '<?' ) && ( ! defined( 'PODS_DISABLE_EVAL' ) || ! PODS_DISABLE_EVAL ) ) {
951
					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' );
952
953
					eval( "?>$content" );
0 ignored issues
show
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
eval is prohibited, please use Anonymous functions instead.
Loading history...
954
				} elseif ( is_object( $pods ) && ! empty( $pods->id ) ) {
955
					echo $pods->do_magic_tags( $content );
956
				} else {
957
					echo $content;
958
				}
959
			}
960
961
			do_action( 'pods_content_post', $pods_page, $content );
962
963
			$content = ob_get_clean();
964
965
			if ( $pods_page == self::$exists ) {
966
				self::$content_called = true;
967
			}
968
		}//end if
969
970
		$content = apply_filters( 'pods_content', $content, $pods_page );
971
972
		if ( $return ) {
973
			return $content;
974
		}
975
976
		echo $content;
977
	}
978
979
	/**
980
	 * Run any precode for current Pod Page
981
	 */
982
	public function precode() {
983
984
		global $pods;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
985
986
		// Fix any global confusion wherever this runs
987
		if ( isset( $pods ) && ! isset( $GLOBALS['pods'] ) ) {
988
			$GLOBALS['pods'] =& $pods;
989
		} elseif ( ! isset( $pods ) && isset( $GLOBALS['pods'] ) ) {
990
			$pods =& $GLOBALS['pods'];
991
		}
992
993
		if ( false !== self::$exists ) {
994
			$permission = pods_permission( self::$exists['options'] );
995
996
			$permission = (boolean) apply_filters( 'pods_pages_permission', $permission, self::$exists );
997
998
			if ( $permission ) {
999
				$content = false;
1000
1001
				if ( ! is_object( $pods ) && 404 != $pods && 0 < strlen( pods_var( 'pod', self::$exists['options'] ) ) ) {
1002
					$slug = pods_var_raw( 'pod_slug', self::$exists['options'], null, null, true );
1003
1004
					// Handle special magic tags
1005
					if ( 0 < strlen( $slug ) ) {
1006
						$slug = pods_evaluate_tags( $slug, true );
1007
					}
1008
1009
					$pods = pods( pods_var( 'pod', self::$exists['options'] ), $slug );
1010
1011
					// Auto 404 handling if item doesn't exist
1012
					if ( 0 < strlen( $slug ) && ! $pods->exists() && apply_filters( 'pods_pages_auto_404', true, $slug, $pods, self::$exists ) ) {
1013
						$pods = 404;
1014
					}
1015
				}
1016
1017
				if ( 0 < strlen( trim( self::$exists['precode'] ) ) ) {
1018
					$content = self::$exists['precode'];
1019
				}
1020
1021
				if ( false !== $content && ( ! defined( 'PODS_DISABLE_EVAL' ) || ! PODS_DISABLE_EVAL ) ) {
1022
					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' );
1023
1024
					eval( "?>$content" );
0 ignored issues
show
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
eval is prohibited, please use Anonymous functions instead.
Loading history...
1025
				}
1026
1027
				do_action( 'pods_page_precode', self::$exists, $pods, $content );
1028
			} elseif ( self::$exists['options']['restrict_redirect'] ) {
1029
				$redirect_url = '';
1030
1031
				if ( self::$exists['options']['restrict_redirect_login'] ) {
1032
					$redirect_url = wp_login_url( pods_current_url() );
1033
				} elseif ( ! empty( self::$exists['options']['restrict_redirect_url'] ) ) {
1034
					$redirect_url = self::$exists['options']['restrict_redirect_url'];
1035
				}
1036
1037
				if ( ! empty( $redirect_url ) ) {
1038
					wp_redirect( $redirect_url );
1039
					die();
1040
				}
1041
			}//end if
1042
1043
			if ( ! $permission || ( ! is_object( $pods ) && ( 404 == $pods || is_wp_error( $pods ) ) ) ) {
1044
				remove_action( 'template_redirect', array( $this, 'template_redirect' ) );
1045
				remove_action( 'wp_head', array( $this, 'wp_head' ) );
1046
				remove_filter( 'redirect_canonical', '__return_false' );
1047
				remove_filter( 'wp_title', array( $this, 'wp_title' ) );
1048
				remove_filter( 'body_class', array( $this, 'body_class' ) );
1049
				remove_filter( 'status_header', array( $this, 'status_header' ) );
1050
				remove_action( 'wp', array( $this, 'silence_404' ), 1 );
1051
			}
1052
		}//end if
1053
	}
1054
1055
	/**
1056
	 *
1057
	 */
1058
	public function wp_head() {
1059
1060
		global $pods;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1061
1062
		do_action( 'pods_wp_head' );
1063
1064
		if ( ! defined( 'PODS_DISABLE_VERSION_OUTPUT' ) || ! PODS_DISABLE_VERSION_OUTPUT ) {
1065
			?>
1066
			<!-- Pods Framework <?php echo esc_html( PODS_VERSION ); ?> -->
1067
			<?php
1068
		}
1069
		if ( ( ! defined( 'PODS_DISABLE_META' ) || ! PODS_DISABLE_META ) && is_object( $pods ) && ! is_wp_error( $pods ) ) {
1070
1071
			if ( isset( $pods->meta ) && is_array( $pods->meta ) && ! empty( $pods->meta ) ) {
1072
				foreach ( $pods->meta as $name => $content ) {
1073
					if ( 'title' === $name ) {
1074
						continue;
1075
					}
1076
					?>
1077
					<meta name="<?php echo esc_attr( $name ); ?>" content="<?php echo esc_attr( $content ); ?>" />
1078
					<?php
1079
				}
1080
			}
1081
1082
			if ( isset( $pods->meta_properties ) && is_array( $pods->meta_properties ) && ! empty( $pods->meta_properties ) ) {
1083
				foreach ( $pods->meta_properties as $property => $content ) {
1084
					?>
1085
					<meta property="<?php echo esc_attr( $property ); ?>" content="<?php echo esc_attr( $content ); ?>" />
1086
					<?php
1087
				}
1088
			}
1089
1090
			if ( isset( $pods->meta_extra ) && 0 < strlen( $pods->meta_extra ) ) {
1091
				echo $pods->meta_extra;
1092
			}
1093
		}//end if
1094
	}
1095
1096
	/**
1097
	 * @param $title
1098
	 * @param $sep
1099
	 * @param $seplocation
1100
	 *
1101
	 * @return mixed|void
1102
	 */
1103
	public function wp_title( $title, $sep, $seplocation ) {
1104
1105
		global $pods;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1106
1107
		$page_title = trim( self::$exists['title'] );
1108
1109
		if ( 0 < strlen( $page_title ) ) {
1110
			if ( is_object( $pods ) && ! is_wp_error( $pods ) ) {
1111
				$page_title = $pods->do_magic_tags( $page_title );
1112
			}
1113
1114
			$title = ( 'right' === $seplocation ) ? "{$page_title} {$sep} " : " {$sep} {$page_title}";
1115
		} elseif ( strlen( trim( $title ) ) < 1 ) {
1116
			$uri = explode( '?', $_SERVER['REQUEST_URI'] );
1117
			$uri = preg_replace( '@^([/]?)(.*?)([/]?)$@', '$2', $uri[0] );
1118
			$uri = preg_replace( '@(-|_)@', ' ', $uri );
1119
			$uri = explode( '/', $uri );
1120
1121
			$title = '';
1122
1123
			foreach ( $uri as $key => $page_title ) {
1124
				$title .= ( 'right' === $seplocation ) ? ucwords( $page_title ) . " {$sep} " : " {$sep} " . ucwords( $page_title );
1125
			}
1126
		}
1127
1128
		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'] ) ) {
1129
			$title = $pods->meta['title'];
1130
		}
1131
1132
		return apply_filters( 'pods_title', $title, $sep, $seplocation, self::$exists );
1133
	}
1134
1135
	/**
1136
	 * @param $classes
1137
	 *
1138
	 * @return mixed|void
1139
	 */
1140
	public function body_class( $classes ) {
1141
1142
		global $pods;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1143
1144
		if ( defined( 'PODS_DISABLE_BODY_CLASSES' ) && PODS_DISABLE_BODY_CLASSES ) {
1145
			return $classes;
1146
		}
1147
1148
		$classes[] = 'pods';
1149
1150
		$uri = explode( '?', self::$exists['uri'] );
1151
		$uri = explode( '#', $uri[0] );
1152
1153
		$class = str_replace( array( '*', '/' ), array( '_w_', '-' ), $uri[0] );
1154
		$class = sanitize_title( $class );
1155
		$class = str_replace( array( '_', '--', '--' ), '-', $class );
1156
		$class = trim( $class, '-' );
1157
1158
		$classes[] = 'pod-page-' . $class;
1159
1160
		if ( is_object( $pods ) && ! is_wp_error( $pods ) ) {
1161
			$class     = sanitize_title( $pods->pod );
1162
			$class     = str_replace( array( '_', '--', '--' ), '-', $class );
1163
			$class     = trim( $class, '-' );
1164
			$classes[] = 'pod-' . $class;
1165
		}
1166
1167
		if ( is_object( $pods ) && ! is_wp_error( $pods ) && isset( $pods->body_classes ) ) {
1168
			$classes[] = $pods->body_classes;
1169
		}
1170
1171
		return apply_filters( 'pods_body_class', $classes, $uri );
1172
	}
1173
1174
	/**
1175
	 * @return string
1176
	 */
1177
	public function status_header() {
1178
1179
		return $_SERVER['SERVER_PROTOCOL'] . ' 200 OK';
1180
	}
1181
1182
	/**
1183
	 *
1184
	 */
1185
	public function silence_404() {
1186
1187
		global $wp_query;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1188
1189
		$wp_query->query_vars['error'] = '';
1190
		$wp_query->is_404              = false;
1191
	}
1192
1193
	/**
1194
	 *
1195
	 */
1196
	public function template_redirect() {
1197
1198
		global $pods;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1199
1200
		if ( false !== self::$exists ) {
1201
			/*
1202
			 * Create pods.php in your theme directory, and
1203
			 * style it to suit your needs. Some helpful functions:
1204
			 *
1205
			 * get_header()
1206
			 * pods_content()
1207
			 * get_sidebar()
1208
			 * get_footer()
1209
			 */
1210
			$template = self::$exists['page_template'];
1211
			$template = apply_filters( 'pods_page_template', $template, self::$exists );
1212
1213
			$render_function = apply_filters( 'pods_template_redirect', null, $template, self::$exists );
1214
1215
			do_action( 'pods_page', $template, self::$exists );
1216
1217
			if ( '_custom' === $template ) {
1218
				pods_content();
1219
			} elseif ( null !== $render_function && is_callable( $render_function ) ) {
1220
				call_user_func( $render_function, $template, self::$exists );
1221
			} 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( array( $pods->page_template ), true ) ) {
1222
				$template = $pods->page_template;
1223
				// found the template and included it, we're good to go!
1224
			} elseif ( ! empty( self::$exists['page_template'] ) && '' != locate_template( array( self::$exists['page_template'] ), true ) ) {
1225
				$template = self::$exists['page_template'];
1226
				// found the template and included it, we're good to go!
1227
			} else {
1228
				$default_templates = array();
1229
1230
				$uri = explode( '?', self::$exists['uri'] );
1231
				$uri = explode( '#', $uri[0] );
1232
1233
				$page_path = explode( '/', $uri[0] );
1234
1235
				while ( $last = array_pop( $page_path ) ) {
1236
					$file_name = str_replace( '*', '-w-', implode( '/', $page_path ) . '/' . $last );
1237
					$sanitized = sanitize_title( $file_name );
1238
1239
					$default_templates[] = 'pods/' . trim( str_replace( '--', '-', $sanitized ), ' -' ) . '.php';
1240
					$default_templates[] = 'pods-' . trim( str_replace( '--', '-', $sanitized ), ' -' ) . '.php';
1241
				}
1242
1243
				$default_templates[] = 'pods.php';
1244
1245
				$default_templates = apply_filters( 'pods_page_default_templates', $default_templates );
1246
1247
				$template = locate_template( $default_templates, true );
1248
1249
				if ( '' !== $template ) {
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1250
					// found the template and included it, we're good to go!
1251
				} else {
1252
					$template = false;
1253
1254
					// templates not found in theme, default output
1255
					do_action( 'pods_page_default', $template, self::$exists );
1256
1257
					get_header();
1258
					pods_content();
1259
					get_sidebar();
1260
					get_footer();
1261
				}
1262
			}//end if
1263
1264
			do_action( 'pods_page_end', $template, self::$exists );
1265
1266
			exit;
1267
		}//end if
1268
	}
1269
}
1270
1271
/**
1272
 * Find out if the current page is a Pod Page
1273
 *
1274
 * @param string $uri The Pod Page URI to check if currently on
0 ignored issues
show
Should the type for parameter $uri not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1275
 *
1276
 * @return bool
1277
 * @since 1.7.5
1278
 */
1279
function is_pod_page( $uri = null ) {
1280
1281
	if ( false !== Pods_Pages::$exists && ( null === $uri || $uri == Pods_Pages::$exists['uri'] || $uri == Pods_Pages::$exists['id'] ) ) {
0 ignored issues
show
This if statement, and the following return statement can be replaced with return false !== \Pods_P..._Pages::$exists['id']);.
Loading history...
1282
		return true;
1283
	}
1284
1285
	return false;
1286
}
1287
1288
/**
1289
 * Check for a specific page template for the current pod page
1290
 *
1291
 * @param string $template The theme template file
0 ignored issues
show
Should the type for parameter $template not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1292
 *
1293
 * @return bool
1294
 * @since 2.3.7
1295
 */
1296
function is_pod_page_template( $template = null ) {
1297
1298
	if ( false !== Pods_Pages::$exists && $template == Pods_Pages::$exists['page_template'] ) {
0 ignored issues
show
This if statement, and the following return statement can be replaced with return false !== \Pods_P...xists['page_template'];.
Loading history...
1299
		return true;
1300
	}
1301
1302
	return false;
1303
}
1304
1305
/**
1306
 * Get the current Pod Page URI
1307
 *
1308
 * @return string|bool
1309
 * @since 2.3.3
1310
 */
1311
function get_pod_page_uri() {
1312
1313
	$pod_page = Pods_Pages::exists();
1314
1315
	if ( ! empty( $pod_page ) ) {
1316
		return $pod_page['uri'];
1317
	}
1318
1319
	return false;
1320
}
1321
1322
/**
1323
 * Check to see if Pod Page exists and return data
1324
 *
1325
 * $uri not required, if NULL then returns REQUEST_URI matching Pod Page
1326
 *
1327
 * @param string $uri The Pod Page URI to check if exists
0 ignored issues
show
Should the type for parameter $uri not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1328
 *
1329
 * @return array
0 ignored issues
show
Should the return type not be array|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
1330
 *
1331
 * @since 1.7.5
1332
 */
1333
function pod_page_exists( $uri = null ) {
1334
1335
	return Pods_Pages::exists( $uri );
1336
}
1337
1338
/**
1339
 * Output Pod Page Content
1340
 *
1341
 * @param bool $return Whether to return or not (default is to echo)
1342
 *
1343
 * @param bool $pods_page
1344
 *
1345
 * @return string
1346
 * @since 1.7.0
1347
 */
1348
function pods_content( $return = false, $pods_page = false ) {
1349
1350
	return Pods_Pages::content( $return, $pods_page );
1351
}
1352
1353
/**
1354
 * Sort an array by length of items, descending, for use with uksort()
1355
 *
1356
 * @param string $a First array item
1357
 * @param string $b Second array item
1358
 *
1359
 * @return int Length difference
1360
 *
1361
 * @since 2.3.4
1362
 */
1363
function pods_page_length_sort( $a, $b ) {
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $a. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
Comprehensibility introduced by
Avoid variables with short names like $b. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1364
1365
	return strlen( $b ) - strlen( $a );
1366
}
1367
1368
/**
1369
 * Flush Pod Page Rewrite cache
1370
 *
1371
 * @return array Pod Page Rewrites
1372
 *
1373
 * @since 2.3.4
1374
 */
1375
function pods_page_flush_rewrites() {
1376
1377
	return Pods_Pages::flush_rewrites();
1378
}
1379
1380
/*
1381
 * Deprecated global variable
1382
 */
1383
$GLOBALS['pod_page_exists'] =& Pods_Pages::$exists;
1384