PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.0.10.5
Pods – Custom Content Types and Fields v3.0.10.5
2.7.31.4 2.8.23.5 2.9.19.5 3.0.10.5 3.1.4.3 3.2.8.4 3.3.9.2 2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / classes / PodsView.php
pods / classes Last commit date
cli 1 day ago fields 1 day ago widgets 1 day ago Pods.php 1 day ago PodsAPI.php 1 day ago PodsAdmin.php 1 day ago PodsArray.php 1 day ago PodsComponent.php 1 day ago PodsComponents.php 1 day ago PodsData.php 1 day ago PodsField.php 1 day ago PodsForm.php 1 day ago PodsI18n.php 1 day ago PodsInit.php 1 day ago PodsMeta.php 1 day ago PodsMigrate.php 1 day ago PodsRESTFields.php 1 day ago PodsRESTHandlers.php 1 day ago PodsTermSplitting.php 1 day ago PodsUI.php 1 day ago PodsView.php 1 day ago
PodsView.php
952 lines
1 <?php
2
3 use Pods\Static_Cache;
4
5 /**
6 * @package Pods
7 */
8 class PodsView {
9
10 /**
11 * List of keys that have been cached grouped by cache mode.
12 *
13 * @since 3.0
14 *
15 * @var array
16 */
17 private static $cached_keys = [
18 'transient' => [],
19 'site-transient' => [],
20 'cache' => [],
21 'static-cache' => [],
22 'option-cache' => [],
23 ];
24
25 /**
26 * @var array $cache_modes Array of available cache modes
27 */
28 public static $cache_modes = [
29 'none' => true,
30 'transient' => true,
31 'site-transient' => true,
32 'cache' => true,
33 'static-cache' => true,
34 'option-cache' => true,
35 ];
36
37 /**
38 * @return \PodsView
39 */
40 private function __construct() {
41 // !nope
42 }
43
44 /**
45 * Add a cache key to keep track of for a cache mode.
46 *
47 * @since 3.0
48 *
49 * @param string $cache_mode The cache mode.
50 * @param string $cache_key The cache key.
51 * @param null|string $group The cache group, if needed.
52 * @param null|string $original_key The original cache key, if different from the cache key.
53 */
54 public static function add_cached_key( $cache_mode, $cache_key, $group = null, $original_key = null ) {
55 if ( ! isset( self::$cached_keys[ $cache_mode ] ) ) {
56 self::$cached_keys[ $cache_mode ] = [];
57 }
58
59 if ( null === $original_key ) {
60 $original_key = $cache_key;
61 }
62
63 if ( $group ) {
64 if ( ! isset( self::$cached_keys[ $cache_mode ][ $group ] ) ) {
65 self::$cached_keys[ $cache_mode ][ $group ] = [];
66 }
67
68 self::$cached_keys[ $cache_mode ][ $group ][ $cache_key ] = $original_key;
69
70 return;
71 }
72
73 self::$cached_keys[ $cache_mode ][ $cache_key ] = $original_key;
74 }
75
76 /**
77 * Remove a cache key from tracking for a cache mode.
78 *
79 * @since 3.0
80 *
81 * @param string $cache_mode The cache mode.
82 * @param string $cache_key The cache key.
83 * @param null|string $group The cache group, if needed.
84 */
85 public static function remove_cached_key( $cache_mode, $cache_key, $group = null ) {
86 if ( ! isset( self::$cached_keys[ $cache_mode ] ) ) {
87 return;
88 }
89
90 if ( $group ) {
91 if ( ! isset( self::$cached_keys[ $cache_mode ][ $group ] ) ) {
92 return;
93 }
94
95 unset( self::$cached_keys[ $cache_mode ][ $group ][ $cache_key ] );
96
97 return;
98 }
99
100 if ( ! isset( self::$cached_keys[ $cache_mode ][ $cache_key ] ) ) {
101 return;
102 }
103
104 unset( self::$cached_keys[ $cache_mode ][ $cache_key ] );
105 }
106
107 /**
108 * Get the list of cache keys based on cache mode.
109 *
110 * @since 3.0
111 *
112 * @param string $cache_mode The cache mode.
113 * @param null|string $group The cache group, if needed.
114 */
115 public static function get_cached_keys( $cache_mode, $group = null ) : array {
116 if ( $group ) {
117 return self::$cached_keys[ $cache_mode ][ $group ] ?? [];
118 }
119
120 return self::$cached_keys[ $cache_mode ] ?? [];
121 }
122
123 /**
124 * Reset cache keys based on cache mode.
125 *
126 * @since 3.0
127 *
128 * @param null|string $cache_mode The cache mode, null if resetting all.
129 * @param null|string $group The cache group, if needed.
130 */
131 public static function reset_cached_keys( $cache_mode = null, $group = null ) {
132 if ( null === $cache_mode ) {
133 foreach ( self::$cache_modes as $cache_mode_to_reset => $unused ) {
134 if ( isset( self::$cached_keys[ $cache_mode_to_reset ] ) ) {
135 self::$cached_keys[ $cache_mode_to_reset ] = [];
136 }
137 }
138
139 return;
140 }
141
142 if ( $group ) {
143 if ( isset( self::$cached_keys[ $cache_mode ][ $group ] ) ) {
144 self::$cached_keys[ $cache_mode ][ $group ] = [];
145 }
146
147 return;
148 }
149
150 if ( isset( self::$cached_keys[ $cache_mode ] ) ) {
151 self::$cached_keys[ $cache_mode ] = [];
152 }
153 }
154
155 /**
156 * @static
157 *
158 * @param string $view Path of the view file
159 * @param array|null $data (optional) Data to pass on to the template
160 * @param bool|int|array $expires (optional) Time in seconds for the cache to expire, if 0 no expiration.
161 * @param string $cache_mode (optional) Decides the caching method to use for the view.
162 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
163 *
164 * @return bool|mixed|null|string|void
165 *
166 * @since 2.0.0
167 */
168 public static function view( $view, $data = null, $expires = false, $cache_mode = 'cache', $limited = false ) {
169
170 /**
171 * Override the value of $view. For example, using Pods AJAX View.
172 *
173 * To use, set first param to true. If that param in not null, this method returns its value.
174 *
175 * @param null|bool If not set to null, this filter overrides the rest of the method.
176 * @param string $view Path of the view file
177 * @param array|null $data (optional) Data to pass on to the template
178 * @param bool|int|array $expires (optional) Time in seconds for the cache to expire, if 0 no expiration.
179 * @param string $cache_mode (optional) Decides the caching method to use for the view.
180 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
181 *
182 * @since 2.4.1
183 */
184 $filter_check = apply_filters( 'pods_view_alt_view', null, $view, $data, $expires, $cache_mode );
185
186 if ( null !== $filter_check ) {
187 return $filter_check;
188 }
189
190 // Advanced $expires handling
191 $expires = self::expires( $expires, $cache_mode );
192
193 if ( ! self::is_cache_mode_valid( $cache_mode ) ) {
194 $cache_mode = 'cache';
195 }
196
197 // Support my-view.php?custom-key=X#hash keying for cache
198 $view_id = '';
199
200 if ( ! is_array( $view ) ) {
201 $view_q = explode( '?', $view );
202
203 if ( 1 < count( $view_q ) ) {
204 $view_id = '?' . $view_q[1];
205
206 $view = $view_q[0];
207 }
208
209 $view_h = explode( '#', $view );
210
211 if ( 1 < count( $view_h ) ) {
212 $view_id .= '#' . $view_h[1];
213
214 $view = $view_h[0];
215 }
216
217 // Support dynamic tags!
218 $view_id = pods_evaluate_tags( $view_id );
219 }
220
221 $view = apply_filters( 'pods_view_inc', $view, $data, $expires, $cache_mode, $limited );
222
223 $view_key = $view;
224
225 if ( is_array( $view_key ) ) {
226 $view_key = implode( '-', $view_key ) . '.php';
227 }
228
229 if ( false !== realpath( $view_key ) ) {
230 $view_key = realpath( $view_key );
231 }
232
233 $pods_ui_dir = realpath( PODS_DIR . 'ui/' );
234 $pods_components_dir = realpath( PODS_DIR . 'components/' );
235 $abspath_dir = realpath( ABSPATH );
236
237 $cache_key = pods_str_replace( $abspath_dir, '/', $view_key, 1 );
238
239 $output = false;
240
241 $caching = false;
242
243 if ( false !== $expires && false === strpos( $view_key, $pods_ui_dir ) && false === strpos( $view_key, $pods_components_dir ) ) {
244 $caching = true;
245 }
246
247 if ( $caching ) {
248 $output = self::get( 'pods-view-' . $cache_key . $view_id, $cache_mode, 'pods_view' );
249 }
250
251 if ( false === $output || null === $output ) {
252 $output = self::get_template_part( $view, $data );
253 }
254
255 if ( false !== $output && $caching ) {
256 self::set( 'pods-view-' . $cache_key . $view_id, $output, $expires, $cache_mode, 'pods_view' );
257 }
258
259 $output = apply_filters( "pods_view_output_{$cache_key}", $output, $view, $data, $expires, $cache_mode );
260 $output = apply_filters( 'pods_view_output', $output, $view, $data, $expires, $cache_mode );
261
262 return $output;
263 }
264
265 /**
266 * Get the full path of the view if it exists.
267 *
268 * @since 3.1.0
269 *
270 * @param string $view Path of the view file
271 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
272 *
273 * @return string|false The full path of the view if it exists.
274 */
275 public static function view_get_path( $view, $limited = false ) {
276 // Support my-view.php?custom-key=X#hash keying for cache
277 if ( ! is_array( $view ) ) {
278 $view_q = explode( '?', $view );
279
280 if ( 1 < count( $view_q ) ) {
281 $view = $view_q[0];
282 }
283
284 $view_h = explode( '#', $view );
285
286 if ( 1 < count( $view_h ) ) {
287 $view = $view_h[0];
288 }
289 }
290
291 $view = apply_filters( 'pods_view_inc', $view, null, false, 'cache', $limited );
292
293 $view_key = $view;
294
295 if ( is_array( $view_key ) ) {
296 $view_key = implode( '-', $view_key ) . '.php';
297 }
298
299 if ( false !== realpath( $view_key ) ) {
300 $view_key = realpath( $view_key );
301 }
302
303 $view_path = self::locate_template( $view_key, $limited );
304
305 if ( empty( $view_path ) ) {
306 return false;
307 }
308
309 return $view_path;
310 }
311
312 /**
313 * Get the cache key, salted with current Pods version, peppered with md5 if too long
314 *
315 * @param string $key
316 * @param string $group_key
317 *
318 * @return string
319 *
320 * @since 2.6.2
321 */
322 public static function get_key( $key, $group_key = '' ) {
323
324 // Add some salt
325 $key .= '-' . sanitize_key( PODS_VERSION );
326
327 // Patch for limitations in DB
328 if ( is_string( $group_key ) && 44 < strlen( $group_key . $key ) ) {
329 $key = md5( $key );
330 }
331
332 return $key;
333
334 }
335
336 /**
337 * @static
338 *
339 * @param string $key Key for the cache
340 * @param string $cache_mode (optional) Decides the caching method to use for the view.
341 * @param string $group (optional) Set the group of the value.
342 * @param string $callback (optional) Callback function to run to set the value if not cached.
343 *
344 * @return bool|mixed|null|void
345 *
346 * @since 2.0.0
347 */
348 public static function get( $key, $cache_mode = 'cache', $group = '', $callback = null ) {
349 $external_object_cache = wp_using_ext_object_cache();
350
351 $object_cache_enabled = (
352 (
353 isset( $GLOBALS['wp_object_cache'] )
354 && is_object( $GLOBALS['wp_object_cache'] )
355 )
356 || $external_object_cache
357 );
358
359 if ( ! self::is_cache_mode_valid( $cache_mode ) ) {
360 $cache_mode = 'cache';
361 }
362
363 $group_key = 'pods_';
364
365 if ( ! empty( $group ) ) {
366 $group_key = $group . '_';
367 }
368
369 $original_key = $key;
370
371 // Get proper cache key
372 $key = self::get_key( $key, $group_key );
373
374 $value = null;
375
376 $called = false;
377
378 $pods_nocache = pods_v( 'pods_nocache' );
379 $nocache = array();
380
381 if ( null !== $pods_nocache && pods_is_admin() ) {
382 if ( is_string( $pods_nocache ) && 1 < strlen( $pods_nocache ) ) {
383 $nocache = explode( ',', $pods_nocache );
384 $nocache = array_flip( $nocache );
385 } else {
386 $nocache = self::$cache_modes;
387 }
388 }
389
390 $cache_enabled = ! isset( $nocache[ $cache_mode ] );
391
392 if ( apply_filters( 'pods_view_cache_alt_get', false, $cache_mode, $group_key . $key, $original_key, $group ) ) {
393 $value = apply_filters( 'pods_view_cache_alt_get_value', $value, $cache_mode, $group_key . $key, $original_key, $group );
394 } elseif ( $cache_enabled ) {
395 if ( 'transient' === $cache_mode ) {
396 $value = get_transient( $group_key . $key );
397 } elseif ( 'site-transient' === $cache_mode ) {
398 $value = get_site_transient( $group_key . $key );
399 } elseif ( 'cache' === $cache_mode && $object_cache_enabled ) {
400 $value = wp_cache_get( $key, ( empty( $group ) ? 'pods_view' : $group ) );
401 } elseif ( 'option-cache' === $cache_mode ) {
402 $pre = apply_filters( "pre_transient_{$key}", false );
403
404 if ( false !== $pre ) {
405 $value = $pre;
406 } elseif ( $external_object_cache ) {
407 $cache_found = false;
408
409 $value = wp_cache_get( $key, ( empty( $group ) ? 'pods_option_cache' : $group ), false, $cache_found );
410
411 if ( false === $value || ! $cache_found ) {
412 if ( is_callable( $callback ) ) {
413 // Callback function should do it's own set/update for cache
414 $callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
415
416 if ( null !== $callback_value && false !== $callback_value ) {
417 $value = $callback_value;
418 }
419
420 $called = true;
421 }
422 }
423 } else {
424 $transient_option = '_pods_option_' . $key;
425 $transient_timeout = '_pods_option_timeout_' . $key;
426
427 $value = get_option( $transient_option );
428 $timeout = get_option( $transient_timeout );
429
430 if ( ! empty( $timeout ) && $timeout < time() ) {
431 if ( is_callable( $callback ) ) {
432 // Callback function should do it's own set/update for cache
433 $callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
434
435 if ( null !== $callback_value && false !== $callback_value ) {
436 $value = $callback_value;
437 }
438
439 $called = true;
440 } else {
441 $value = false;
442
443 delete_option( $transient_option );
444 delete_option( $transient_timeout );
445 }
446 }
447 }//end if
448
449 if ( false !== $value ) {
450 $value = apply_filters( "transient_{$key}", $value );
451 }
452 } elseif ( 'static-cache' === $cache_mode ) {
453 $static_cache = pods_container( Static_Cache::class );
454
455 if ( $static_cache ) {
456 $value = $static_cache->get( $key, ( empty( $group ) ? 'pods_view' : $group ) );
457 } else {
458 $value = false;
459 }
460 } else {
461 $value = false;
462 }//end if
463 } else {
464 $value = false;
465 }//end if
466
467 if ( false === $value && is_callable( $callback ) && ! $called ) {
468 // Callback function should do it's own set/update for cache
469 $callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
470
471 if ( null !== $callback_value && false !== $callback_value ) {
472 $value = $callback_value;
473 }
474 }
475
476 $value = apply_filters( "pods_view_get_{$cache_mode}", $value, $original_key, $group );
477
478 return $value;
479 }
480
481 /**
482 * @static
483 *
484 * Set a cached value
485 *
486 * @param string $key Key for the cache
487 * @param mixed $value Value to add to the cache
488 * @param int $expires (optional) Time in seconds for the cache to expire, if 0 no expiration.
489 * @param string $cache_mode (optional) Decides the caching method to use for the view.
490 * @param string $group (optional) Set the group of the value.
491 *
492 * @return bool|mixed|null|string|void
493 *
494 * @since 2.0.0
495 */
496 public static function set( $key, $value, $expires = 0, $cache_mode = null, $group = '' ) {
497 $external_object_cache = wp_using_ext_object_cache();
498
499 $object_cache_enabled = (
500 (
501 isset( $GLOBALS['wp_object_cache'] )
502 && is_object( $GLOBALS['wp_object_cache'] )
503 )
504 || $external_object_cache
505 );
506
507 // Advanced $expires handling
508 $expires = self::expires( $expires, $cache_mode );
509
510 if ( ! self::is_cache_mode_valid( $cache_mode ) ) {
511 $cache_mode = 'cache';
512 }
513
514 $group_key = 'pods_';
515
516 if ( ! empty( $group ) ) {
517 $group_key = $group . '_';
518 }
519
520 $original_key = $key;
521
522 // Get proper cache key
523 $key = self::get_key( $key, $group_key );
524
525 if ( apply_filters( 'pods_view_cache_alt_set', false, $cache_mode, $group_key . $key, $original_key, $value, $expires, $group ) ) {
526 self::add_cached_key( $cache_mode, $group_key . $key, null, $original_key );
527
528 return $value;
529 } elseif ( 'transient' === $cache_mode ) {
530 self::add_cached_key( $cache_mode, $group_key . $key, null, $original_key );
531
532 set_transient( $group_key . $key, $value, $expires );
533 } elseif ( 'site-transient' === $cache_mode ) {
534 self::add_cached_key( $cache_mode, $group_key . $key, null, $original_key );
535
536 set_site_transient( $group_key . $key, $value, $expires );
537 } elseif ( 'cache' === $cache_mode && $object_cache_enabled ) {
538 $group = ( empty( $group ) ? 'pods_view' : $group );
539 $key = ( empty( $key ) ? 'pods_view' : $key );
540
541 self::add_cached_key( $cache_mode, $key, $group, $original_key );
542
543 wp_cache_set( $key, $value, $group, $expires );
544 } elseif ( 'option-cache' === $cache_mode ) {
545 $group = ( empty( $group ) ? 'pods_option_cache' : $group );
546
547 $value = apply_filters( "pre_set_transient_{$key}", $value );
548
549 if ( $external_object_cache ) {
550 $result = wp_cache_set( $key, $value, $group, $expires );
551 } else {
552 $transient_timeout = '_pods_option_timeout_' . $key;
553 $key = '_pods_option_' . $key;
554
555 if ( false === get_option( $key ) ) {
556 if ( $expires ) {
557 add_option( $transient_timeout, time() + $expires, '', 'no' );
558 }
559
560 $result = add_option( $key, $value, '', 'no' );
561 } else {
562 if ( $expires ) {
563 update_option( $transient_timeout, time() + $expires );
564 }
565
566 $result = update_option( $key, $value );
567 }
568 }//end if
569
570 self::add_cached_key( $cache_mode, $key, $group, $original_key );
571
572 if ( $result ) {
573 do_action( "set_transient_{$key}" );
574 do_action( 'setted_transient', $key );
575 }
576 } elseif ( 'static-cache' === $cache_mode ) {
577 $static_cache = pods_container( Static_Cache::class );
578
579 if ( $static_cache ) {
580 $group = ( empty( $group ) ? __CLASS__ : $group );
581
582 self::add_cached_key( $cache_mode, $key, $group, $original_key );
583
584 $static_cache->set( $key, $value, $group );
585 }
586 }//end if
587
588 do_action( "pods_view_set_{$cache_mode}", $original_key, $value, $expires, $group );
589
590 return $value;
591 }
592
593 /**
594 * @static
595 *
596 * Clear a cached value
597 *
598 * @param string|bool $key Key for the cache
599 * @param string $cache_mode (optional) Decides the caching method to use for the view.
600 * @param string $group (optional) Set the group.
601 *
602 * @return bool
603 *
604 * @since 2.0.0
605 */
606 public static function clear( $key = true, $cache_mode = null, $group = '' ) {
607 $external_object_cache = wp_using_ext_object_cache();
608
609 $object_cache_enabled = (
610 (
611 isset( $GLOBALS['wp_object_cache'] )
612 && is_object( $GLOBALS['wp_object_cache'] )
613 )
614 || $external_object_cache
615 );
616
617 global $wpdb;
618
619 if ( ! self::is_cache_mode_valid( $cache_mode ) ) {
620 $cache_mode = 'cache';
621 }
622
623 $group_key = 'pods_';
624
625 if ( ! empty( $group ) ) {
626 $group_key = $group . '_';
627 }
628
629 $full_key = $key;
630 $original_key = $key;
631
632 if ( true !== $key ) {
633 // Get proper cache key
634 $key = self::get_key( $key, $group_key );
635
636 $full_key = $group_key . $key;
637 }
638
639 if ( apply_filters( 'pods_view_cache_alt_set', false, $cache_mode, $full_key, $original_key, '', 0, $group ) ) {
640 self::remove_cached_key( $cache_mode, $full_key );
641
642 return true;
643 } elseif ( 'transient' === $cache_mode ) {
644 if ( true === $key ) {
645 $group_key = pods_sanitize_like( $group_key );
646
647 $wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE option_name LIKE '_transient_{$group_key}%'" );
648
649 if ( $object_cache_enabled ) {
650 if ( $group && function_exists( 'wp_cache_flush_group' ) && wp_cache_supports( 'flush_group' ) ) {
651 wp_cache_flush_group( $group );
652 } else {
653 wp_cache_flush();
654 }
655 }
656
657 self::reset_cached_keys( $cache_mode );
658 } else {
659 delete_transient( $group_key . $key );
660
661 self::remove_cached_key( $cache_mode, $group_key . $key );
662 }
663 } elseif ( 'site-transient' === $cache_mode ) {
664 if ( true === $key ) {
665 $group_key = pods_sanitize_like( $group_key );
666
667 $wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE option_name LIKE '_site_transient_{$group_key}%'" );
668
669 if ( $object_cache_enabled ) {
670 if ( $group && function_exists( 'wp_cache_flush_group' ) && wp_cache_supports( 'flush_group' ) ) {
671 wp_cache_flush_group( $group );
672 } else {
673 wp_cache_flush();
674 }
675 }
676
677 self::reset_cached_keys( $cache_mode );
678 } else {
679 delete_site_transient( $group_key . $key );
680
681 self::remove_cached_key( $cache_mode, $group_key . $key );
682 }
683 } elseif ( 'cache' === $cache_mode && $object_cache_enabled ) {
684 if ( true === $key ) {
685 if ( $group && function_exists( 'wp_cache_flush_group' ) && wp_cache_supports( 'flush_group' ) ) {
686 wp_cache_flush_group( $group );
687
688 self::reset_cached_keys( $cache_mode, $group );
689 } else {
690 wp_cache_flush();
691
692 self::reset_cached_keys( $cache_mode );
693 }
694 } else {
695 $group = ( empty( $group ) ? 'pods_view' : $group );
696 $key = ( empty( $key ) ? 'pods_view' : $key );
697
698 wp_cache_delete( $key, $group );
699
700 self::remove_cached_key( $cache_mode, $key, $group );
701 }
702 } elseif ( 'option-cache' === $cache_mode ) {
703 do_action( "delete_transient_{$key}", $key );
704
705 $group = ( empty( $group ) ? 'pods_option_cache' : $group );
706
707 if ( $external_object_cache ) {
708 $result = wp_cache_delete( $key, $group );
709
710 wp_cache_delete( '_timeout_' . $key, $group );
711 } else {
712 $option_timeout = '_pods_option_timeout_' . $key;
713 $option = '_pods_option_' . $key;
714
715 $result = delete_option( $option );
716
717 if ( $result ) {
718 delete_option( $option_timeout );
719 }
720 }
721
722 self::remove_cached_key( $cache_mode, $key, $group );
723
724 if ( $result ) {
725 do_action( 'deleted_transient', $key );
726 }
727 } elseif ( 'static-cache' === $cache_mode ) {
728 $static_cache = pods_container( Static_Cache::class );
729
730 if ( $static_cache ) {
731 $group = ( empty( $group ) ? __CLASS__ : $group );
732
733 if ( true === $key ) {
734 $static_cache->flush( $group );
735
736 self::reset_cached_keys( $cache_mode, $group );
737 } else {
738 $static_cache->delete( $key, $group );
739
740 self::remove_cached_key( $cache_mode, $key, $group );
741 }
742 }
743 }//end if
744
745 do_action( "pods_view_clear_{$cache_mode}", $original_key, $group );
746
747 return true;
748 }
749
750 /**
751 * @static
752 *
753 * @param $_view
754 * @param null|array $_data
755 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
756 *
757 * @return bool|mixed|string|void
758 */
759 public static function get_template_part( $_view, $_data = null, $limited = false ) {
760
761 /*
762 To be reviewed later, should have more checks and restrictions like a whitelist etc.
763
764 if ( 0 === strpos( $_view, 'http://' ) || 0 === strpos( $_view, 'https://' ) ) {
765 $_view = apply_filters( 'pods_view_url_include', $_view );
766
767 if ( empty( $_view ) || ( defined( 'PODS_REMOTE_VIEWS' ) && PODS_REMOTE_VIEWS ) )
768 return '';
769
770 $response = wp_remote_get( $_view );
771
772 return wp_remote_retrieve_body( $response );
773 }
774 */
775
776 $_view = self::locate_template( $_view, $limited );
777
778 if ( empty( $_view ) ) {
779 return $_view;
780 }
781
782 if ( ! empty( $_data ) && is_array( $_data ) ) {
783 // Only expose array entries whose keys are valid PHP variable names as template variables (EXTR_SKIP prevents overwriting existing scope), to help prevent security issues.
784 $_safe_data = array_filter(
785 $_data,
786 static function ( $key ) {
787 return is_string( $key ) && preg_match( '/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $key );
788 },
789 ARRAY_FILTER_USE_KEY
790 );
791
792 extract( $_safe_data, EXTR_SKIP );
793 }
794
795 ob_start();
796 require $_view;
797 $output = ob_get_clean();
798
799 return $output;
800 }
801
802 /**
803 * @static
804 *
805 * @param array|string $_view
806 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
807 *
808 * @return bool|mixed|string|void
809 */
810 private static function locate_template( $_view, $limited = false ) {
811 if ( is_array( $_view ) ) {
812 $_views = [];
813
814 if ( isset( $_view[0] ) && false === strpos( $_view[0], '.php' ) ) {
815 $_view_count = count( $_view );
816
817 for ( $_view_x = $_view_count; 0 < $_view_x; $_view_x -- ) {
818 $_view_v = array_slice( $_view, 0, $_view_x );
819
820 $_views[] = implode( '-', $_view_v ) . '.php';
821 }
822 } else {
823 $_views = $_view;
824 }
825
826 $_view = false;
827
828 foreach ( $_views as $_view_check ) {
829 $_view = self::locate_template( $_view_check );
830
831 if ( ! empty( $_view ) ) {
832 break;
833 }
834 }
835
836 return $_view;
837 }//end if
838
839 $paths_to_check = [ 'plugins', 'pods', 'theme' ];
840
841 if ( $limited ) {
842 $paths_to_check = [ 'theme' ];
843 }
844
845 // Is the view's file somewhere within the plugin directory tree?
846 // Note: we include PODS_DIR for the case of symlinks (see issue #2945).
847 $located = pods_validate_safe_path( $_view, $paths_to_check );
848
849 /**
850 * Allow filtering the validated view file path to use.
851 *
852 * @since unknown
853 *
854 * @param string|false $located The validated view file path to use, or false if it was not valid.
855 * @param string $_view The original view file path to use.
856 */
857 $located = apply_filters( 'pods_view_locate_template', $located, $_view );
858
859 if ( ! $located ) {
860 return false;
861 }
862
863 return $located;
864
865 }
866
867 /**
868 * Advanced $expires handling
869 *
870 * @param array|bool|int $expires
871 * @param string $cache_mode
872 *
873 * @return bool|int
874 *
875 * @since 2.7.0
876 * @static
877 */
878 public static function expires( $expires, $cache_mode = 'cache' ) {
879
880 // Different $expires if user is anonymous or logged in or specific capability
881 if ( is_array( $expires ) ) {
882 if ( ( isset( $expires['anonymous'] ) || isset( $expires['user_with_access'] ) ) && isset( $expires['user'] ) ) {
883 if ( isset( $expires['user_with_access'] ) ) {
884 $expires = array(
885 pods_v( 'anonymous', $expires, false ),
886 pods_v( 'user', $expires, false ),
887 pods_v( 'user_with_access', $expires, false ),
888 pods_v( 'capability', $expires, null, null, true ),
889 );
890 } elseif ( isset( $expires['anonymous'] ) ) {
891 $expires = array(
892 pods_v( 'anonymous', $expires, false ),
893 pods_v( 'user', $expires, false ),
894 pods_v( 'capability', $expires, null, null, true ),
895 );
896 }
897 } else {
898 $expires = array_values( $expires );
899 }
900
901 if ( 4 === count( $expires ) ) {
902 if ( ! is_user_logged_in() ) {
903 $expires = pods_v( 0, $expires, false );
904 } else {
905 $user_no_access = pods_v( 1, $expires, false );
906 $user_with_access = pods_v( 2, $expires, false );
907 $capability = pods_v( 3, $expires, null, true );
908
909 $expires = pods_var_user( $user_no_access, $user_with_access, $capability );
910 }
911 } else {
912 $anon = pods_v( 0, $expires, false );
913 $user = pods_v( 1, $expires, false );
914 $capability = pods_v( 2, $expires, null, true );
915
916 $expires = pods_var_user( $anon, $user, $capability );
917 }
918 }//end if
919
920 if ( 'none' === $cache_mode ) {
921 $expires = false;
922 } elseif ( false !== $expires ) {
923 $expires = (int) $expires;
924
925 if ( $expires < 1 ) {
926 $expires = 0;
927 }
928 }
929
930 return $expires;
931
932 }
933
934 /**
935 * Determine whether the cache mode is valid.
936 *
937 * @since 2.9.14
938 *
939 * @param string|mixed $cache_mode The cache mode.
940 *
941 * @return bool Whether the cache mode is valid.
942 */
943 public static function is_cache_mode_valid( $cache_mode ) {
944 return (
945 $cache_mode
946 && is_string( $cache_mode )
947 && isset( self::$cache_modes[ $cache_mode ] )
948 );
949 }
950
951 }
952