Completed
Push — 2.x ( 23cefc...81076f )
by Scott Kingsley
05:50
created

PodsView   D

Complexity

Total Complexity 136

Size/Duplication

Total Lines 664
Duplicated Lines 2.11 %

Coupling/Cohesion

Components 1
Dependencies 0
Metric Value
wmc 136
lcom 1
cbo 0
dl 14
loc 664
rs 4.6062

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
F view() 0 97 16
A get_key() 0 13 2
F get() 0 120 41
D set() 0 74 20
F clear() 0 90 24
B get_template_part() 0 30 4
C locate_template() 0 72 16
C expires() 14 55 12

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PodsView often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PodsView, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package Pods
4
 */
5
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...
6
7
	/**
8
	 * @var array $cache_modes Array of available cache modes
9
	 */
10
	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...
11
12
	/**
13
	 * @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...
14
	 */
15
	private function __construct() {
16
17
		// !nope
18
19
	}
20
21
	/**
22
	 * @static
23
	 *
24
	 * @param string         $view       Path of the view file
25
	 * @param array|null     $data       (optional) Data to pass on to the template
26
	 * @param bool|int|array $expires    (optional) Time in seconds for the cache to expire, if 0 no expiration.
27
	 * @param string         $cache_mode (optional) Decides the caching method to use for the view.
28
	 *
29
	 * @return bool|mixed|null|string|void
30
	 *
31
	 * @since 2.0
32
	 */
33
	public static function view( $view, $data = null, $expires = false, $cache_mode = 'cache' ) {
34
35
		/**
36
		 * Override the value of $view. For example, using Pods AJAX View.
37
		 *
38
		 * To use, set first param to true. If that param in not null, this method returns its value.
39
		 *
40
		 * @param null|bool      If          not set to null, this filter overrides the rest of the method.
41
		 * @param string         $view       Path of the view file
42
		 * @param array|null     $data       (optional) Data to pass on to the template
43
		 * @param bool|int|array $expires    (optional) Time in seconds for the cache to expire, if 0 no expiration.
44
		 * @param string         $cache_mode (optional) Decides the caching method to use for the view.
45
		 *
46
		 * @returns The value of the first param.
47
		 *
48
		 * @since 2.4.1
49
		 */
50
		$filter_check = apply_filters( 'pods_view_alt_view', null, $view, $data, $expires, $cache_mode );
51
		if ( ! is_null( $filter_check ) ) {
52
			return $filter_check;
53
54
		}
55
56
		// Advanced $expires handling
57
		$expires = self::expires( $expires, $cache_mode );
58
59
		if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
60
			$cache_mode = 'cache';
61
		}
62
63
		// Support my-view.php?custom-key=X#hash keying for cache
64
		$view_id = '';
65
66
		if ( ! is_array( $view ) ) {
67
			$view_q = explode( '?', $view );
68
69
			if ( 1 < count( $view_q ) ) {
70
				$view_id = '?' . $view_q[1];
71
72
				$view = $view_q[0];
73
			}
74
75
			$view_h = explode( '#', $view );
76
77
			if ( 1 < count( $view_h ) ) {
78
				$view_id .= '#' . $view_h[1];
79
80
				$view = $view_h[0];
81
			}
82
83
			// Support dynamic tags!
84
			$view_id = pods_evaluate_tags( $view_id );
85
		}
86
87
		$view = apply_filters( 'pods_view_inc', $view, $data, $expires, $cache_mode );
88
89
		$view_key = $view;
90
91
		if ( is_array( $view_key ) ) {
92
			$view_key = implode( '-', $view_key ) . '.php';
93
		}
94
95
		if ( false !== realpath( $view_key ) ) {
96
			$view_key = realpath( $view_key );
97
		}
98
99
		$pods_ui_dir         = realpath( PODS_DIR . 'ui/' );
100
		$pods_components_dir = realpath( PODS_DIR . 'components/' );
101
		$abspath_dir         = realpath( ABSPATH );
102
103
		$cache_key = pods_str_replace( $abspath_dir, '/', $view_key, 1 );
104
105
		$output = false;
106
107
		$caching = false;
108
109
		if ( false !== $expires && false === strpos( $view_key, $pods_ui_dir ) && false === strpos( $view_key, $pods_components_dir ) ) {
110
			$caching = true;
111
		}
112
113
		if ( $caching ) {
114
			$output = self::get( 'pods-view-' . $cache_key . $view_id, $cache_mode, 'pods_view' );
115
		}
116
117
		if ( false === $output || null === $output ) {
118
			$output = self::get_template_part( $view, $data );
119
		}
120
121
		if ( false !== $output && $caching ) {
122
			self::set( 'pods-view-' . $cache_key . $view_id, $output, $expires, $cache_mode, 'pods_view' );
123
		}
124
125
		$output = apply_filters( 'pods_view_output_' . $cache_key, $output, $view, $data, $expires, $cache_mode );
126
		$output = apply_filters( 'pods_view_output', $output, $view, $data, $expires, $cache_mode );
127
128
		return $output;
129
	}
130
131
	/**
132
	 * Get the cache key, salted with current Pods version, peppered with md5 if too long
133
	 *
134
	 * @param string $key
135
	 * @param string $group_key
136
	 *
137
	 * @return string
138
	 *
139
	 * @since 2.6.2
140
	 */
141
	public static function get_key( $key, $group_key = '' ) {
142
143
		// Add some salt
144
		$key .= '-' . PODS_VERSION;
145
146
		// Patch for limitations in DB
147
		if ( 44 < strlen( $group_key . $key ) ) {
148
			$key = md5( $key );
149
		}
150
151
		return $key;
152
153
	}
154
155
	/**
156
	 * @static
157
	 *
158
	 * @param string $key        Key for the cache
159
	 * @param string $cache_mode (optional) Decides the caching method to use for the view.
160
	 * @param string $group      (optional) Set the group of the value.
161
	 * @param string $callback   (optional) Callback function to run to set the value if not cached.
162
	 *
163
	 * @return bool|mixed|null|void
164
	 *
165
	 * @since 2.0
166
	 */
167
	public static function get( $key, $cache_mode = 'cache', $group = '', $callback = null ) {
168
169
		$object_cache = false;
170
171
		if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
172
			$object_cache = true;
173
		}
174
175
		if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
176
			$cache_mode = 'cache';
177
		}
178
179
		$group_key = 'pods_';
180
181
		if ( ! empty( $group ) ) {
182
			$group_key = $group . '_';
183
		}
184
185
		$original_key = $key;
186
187
		// Get proper cache key
188
		$key = self::get_key( $key, $group_key );
189
190
		$value = null;
191
192
		$called = false;
193
194
		$pods_nocache = pods_var_raw( 'pods_nocache' );
195
		$nocache      = array();
196
197
		if ( pods_is_admin() && null !== $pods_nocache ) {
198
			if ( 1 < strlen( $pods_nocache ) ) {
199
				$nocache = explode( ',', $pods_nocache );
200
			} else {
201
				$nocache = self::$cache_modes;
202
			}
203
		}
204
205
		if ( apply_filters( 'pods_view_cache_alt_get', false, $cache_mode, $group_key . $key, $original_key, $group ) ) {
206
			$value = apply_filters( 'pods_view_cache_alt_get_value', $value, $cache_mode, $group_key . $key, $original_key, $group );
207
		} elseif ( 'transient' == $cache_mode && ! in_array( $cache_mode, $nocache ) ) {
208
			$value = get_transient( $group_key . $key );
209
		} elseif ( 'site-transient' == $cache_mode && ! in_array( $cache_mode, $nocache ) ) {
210
			$value = get_site_transient( $group_key . $key );
211
		} elseif ( 'cache' == $cache_mode && $object_cache && ! in_array( $cache_mode, $nocache ) ) {
212
			$value = wp_cache_get( $key, ( empty( $group ) ? 'pods_view' : $group ) );
213
		} elseif ( 'option-cache' == $cache_mode && ! in_array( $cache_mode, $nocache ) ) {
214
			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...
215
216
			$pre = apply_filters( 'pre_transient_' . $key, false );
217
218
			if ( false !== $pre ) {
219
				$value = $pre;
220
			} elseif ( $_wp_using_ext_object_cache ) {
221
				$value   = wp_cache_get( $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
222
				$timeout = wp_cache_get( '_timeout_' . $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
223
224
				if ( ! empty( $timeout ) && $timeout < time() ) {
225
					if ( is_callable( $callback ) ) {
226
						// Callback function should do it's own set/update for cache
227
						$callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
228
229
						if ( null !== $callback_value && false !== $callback_value ) {
230
							$value = $callback_value;
231
						}
232
233
						$called = true;
234
					} else {
235
						$value = false;
236
237
						wp_cache_delete( $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
238
						wp_cache_delete( '_timeout_' . $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
239
					}
240
				}
241
			} else {
242
				$transient_option  = '_pods_option_' . $key;
243
				$transient_timeout = '_pods_option_timeout_' . $key;
244
245
				$value   = get_option( $transient_option );
246
				$timeout = get_option( $transient_timeout );
247
248
				if ( ! empty( $timeout ) && $timeout < time() ) {
249
					if ( is_callable( $callback ) ) {
250
						// Callback function should do it's own set/update for cache
251
						$callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
252
253
						if ( null !== $callback_value && false !== $callback_value ) {
254
							$value = $callback_value;
255
						}
256
257
						$called = true;
258
					} else {
259
						$value = false;
260
261
						delete_option( $transient_option );
262
						delete_option( $transient_timeout );
263
					}
264
				}
265
			}
266
267
			if ( false !== $value ) {
268
				$value = apply_filters( 'transient_' . $key, $value );
269
			}
270
		} else {
271
			$value = false;
272
		}
273
274
		if ( false === $value && is_callable( $callback ) && ! $called ) {
275
			// Callback function should do it's own set/update for cache
276
			$callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
277
278
			if ( null !== $callback_value && false !== $callback_value ) {
279
				$value = $callback_value;
280
			}
281
		}
282
283
		$value = apply_filters( 'pods_view_get_' . $cache_mode, $value, $original_key, $group );
284
285
		return $value;
286
	}
287
288
	/**
289
	 * @static
290
	 *
291
	 * Set a cached value
292
	 *
293
	 * @param string $key        Key for the cache
294
	 * @param mixed  $value      Value to add to the cache
295
	 * @param int    $expires    (optional) Time in seconds for the cache to expire, if 0 no expiration.
296
	 * @param string $cache_mode (optional) Decides the caching method to use for the view.
297
	 * @param string $group      (optional) Set the group of the value.
298
	 *
299
	 * @return bool|mixed|null|string|void
300
	 *
301
	 * @since 2.0
302
	 */
303
	public static function set( $key, $value, $expires = 0, $cache_mode = null, $group = '' ) {
304
305
		$object_cache = false;
306
307
		if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
308
			$object_cache = true;
309
		}
310
311
		// Advanced $expires handling
312
		$expires = self::expires( $expires, $cache_mode );
313
314
		if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
315
			$cache_mode = 'cache';
316
		}
317
318
		$group_key = 'pods_';
319
320
		if ( ! empty( $group ) ) {
321
			$group_key = $group . '_';
322
		}
323
324
		$original_key = $key;
325
326
		// Get proper cache key
327
		$key = self::get_key( $key, $group_key );
328
329
		if ( apply_filters( 'pods_view_cache_alt_set', false, $cache_mode, $group_key . $key, $original_key, $value, $expires, $group ) ) {
330
			return $value;
331
		} elseif ( 'transient' == $cache_mode ) {
332
			set_transient( $group_key . $key, $value, $expires );
333
		} elseif ( 'site-transient' == $cache_mode ) {
334
			set_site_transient( $group_key . $key, $value, $expires );
335
		} elseif ( 'cache' == $cache_mode && $object_cache ) {
336
			wp_cache_set( $key, $value, ( empty( $group ) ? 'pods_view' : $group ), $expires );
337
		} elseif ( 'option-cache' == $cache_mode ) {
338
			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...
339
340
			$value = apply_filters( 'pre_set_transient_' . $key, $value );
341
342
			if ( $_wp_using_ext_object_cache ) {
343
				$result = wp_cache_set( $key, $value, ( empty( $group ) ? 'pods_option_cache' : $group ) );
344
345
				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...
346
					$result = wp_cache_set( '_timeout_' . $key, $expires, ( empty( $group ) ? 'pods_option_cache' : $group ) );
347
				}
348
			} else {
349
				$transient_timeout = '_pods_option_timeout_' . $key;
350
				$key               = '_pods_option_' . $key;
351
352
				if ( false === get_option( $key ) ) {
353
					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...
354
						add_option( $transient_timeout, time() + $expires, '', 'no' );
355
					}
356
357
					$result = add_option( $key, $value, '', 'no' );
358
				} else {
359
					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...
360
						update_option( $transient_timeout, time() + $expires );
361
					}
362
363
					$result = update_option( $key, $value );
364
				}
365
			}
366
367
			if ( $result ) {
368
				do_action( 'set_transient_' . $key );
369
				do_action( 'setted_transient', $key );
370
			}
371
		}
372
373
		do_action( 'pods_view_set_' . $cache_mode, $original_key, $value, $expires, $group );
374
375
		return $value;
376
	}
377
378
	/**
379
	 * @static
380
	 *
381
	 * Clear a cached value
382
	 *
383
	 * @param string|bool $key        Key for the cache
384
	 * @param string      $cache_mode (optional) Decides the caching method to use for the view.
385
	 * @param string      $group      (optional) Set the group.
386
	 *
387
	 * @return bool
388
	 *
389
	 * @since 2.0
390
	 */
391
	public static function clear( $key = true, $cache_mode = null, $group = '' ) {
392
393
		$object_cache = false;
394
395
		if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
396
			$object_cache = true;
397
		}
398
399
		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...
400
401
		if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
402
			$cache_mode = 'cache';
403
		}
404
405
		$group_key = 'pods_';
406
407
		if ( ! empty( $group ) ) {
408
			$group_key = $group . '_';
409
		}
410
411
		$full_key = $original_key = $key;
412
413
		if ( true !== $key ) {
414
			// Get proper cache key
415
			$key = self::get_key( $key, $group_key );
416
417
			$full_key = $group_key . $key;
418
		}
419
420
		if ( apply_filters( 'pods_view_cache_alt_set', false, $cache_mode, $full_key, $original_key, '', 0, $group ) ) {
421
			return true;
422
		} elseif ( 'transient' == $cache_mode ) {
423
			if ( true === $key ) {
424
				$group_key = pods_sanitize_like( $group_key );
425
426
				$wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE option_name LIKE '_transient_{$group_key}%'" );
427
428
				if ( $object_cache ) {
429
					wp_cache_flush();
430
				}
431
			} else {
432
				delete_transient( $group_key . $key );
433
			}
434
		} elseif ( 'site-transient' == $cache_mode ) {
435
			if ( true === $key ) {
436
				$group_key = pods_sanitize_like( $group_key );
437
438
				$wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE option_name LIKE '_site_transient_{$group_key}%'" );
439
440
				if ( $object_cache ) {
441
					wp_cache_flush();
442
				}
443
			} else {
444
				delete_site_transient( $group_key . $key );
445
			}
446
		} elseif ( 'cache' == $cache_mode && $object_cache ) {
447
			if ( true === $key ) {
448
				wp_cache_flush();
449
			} else {
450
				wp_cache_delete( ( empty( $key ) ? 'pods_view' : $key ), ( empty( $group ) ? 'pods_view' : $group ) );
451
			}
452
		} elseif ( 'option-cache' == $cache_mode ) {
453
			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...
454
455
			do_action( 'delete_transient_' . $key, $key );
456
457
			if ( $_wp_using_ext_object_cache ) {
458
				$result = wp_cache_delete( $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
459
460
				wp_cache_delete( '_timeout_' . $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
461
			} else {
462
				$option_timeout = '_pods_option_timeout_' . $key;
463
				$option         = '_pods_option_' . $key;
464
465
				$result = delete_option( $option );
466
467
				if ( $result ) {
468
					delete_option( $option_timeout );
469
				}
470
			}
471
472
			if ( $result ) {
473
				do_action( 'deleted_transient', $key );
474
			}
475
		}
476
477
		do_action( 'pods_view_clear_' . $cache_mode, $original_key, $group );
478
479
		return true;
480
	}
481
482
	/**
483
	 * @static
484
	 *
485
	 * @param            $_view
486
	 * @param null|array $_data
487
	 *
488
	 * @return bool|mixed|string|void
489
	 */
490
	public static function get_template_part( $_view, $_data = null ) {
491
492
		/* 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...
493
		if ( 0 === strpos( $_view, 'http://' ) || 0 === strpos( $_view, 'https://' ) ) {
494
			$_view = apply_filters( 'pods_view_url_include', $_view );
495
496
			if ( empty( $_view ) || ( defined( 'PODS_REMOTE_VIEWS' ) && PODS_REMOTE_VIEWS ) )
497
				return '';
498
499
			$response = wp_remote_get( $_view );
500
501
			return wp_remote_retrieve_body( $response );
502
		}*/
503
504
		$_view = self::locate_template( $_view );
505
506
		if ( empty( $_view ) ) {
507
			return $_view;
508
		}
509
510
		if ( ! empty( $_data ) && is_array( $_data ) ) {
511
			extract( $_data, EXTR_SKIP );
512
		}
513
514
		ob_start();
515
		require $_view;
516
		$output = ob_get_clean();
517
518
		return $output;
519
	}
520
521
	/**
522
	 * @static
523
	 *
524
	 * @param $_view
525
	 *
526
	 * @return bool|mixed|string|void
527
	 */
528
	private static function locate_template( $_view ) {
529
530
		if ( is_array( $_view ) ) {
531
			$_views = array();
532
533
			if ( isset( $_view[0] ) && false === strpos( $_view[0], '.php' ) ) {
534
				$_view_count = count( $_view );
535
536
				for ( $_view_x = $_view_count; 0 < $_view_x; $_view_x -- ) {
537
					$_view_v = array_slice( $_view, 0, $_view_x );
538
539
					$_views[] = implode( '-', $_view_v ) . '.php';
540
				}
541
			} else {
542
				$_views = $_view;
543
			}
544
545
			$_view = false;
546
547
			foreach ( $_views as $_view_check ) {
548
				$_view = self::locate_template( $_view_check );
549
550
				if ( ! empty( $_view ) ) {
551
					break;
552
				}
553
			}
554
555
			return $_view;
556
		}
557
558
		// Keep it safe
559
		$_view = trim( str_replace( array( '../', '\\' ), array( '', '/' ), (string) $_view ) );
560
561
		if ( empty( $_view ) ) {
562
			return false;
563
		}
564
565
		$_real_view = realpath( $_view );
566
567
		if ( empty( $_real_view ) ) {
568
			$_real_view = $_view;
569
		}
570
571
		$located = false;
572
573
		// Is the view's file somewhere within the plugin directory tree?
574
		// Note: we explicitly whitelist PODS_DIR for the case of symlinks (see issue #2945)
575
		if ( false !== strpos( $_real_view, realpath( WP_PLUGIN_DIR ) ) || false !== strpos( $_real_view, realpath( WPMU_PLUGIN_DIR ) ) || false !== strpos( $_real_view, PODS_DIR ) ) {
576
			if ( file_exists( $_view ) ) {
577
				$located = $_view;
578
			} else {
579
				$located = apply_filters( 'pods_view_locate_template', $located, $_view );
580
			}
581
582
		} else { // The view's file is outside the plugin directory
583
			$_real_view = trim( $_real_view, '/' );
584
585
			if ( empty( $_real_view ) ) {
586
				return false;
587
			}
588
589
			// Allow views in the theme or child theme
590
			if ( file_exists( realpath( get_stylesheet_directory() . '/' . $_real_view ) ) ) {
591
				$located = realpath( get_stylesheet_directory() . '/' . $_real_view );
592
			} elseif ( file_exists( realpath( get_template_directory() . '/' . $_real_view ) ) ) {
593
				$located = realpath( get_template_directory() . '/' . $_real_view );
594
			}
595
		}
596
597
		return $located;
598
599
	}
600
601
	/**
602
	 * Advanced $expires handling
603
	 *
604
	 * @param array|bool|int $expires
605
	 * @param string         $cache_mode
606
	 *
607
	 * @return bool|int
608
	 *
609
	 * @since 3.0
610
	 * @static
611
	 */
612
	public static function expires( $expires, $cache_mode = 'cache' ) {
613
614
		// Different $expires if user is anonymous or logged in or specific capability
615
		if ( is_array( $expires ) ) {
616
			if ( ( isset( $expires['anonymous'] ) || isset( $expires['user_with_access'] ) ) && isset( $expires['user'] ) ) {
617
				if ( isset( $expires['user_with_access'] ) ) {
618
					$expires = array(
619
						pods_var_raw( 'anonymous', $expires, false ),
620
						pods_var_raw( 'user', $expires, false ),
621
						pods_var_raw( 'user_with_access', $expires, false ),
622
						pods_var_raw( 'capability', $expires, null, null, true )
623
					);
624
				} elseif ( isset( $expires['anonymous'] ) ) {
625
					$expires = array(
626
						pods_var_raw( 'anonymous', $expires, false ),
627
						pods_var_raw( 'user', $expires, false ),
628
						pods_var_raw( 'capability', $expires, null, null, true )
629
					);
630
				}
631
			} else {
632
				$expires = array_values( $expires );
633
			}
634
635
			if ( 4 == count( $expires ) ) {
636
				if ( ! is_user_logged_in() ) {
637
					$expires = pods_var_raw( 0, $expires, false );
638 View Code Duplication
				} else {
639
					$user_no_access   = pods_var_raw( 1, $expires, false );
640
					$user_with_access = pods_var_raw( 2, $expires, false );
641
					$capability       = pods_var_raw( 3, $expires, null, null, true );
642
643
					$expires = pods_var_user( $user_no_access, $user_with_access, $capability );
644
				}
645 View Code Duplication
			} else {
646
				$anon       = pods_var_raw( 0, $expires, false );
647
				$user       = pods_var_raw( 1, $expires, false );
648
				$capability = pods_var_raw( 2, $expires, null, null, true );
649
650
				$expires = pods_var_user( $anon, $user, $capability );
651
			}
652
		}
653
654
		if ( 'none' == $cache_mode ) {
655
			$expires = false;
656
		} elseif ( false !== $expires ) {
657
			$expires = (int) $expires;
658
659
			if ( $expires < 1 ) {
660
				$expires = 0;
661
			}
662
		}
663
664
		return $expires;
665
666
	}
667
668
}
669