Completed
Pull Request — 2.x (#3401)
by Scott Kingsley
11:14
created

PodsView::get_key()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 13
rs 9.4285
cc 2
eloc 5
nc 2
nop 2
1
<?php
2
3
/**
4
 * @package Pods
5
 */
6
class PodsView {
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
7
8
	/**
9
	 * @var array $cache_modes Array of available cache modes
10
	 */
11
	static $cache_modes = array( 'none', 'transient', 'site-transient', 'cache', 'option-cache' );
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $cache_modes.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

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

Loading history...
12
13
	/**
14
	 * @return \PodsView
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
15
	 */
16
	private function __construct() {
17
18
		// !nope
19
20
	}
21
22
	/**
23
	 * @static
24
	 *
25
	 * @param string         $view       Path of the view file
26
	 * @param array|null     $data       (optional) Data to pass on to the template
27
	 * @param bool|int|array $expires    (optional) Time in seconds for the cache to expire, if 0 no expiration.
28
	 * @param string         $cache_mode (optional) Decides the caching method to use for the view.
29
	 *
30
	 * @return bool|mixed|null|string|void
31
	 *
32
	 * @since 2.0
33
	 */
34
	public static function view( $view, $data = null, $expires = false, $cache_mode = 'cache' ) {
35
36
		/**
37
		 * Override the value of $view. For example, using Pods AJAX View.
38
		 *
39
		 * To use, set first param to true. If that param in not null, this method returns its value.
40
		 *
41
		 * @param null|bool      If          not set to null, this filter overrides the rest of the method.
42
		 * @param string         $view       Path of the view file
43
		 * @param array|null     $data       (optional) Data to pass on to the template
44
		 * @param bool|int|array $expires    (optional) Time in seconds for the cache to expire, if 0 no expiration.
45
		 * @param string         $cache_mode (optional) Decides the caching method to use for the view.
46
		 *
47
		 * @returns The value of the first param.
48
		 *
49
		 * @since 2.4.1
50
		 */
51
		$filter_check = apply_filters( 'pods_view_alt_view', null, $view, $data, $expires, $cache_mode );
52
		if ( ! is_null( $filter_check ) ) {
53
			return $filter_check;
54
55
		}
56
57
		// Advanced $expires handling
58
		$expires = self::expires( $expires, $cache_mode );
59
60
		if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
61
			$cache_mode = 'cache';
62
		}
63
64
		// Support my-view.php?custom-key=X#hash keying for cache
65
		$view_id = '';
66
67
		if ( ! is_array( $view ) ) {
68
			$view_q = explode( '?', $view );
69
70
			if ( 1 < count( $view_q ) ) {
71
				$view_id = '?' . $view_q[1];
72
73
				$view = $view_q[0];
74
			}
75
76
			$view_h = explode( '#', $view );
77
78
			if ( 1 < count( $view_h ) ) {
79
				$view_id .= '#' . $view_h[1];
80
81
				$view = $view_h[0];
82
			}
83
84
			// Support dynamic tags!
85
			$view_id = pods_evaluate_tags( $view_id );
86
		}
87
88
		$view = apply_filters( 'pods_view_inc', $view, $data, $expires, $cache_mode );
89
90
		$view_key = $view;
91
92
		if ( is_array( $view_key ) ) {
93
			$view_key = implode( '-', $view_key ) . '.php';
94
		}
95
96
		if ( false !== realpath( $view_key ) ) {
97
			$view_key = realpath( $view_key );
98
		}
99
100
		$pods_ui_dir         = realpath( PODS_DIR . 'ui/' );
101
		$pods_components_dir = realpath( PODS_DIR . 'components/' );
102
		$abspath_dir         = realpath( ABSPATH );
103
104
		$cache_key = pods_str_replace( $abspath_dir, '/', $view_key, 1 );
105
106
		$output = false;
107
108
		$caching = false;
109
110
		if ( false !== $expires && false === strpos( $view_key, $pods_ui_dir ) && false === strpos( $view_key, $pods_components_dir ) ) {
111
			$caching = true;
112
		}
113
114
		if ( $caching ) {
115
			$output = self::get( 'pods-view-' . $cache_key . $view_id, $cache_mode, 'pods_view' );
116
		}
117
118
		if ( false === $output || null === $output ) {
119
			$output = self::get_template_part( $view, $data );
120
		}
121
122
		if ( false !== $output && $caching ) {
123
			self::set( 'pods-view-' . $cache_key . $view_id, $output, $expires, $cache_mode, 'pods_view' );
124
		}
125
126
		$output = apply_filters( 'pods_view_output_' . $cache_key, $output, $view, $data, $expires, $cache_mode );
127
		$output = apply_filters( 'pods_view_output', $output, $view, $data, $expires, $cache_mode );
128
129
		return $output;
130
	}
131
132
	/**
133
	 * Get the cache key, salted with current Pods version, peppered with md5 if too long
134
	 *
135
	 * @param string $key
136
	 * @param string $group_key
137
	 *
138
	 * @return string
139
	 *
140
	 * @since 2.6.2
141
	 */
142
	public static function get_key( $key, $group_key = '' ) {
143
144
		// Add some salt
145
		$key .= '-' . PODS_VERSION;
146
147
		// Patch for limitations in DB
148
		if ( 44 < strlen( $group_key . $key ) ) {
149
			$key = md5( $key );
150
		}
151
152
		return $key;
153
154
	}
155
156
	/**
157
	 * @static
158
	 *
159
	 * @param string $key        Key for the cache
160
	 * @param string $cache_mode (optional) Decides the caching method to use for the view.
161
	 * @param string $group      (optional) Set the group of the value.
162
	 * @param string $callback   (optional) Callback function to run to set the value if not cached.
163
	 *
164
	 * @return bool|mixed|null|void
165
	 *
166
	 * @since 2.0
167
	 */
168
	public static function get( $key, $cache_mode = 'cache', $group = '', $callback = null ) {
169
170
		$object_cache = false;
171
172
		if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
173
			$object_cache = true;
174
		}
175
176
		if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
177
			$cache_mode = 'cache';
178
		}
179
180
		$group_key = 'pods_';
181
182
		if ( ! empty( $group ) ) {
183
			$group_key = $group . '_';
184
		}
185
186
		$original_key = $key;
187
188
		// Get proper cache key
189
		$key = self::get_key( $key, $group_key );
190
191
		$value = null;
192
193
		$called = false;
194
195
		$pods_nocache = pods_var_raw( 'pods_nocache' );
196
		$nocache      = array();
197
198
		if ( pods_is_admin() && null !== $pods_nocache ) {
199
			if ( 1 < strlen( $pods_nocache ) ) {
200
				$nocache = explode( ',', $pods_nocache );
201
			} else {
202
				$nocache = self::$cache_modes;
203
			}
204
		}
205
206
		if ( apply_filters( 'pods_view_cache_alt_get', false, $cache_mode, $group_key . $key, $original_key, $group ) ) {
207
			$value = apply_filters( 'pods_view_cache_alt_get_value', $value, $cache_mode, $group_key . $key, $original_key, $group );
208
		} elseif ( 'transient' == $cache_mode && ! in_array( $cache_mode, $nocache ) ) {
209
			$value = get_transient( $group_key . $key );
210
		} elseif ( 'site-transient' == $cache_mode && ! in_array( $cache_mode, $nocache ) ) {
211
			$value = get_site_transient( $group_key . $key );
212
		} elseif ( 'cache' == $cache_mode && $object_cache && ! in_array( $cache_mode, $nocache ) ) {
213
			$value = wp_cache_get( $key, ( empty( $group ) ? 'pods_view' : $group ) );
214
		} elseif ( 'option-cache' == $cache_mode && ! in_array( $cache_mode, $nocache ) ) {
215
			global $_wp_using_ext_object_cache;
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...
216
217
			$pre = apply_filters( 'pre_transient_' . $key, false );
218
219
			if ( false !== $pre ) {
220
				$value = $pre;
221
			} elseif ( $_wp_using_ext_object_cache ) {
222
				$value   = wp_cache_get( $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
223
				$timeout = wp_cache_get( '_timeout_' . $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
224
225
				if ( ! empty( $timeout ) && $timeout < time() ) {
226
					if ( is_callable( $callback ) ) {
227
						// Callback function should do it's own set/update for cache
228
						$callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
229
230
						if ( null !== $callback_value && false !== $callback_value ) {
231
							$value = $callback_value;
232
						}
233
234
						$called = true;
235
					} else {
236
						$value = false;
237
238
						wp_cache_delete( $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
239
						wp_cache_delete( '_timeout_' . $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
240
					}
241
				}
242
			} else {
243
				$transient_option  = '_pods_option_' . $key;
244
				$transient_timeout = '_pods_option_timeout_' . $key;
245
246
				$value   = get_option( $transient_option );
247
				$timeout = get_option( $transient_timeout );
248
249
				if ( ! empty( $timeout ) && $timeout < time() ) {
250
					if ( is_callable( $callback ) ) {
251
						// Callback function should do it's own set/update for cache
252
						$callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
253
254
						if ( null !== $callback_value && false !== $callback_value ) {
255
							$value = $callback_value;
256
						}
257
258
						$called = true;
259
					} else {
260
						$value = false;
261
262
						delete_option( $transient_option );
263
						delete_option( $transient_timeout );
264
					}
265
				}
266
			}
267
268
			if ( false !== $value ) {
269
				$value = apply_filters( 'transient_' . $key, $value );
270
			}
271
		} else {
272
			$value = false;
273
		}
274
275
		if ( false === $value && is_callable( $callback ) && ! $called ) {
276
			// Callback function should do it's own set/update for cache
277
			$callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
278
279
			if ( null !== $callback_value && false !== $callback_value ) {
280
				$value = $callback_value;
281
			}
282
		}
283
284
		$value = apply_filters( 'pods_view_get_' . $cache_mode, $value, $original_key, $group );
285
286
		return $value;
287
	}
288
289
	/**
290
	 * @static
291
	 *
292
	 * Set a cached value
293
	 *
294
	 * @param string $key        Key for the cache
295
	 * @param mixed  $value      Value to add to the cache
296
	 * @param int    $expires    (optional) Time in seconds for the cache to expire, if 0 no expiration.
297
	 * @param string $cache_mode (optional) Decides the caching method to use for the view.
298
	 * @param string $group      (optional) Set the group of the value.
299
	 *
300
	 * @return bool|mixed|null|string|void
301
	 *
302
	 * @since 2.0
303
	 */
304
	public static function set( $key, $value, $expires = 0, $cache_mode = null, $group = '' ) {
305
306
		$object_cache = false;
307
308
		if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
309
			$object_cache = true;
310
		}
311
312
		// Advanced $expires handling
313
		$expires = self::expires( $expires, $cache_mode );
314
315
		if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
316
			$cache_mode = 'cache';
317
		}
318
319
		$group_key = 'pods_';
320
321
		if ( ! empty( $group ) ) {
322
			$group_key = $group . '_';
323
		}
324
325
		$original_key = $key;
326
327
		// Get proper cache key
328
		$key = self::get_key( $key, $group_key );
329
330
		if ( apply_filters( 'pods_view_cache_alt_set', false, $cache_mode, $group_key . $key, $original_key, $value, $expires, $group ) ) {
331
			return $value;
332
		} elseif ( 'transient' == $cache_mode ) {
333
			set_transient( $group_key . $key, $value, $expires );
334
		} elseif ( 'site-transient' == $cache_mode ) {
335
			set_site_transient( $group_key . $key, $value, $expires );
336
		} elseif ( 'cache' == $cache_mode && $object_cache ) {
337
			wp_cache_set( $key, $value, ( empty( $group ) ? 'pods_view' : $group ), $expires );
338
		} elseif ( 'option-cache' == $cache_mode ) {
339
			global $_wp_using_ext_object_cache;
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...
340
341
			$value = apply_filters( 'pre_set_transient_' . $key, $value );
342
343
			if ( $_wp_using_ext_object_cache ) {
344
				$result = wp_cache_set( $key, $value, ( empty( $group ) ? 'pods_option_cache' : $group ) );
345
346
				if ( $expires ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $expires of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
347
					$result = wp_cache_set( '_timeout_' . $key, $expires, ( empty( $group ) ? 'pods_option_cache' : $group ) );
348
				}
349
			} else {
350
				$transient_timeout = '_pods_option_timeout_' . $key;
351
				$key               = '_pods_option_' . $key;
352
353
				if ( false === get_option( $key ) ) {
354
					if ( $expires ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $expires of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
355
						add_option( $transient_timeout, time() + $expires, '', 'no' );
356
					}
357
358
					$result = add_option( $key, $value, '', 'no' );
359
				} else {
360
					if ( $expires ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $expires of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
361
						update_option( $transient_timeout, time() + $expires );
362
					}
363
364
					$result = update_option( $key, $value );
365
				}
366
			}
367
368
			if ( $result ) {
369
				do_action( 'set_transient_' . $key );
370
				do_action( 'setted_transient', $key );
371
			}
372
		}
373
374
		do_action( 'pods_view_set_' . $cache_mode, $original_key, $value, $expires, $group );
375
376
		return $value;
377
	}
378
379
	/**
380
	 * @static
381
	 *
382
	 * Clear a cached value
383
	 *
384
	 * @param string|bool $key        Key for the cache
385
	 * @param string      $cache_mode (optional) Decides the caching method to use for the view.
386
	 * @param string      $group      (optional) Set the group.
387
	 *
388
	 * @return bool
389
	 *
390
	 * @since 2.0
391
	 */
392
	public static function clear( $key = true, $cache_mode = null, $group = '' ) {
393
394
		$object_cache = false;
395
396
		if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
397
			$object_cache = true;
398
		}
399
400
		global $wpdb;
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...
401
402
		if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
403
			$cache_mode = 'cache';
404
		}
405
406
		$group_key = 'pods_';
407
408
		if ( ! empty( $group ) ) {
409
			$group_key = $group . '_';
410
		}
411
412
		$full_key = $original_key = $key;
413
414
		if ( true !== $key ) {
415
			// Get proper cache key
416
			$key = self::get_key( $key, $group_key );
417
418
			$full_key = $group_key . $key;
419
		}
420
421
		if ( apply_filters( 'pods_view_cache_alt_set', false, $cache_mode, $full_key, $original_key, '', 0, $group ) ) {
422
			return true;
423
		} elseif ( 'transient' == $cache_mode ) {
424
			if ( true === $key ) {
425
				$group_key = pods_sanitize_like( $group_key );
426
427
				$wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE option_name LIKE '_transient_{$group_key}%'" );
428
429
				if ( $object_cache ) {
430
					wp_cache_flush();
431
				}
432
			} else {
433
				delete_transient( $group_key . $key );
434
			}
435
		} elseif ( 'site-transient' == $cache_mode ) {
436
			if ( true === $key ) {
437
				$group_key = pods_sanitize_like( $group_key );
438
439
				$wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE option_name LIKE '_site_transient_{$group_key}%'" );
440
441
				if ( $object_cache ) {
442
					wp_cache_flush();
443
				}
444
			} else {
445
				delete_site_transient( $group_key . $key );
446
			}
447
		} elseif ( 'cache' == $cache_mode && $object_cache ) {
448
			if ( true === $key ) {
449
				wp_cache_flush();
450
			} else {
451
				wp_cache_delete( ( empty( $key ) ? 'pods_view' : $key ), ( empty( $group ) ? 'pods_view' : $group ) );
452
			}
453
		} elseif ( 'option-cache' == $cache_mode ) {
454
			global $_wp_using_ext_object_cache;
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...
455
456
			do_action( 'delete_transient_' . $key, $key );
457
458
			if ( $_wp_using_ext_object_cache ) {
459
				$result = wp_cache_delete( $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
460
461
				wp_cache_delete( '_timeout_' . $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
462
			} else {
463
				$option_timeout = '_pods_option_timeout_' . $key;
464
				$option         = '_pods_option_' . $key;
465
466
				$result = delete_option( $option );
467
468
				if ( $result ) {
469
					delete_option( $option_timeout );
470
				}
471
			}
472
473
			if ( $result ) {
474
				do_action( 'deleted_transient', $key );
475
			}
476
		}
477
478
		do_action( 'pods_view_clear_' . $cache_mode, $original_key, $group );
479
480
		return true;
481
	}
482
483
	/**
484
	 * @static
485
	 *
486
	 * @param            $_view
487
	 * @param null|array $_data
488
	 *
489
	 * @return bool|mixed|string|void
490
	 */
491
	public static function get_template_part( $_view, $_data = null ) {
492
493
		/* to be reviewed later, should have more checks and restrictions like a whitelist etc
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
494
		if ( 0 === strpos( $_view, 'http://' ) || 0 === strpos( $_view, 'https://' ) ) {
495
			$_view = apply_filters( 'pods_view_url_include', $_view );
496
497
			if ( empty( $_view ) || ( defined( 'PODS_REMOTE_VIEWS' ) && PODS_REMOTE_VIEWS ) )
498
				return '';
499
500
			$response = wp_remote_get( $_view );
501
502
			return wp_remote_retrieve_body( $response );
503
		}*/
504
505
		$_view = self::locate_template( $_view );
506
507
		if ( empty( $_view ) ) {
508
			return $_view;
509
		}
510
511
		if ( ! empty( $_data ) && is_array( $_data ) ) {
512
			extract( $_data, EXTR_SKIP );
513
		}
514
515
		ob_start();
516
		require $_view;
517
		$output = ob_get_clean();
518
519
		return $output;
520
	}
521
522
	/**
523
	 * @static
524
	 *
525
	 * @param $_view
526
	 *
527
	 * @return bool|mixed|string|void
528
	 */
529
	private static function locate_template( $_view ) {
530
531
		if ( is_array( $_view ) ) {
532
			$_views = array();
533
534
			if ( isset( $_view[0] ) && false === strpos( $_view[0], '.php' ) ) {
535
				$_view_count = count( $_view );
536
537
				for ( $_view_x = $_view_count; 0 < $_view_x; $_view_x -- ) {
538
					$_view_v = array_slice( $_view, 0, $_view_x );
539
540
					$_views[] = implode( '-', $_view_v ) . '.php';
541
				}
542
			} else {
543
				$_views = $_view;
544
			}
545
546
			$_view = false;
547
548
			foreach ( $_views as $_view_check ) {
549
				$_view = self::locate_template( $_view_check );
550
551
				if ( ! empty( $_view ) ) {
552
					break;
553
				}
554
			}
555
556
			return $_view;
557
		}
558
559
		// Keep it safe
560
		$_view = trim( str_replace( array( '../', '\\' ), array( '', '/' ), (string) $_view ) );
561
562
		if ( empty( $_view ) ) {
563
			return false;
564
		}
565
566
		$_real_view = realpath( $_view );
567
568
		if ( empty( $_real_view ) ) {
569
			$_real_view = $_view;
570
		}
571
572
		$located = false;
573
574
		// Is the view's file somewhere within the plugin directory tree?
575
		// Note: we explicitly whitelist PODS_DIR for the case of symlinks (see issue #2945)
576
		if ( false !== strpos( $_real_view, realpath( WP_PLUGIN_DIR ) ) || false !== strpos( $_real_view, realpath( WPMU_PLUGIN_DIR ) ) || false !== strpos( $_real_view, PODS_DIR ) ) {
577
			if ( file_exists( $_view ) ) {
578
				$located = $_view;
579
			} else {
580
				$located = apply_filters( 'pods_view_locate_template', $located, $_view );
581
			}
582
583
		} else { // The view's file is outside the plugin directory
584
			$_real_view = trim( $_real_view, '/' );
585
586
			if ( empty( $_real_view ) ) {
587
				return false;
588
			}
589
590
			// Allow views in the theme or child theme
591
			if ( file_exists( realpath( get_stylesheet_directory() . '/' . $_real_view ) ) ) {
592
				$located = realpath( get_stylesheet_directory() . '/' . $_real_view );
593
			} elseif ( file_exists( realpath( get_template_directory() . '/' . $_real_view ) ) ) {
594
				$located = realpath( get_template_directory() . '/' . $_real_view );
595
			}
596
		}
597
598
		return $located;
599
600
	}
601
602
	/**
603
	 * Advanced $expires handling
604
	 *
605
	 * @param array|bool|int $expires
606
	 * @param string         $cache_mode
607
	 *
608
	 * @return bool|int
609
	 *
610
	 * @since 3.0
611
	 * @static
612
	 */
613
	public static function expires( $expires, $cache_mode = 'cache' ) {
614
615
		// Different $expires if user is anonymous or logged in or specific capability
616
		if ( is_array( $expires ) ) {
617
			if ( ( isset( $expires['anonymous'] ) || isset( $expires['user_with_access'] ) ) && isset( $expires['user'] ) ) {
618
				if ( isset( $expires['user_with_access'] ) ) {
619
					$expires = array(
620
						pods_var_raw( 'anonymous', $expires, false ),
621
						pods_var_raw( 'user', $expires, false ),
622
						pods_var_raw( 'user_with_access', $expires, false ),
623
						pods_var_raw( 'capability', $expires, null, null, true )
624
					);
625
				} elseif ( isset( $expires['anonymous'] ) ) {
626
					$expires = array(
627
						pods_var_raw( 'anonymous', $expires, false ),
628
						pods_var_raw( 'user', $expires, false ),
629
						pods_var_raw( 'capability', $expires, null, null, true )
630
					);
631
				}
632
			} else {
633
				$expires = array_values( $expires );
634
			}
635
636
			if ( 4 == count( $expires ) ) {
637
				if ( ! is_user_logged_in() ) {
638
					$expires = pods_var_raw( 0, $expires, false );
639 View Code Duplication
				} else {
640
					$user_no_access   = pods_var_raw( 1, $expires, false );
641
					$user_with_access = pods_var_raw( 2, $expires, false );
642
					$capability       = pods_var_raw( 3, $expires, null, null, true );
643
644
					$expires = pods_var_user( $user_no_access, $user_with_access, $capability );
645
				}
646 View Code Duplication
			} else {
647
				$anon       = pods_var_raw( 0, $expires, false );
648
				$user       = pods_var_raw( 1, $expires, false );
649
				$capability = pods_var_raw( 2, $expires, null, null, true );
650
651
				$expires = pods_var_user( $anon, $user, $capability );
652
			}
653
		}
654
655
		if ( 'none' == $cache_mode ) {
656
			$expires = false;
657
		} elseif ( false !== $expires ) {
658
			$expires = (int) $expires;
659
660
			if ( $expires < 1 ) {
661
				$expires = 0;
662
			}
663
		}
664
665
		return $expires;
666
667
	}
668
669
}
670