PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 2.7.31.4
Pods – Custom Content Types and Fields v2.7.31.4
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 3 days ago fields 3 days ago widgets 3 days ago Pods.php 3 days ago PodsAPI.php 3 days ago PodsAdmin.php 3 days ago PodsArray.php 3 days ago PodsComponent.php 3 days ago PodsComponents.php 3 days ago PodsData.php 3 days ago PodsField.php 3 days ago PodsForm.php 3 days ago PodsI18n.php 3 days ago PodsInit.php 3 days ago PodsMeta.php 3 days ago PodsMigrate.php 3 days ago PodsRESTFields.php 3 days ago PodsRESTHandlers.php 3 days ago PodsTermSplitting.php 3 days ago PodsUI.php 3 days ago PodsView.php 3 days ago
PodsView.php
720 lines
1 <?php
2
3 /**
4 * @package Pods
5 */
6 class PodsView {
7
8 /**
9 * @var array $cache_modes Array of available cache modes
10 */
11 public static $cache_modes = array( 'none', 'transient', 'site-transient', 'cache', 'option-cache' );
12
13 /**
14 * @return \PodsView
15 */
16 private function __construct() {
17
18 // !nope
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 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
29 *
30 * @return bool|mixed|null|string|void
31 *
32 * @since 2.0.0
33 */
34 public static function view( $view, $data = null, $expires = false, $cache_mode = 'cache', $limited = false ) {
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 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
47 *
48 * @since 2.4.1
49 */
50 $filter_check = apply_filters( 'pods_view_alt_view', null, $view, $data, $expires, $cache_mode, $limited );
51
52 if ( null !== $filter_check ) {
53 return $filter_check;
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, $limited );
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 full path of the view if it exists.
133 *
134 * @since 3.1.0
135 *
136 * @param string $view Path of the view file
137 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
138 *
139 * @return string|false The full path of the view if it exists.
140 */
141 public static function view_get_path( $view, $limited = false ) {
142 // Support my-view.php?custom-key=X#hash keying for cache
143 if ( ! is_array( $view ) ) {
144 $view_q = explode( '?', $view );
145
146 if ( 1 < count( $view_q ) ) {
147 $view = $view_q[0];
148 }
149
150 $view_h = explode( '#', $view );
151
152 if ( 1 < count( $view_h ) ) {
153 $view = $view_h[0];
154 }
155 }
156
157 $view = apply_filters( 'pods_view_inc', $view, null, false, 'cache', $limited );
158
159 $view_key = $view;
160
161 if ( is_array( $view_key ) ) {
162 $view_key = implode( '-', $view_key ) . '.php';
163 }
164
165 if ( false !== realpath( $view_key ) ) {
166 $view_key = realpath( $view_key );
167 }
168
169 $view_path = self::locate_template( $view_key, $limited );
170
171 if ( empty( $view_path ) ) {
172 return false;
173 }
174
175 return $view_path;
176 }
177
178 /**
179 * Get the cache key, salted with current Pods version, peppered with md5 if too long
180 *
181 * @param string $key
182 * @param string $group_key
183 *
184 * @return string
185 *
186 * @since 2.6.2
187 */
188 public static function get_key( $key, $group_key = '' ) {
189
190 // Add some salt
191 $key .= '-' . PODS_VERSION;
192
193 // Patch for limitations in DB
194 if ( 44 < strlen( $group_key . $key ) ) {
195 $key = md5( $key );
196 }
197
198 return $key;
199
200 }
201
202 /**
203 * @static
204 *
205 * @param string $key Key for the cache
206 * @param string $cache_mode (optional) Decides the caching method to use for the view.
207 * @param string $group (optional) Set the group of the value.
208 * @param string $callback (optional) Callback function to run to set the value if not cached.
209 *
210 * @return bool|mixed|null|void
211 *
212 * @since 2.0.0
213 */
214 public static function get( $key, $cache_mode = 'cache', $group = '', $callback = null ) {
215
216 $object_cache = false;
217
218 if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
219 $object_cache = true;
220 }
221
222 if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
223 $cache_mode = 'cache';
224 }
225
226 $group_key = 'pods_';
227
228 if ( ! empty( $group ) ) {
229 $group_key = $group . '_';
230 }
231
232 $original_key = $key;
233
234 // Get proper cache key
235 $key = self::get_key( $key, $group_key );
236
237 $value = null;
238
239 $called = false;
240
241 $pods_nocache = pods_var_raw( 'pods_nocache' );
242 $nocache = array();
243
244 if ( null !== $pods_nocache && pods_is_admin() ) {
245 if ( 1 < strlen( $pods_nocache ) ) {
246 $nocache = explode( ',', $pods_nocache );
247 } else {
248 $nocache = self::$cache_modes;
249 }
250 }
251
252 if ( apply_filters( 'pods_view_cache_alt_get', false, $cache_mode, $group_key . $key, $original_key, $group ) ) {
253 $value = apply_filters( 'pods_view_cache_alt_get_value', $value, $cache_mode, $group_key . $key, $original_key, $group );
254 } elseif ( 'transient' === $cache_mode && ! in_array( $cache_mode, $nocache ) ) {
255 $value = get_transient( $group_key . $key );
256 } elseif ( 'site-transient' === $cache_mode && ! in_array( $cache_mode, $nocache ) ) {
257 $value = get_site_transient( $group_key . $key );
258 } elseif ( 'cache' === $cache_mode && $object_cache && ! in_array( $cache_mode, $nocache ) ) {
259 $value = wp_cache_get( $key, ( empty( $group ) ? 'pods_view' : $group ) );
260 } elseif ( 'option-cache' === $cache_mode && ! in_array( $cache_mode, $nocache ) ) {
261 global $_wp_using_ext_object_cache;
262
263 $pre = apply_filters( "pre_transient_{$key}", false );
264
265 if ( false !== $pre ) {
266 $value = $pre;
267 } elseif ( $_wp_using_ext_object_cache ) {
268 $cache_found = false;
269
270 $value = wp_cache_get( $key, ( empty( $group ) ? 'pods_option_cache' : $group ), false, $cache_found );
271
272 if ( false === $value || ! $cache_found ) {
273 if ( is_callable( $callback ) ) {
274 // Callback function should do it's own set/update for cache
275 $callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
276
277 if ( null !== $callback_value && false !== $callback_value ) {
278 $value = $callback_value;
279 }
280
281 $called = true;
282 }
283 }
284 } else {
285 $transient_option = '_pods_option_' . $key;
286 $transient_timeout = '_pods_option_timeout_' . $key;
287
288 $value = get_option( $transient_option );
289 $timeout = get_option( $transient_timeout );
290
291 if ( ! empty( $timeout ) && $timeout < time() ) {
292 if ( is_callable( $callback ) ) {
293 // Callback function should do it's own set/update for cache
294 $callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
295
296 if ( null !== $callback_value && false !== $callback_value ) {
297 $value = $callback_value;
298 }
299
300 $called = true;
301 } else {
302 $value = false;
303
304 delete_option( $transient_option );
305 delete_option( $transient_timeout );
306 }
307 }
308 }//end if
309
310 if ( false !== $value ) {
311 $value = apply_filters( "transient_{$key}", $value );
312 }
313 } else {
314 $value = false;
315 }//end if
316
317 if ( false === $value && is_callable( $callback ) && ! $called ) {
318 // Callback function should do it's own set/update for cache
319 $callback_value = call_user_func( $callback, $original_key, $group, $cache_mode );
320
321 if ( null !== $callback_value && false !== $callback_value ) {
322 $value = $callback_value;
323 }
324 }
325
326 $value = apply_filters( "pods_view_get_{$cache_mode}", $value, $original_key, $group );
327
328 return $value;
329 }
330
331 /**
332 * @static
333 *
334 * Set a cached value
335 *
336 * @param string $key Key for the cache
337 * @param mixed $value Value to add to the cache
338 * @param int $expires (optional) Time in seconds for the cache to expire, if 0 no expiration.
339 * @param string $cache_mode (optional) Decides the caching method to use for the view.
340 * @param string $group (optional) Set the group of the value.
341 *
342 * @return bool|mixed|null|string|void
343 *
344 * @since 2.0.0
345 */
346 public static function set( $key, $value, $expires = 0, $cache_mode = null, $group = '' ) {
347
348 $object_cache = false;
349
350 if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
351 $object_cache = true;
352 }
353
354 // Advanced $expires handling
355 $expires = self::expires( $expires, $cache_mode );
356
357 if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
358 $cache_mode = 'cache';
359 }
360
361 $group_key = 'pods_';
362
363 if ( ! empty( $group ) ) {
364 $group_key = $group . '_';
365 }
366
367 $original_key = $key;
368
369 // Get proper cache key
370 $key = self::get_key( $key, $group_key );
371
372 if ( apply_filters( 'pods_view_cache_alt_set', false, $cache_mode, $group_key . $key, $original_key, $value, $expires, $group ) ) {
373 return $value;
374 } elseif ( 'transient' === $cache_mode ) {
375 set_transient( $group_key . $key, $value, $expires );
376 } elseif ( 'site-transient' === $cache_mode ) {
377 set_site_transient( $group_key . $key, $value, $expires );
378 } elseif ( 'cache' === $cache_mode && $object_cache ) {
379 wp_cache_set( $key, $value, ( empty( $group ) ? 'pods_view' : $group ), $expires );
380 } elseif ( 'option-cache' === $cache_mode ) {
381 global $_wp_using_ext_object_cache;
382
383 $value = apply_filters( "pre_set_transient_{$key}", $value );
384
385 if ( $_wp_using_ext_object_cache ) {
386 $result = wp_cache_set( $key, $value, ( empty( $group ) ? 'pods_option_cache' : $group ), $expires );
387 } else {
388 $transient_timeout = '_pods_option_timeout_' . $key;
389 $key = '_pods_option_' . $key;
390
391 if ( false === get_option( $key ) ) {
392 if ( $expires ) {
393 add_option( $transient_timeout, time() + $expires, '', 'no' );
394 }
395
396 $result = add_option( $key, $value, '', 'no' );
397 } else {
398 if ( $expires ) {
399 update_option( $transient_timeout, time() + $expires );
400 }
401
402 $result = update_option( $key, $value );
403 }
404 }//end if
405
406 if ( $result ) {
407 do_action( "set_transient_{$key}" );
408 do_action( 'setted_transient', $key );
409 }
410 }//end if
411
412 do_action( "pods_view_set_{$cache_mode}", $original_key, $value, $expires, $group );
413
414 return $value;
415 }
416
417 /**
418 * @static
419 *
420 * Clear a cached value
421 *
422 * @param string|bool $key Key for the cache
423 * @param string $cache_mode (optional) Decides the caching method to use for the view.
424 * @param string $group (optional) Set the group.
425 *
426 * @return bool
427 *
428 * @since 2.0.0
429 */
430 public static function clear( $key = true, $cache_mode = null, $group = '' ) {
431
432 $object_cache = false;
433
434 if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
435 $object_cache = true;
436 }
437
438 global $wpdb;
439
440 if ( ! in_array( $cache_mode, self::$cache_modes ) ) {
441 $cache_mode = 'cache';
442 }
443
444 $group_key = 'pods_';
445
446 if ( ! empty( $group ) ) {
447 $group_key = $group . '_';
448 }
449
450 $full_key = $key;
451 $original_key = $key;
452
453 if ( true !== $key ) {
454 // Get proper cache key
455 $key = self::get_key( $key, $group_key );
456
457 $full_key = $group_key . $key;
458 }
459
460 if ( apply_filters( 'pods_view_cache_alt_set', false, $cache_mode, $full_key, $original_key, '', 0, $group ) ) {
461 return true;
462 } elseif ( 'transient' === $cache_mode ) {
463 if ( true === $key ) {
464 $group_key = pods_sanitize_like( $group_key );
465
466 $wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE option_name LIKE '_transient_{$group_key}%'" );
467
468 if ( $object_cache ) {
469 wp_cache_flush();
470 }
471 } else {
472 delete_transient( $group_key . $key );
473 }
474 } elseif ( 'site-transient' === $cache_mode ) {
475 if ( true === $key ) {
476 $group_key = pods_sanitize_like( $group_key );
477
478 $wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE option_name LIKE '_site_transient_{$group_key}%'" );
479
480 if ( $object_cache ) {
481 wp_cache_flush();
482 }
483 } else {
484 delete_site_transient( $group_key . $key );
485 }
486 } elseif ( 'cache' === $cache_mode && $object_cache ) {
487 if ( true === $key ) {
488 wp_cache_flush();
489 } else {
490 wp_cache_delete( ( empty( $key ) ? 'pods_view' : $key ), ( empty( $group ) ? 'pods_view' : $group ) );
491 }
492 } elseif ( 'option-cache' === $cache_mode ) {
493 global $_wp_using_ext_object_cache;
494
495 do_action( "delete_transient_{$key}", $key );
496
497 if ( $_wp_using_ext_object_cache ) {
498 $result = wp_cache_delete( $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
499
500 wp_cache_delete( '_timeout_' . $key, ( empty( $group ) ? 'pods_option_cache' : $group ) );
501 } else {
502 $option_timeout = '_pods_option_timeout_' . $key;
503 $option = '_pods_option_' . $key;
504
505 $result = delete_option( $option );
506
507 if ( $result ) {
508 delete_option( $option_timeout );
509 }
510 }
511
512 if ( $result ) {
513 do_action( 'deleted_transient', $key );
514 }
515 }//end if
516
517 do_action( "pods_view_clear_{$cache_mode}", $original_key, $group );
518
519 return true;
520 }
521
522 /**
523 * @static
524 *
525 * @param $_view
526 * @param null|array $_data
527 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
528 *
529 * @return bool|mixed|string|void
530 */
531 public static function get_template_part( $_view, $_data = null, $limited = false ) {
532
533 /*
534 To be reviewed later, should have more checks and restrictions like a whitelist etc.
535
536 if ( 0 === strpos( $_view, 'http://' ) || 0 === strpos( $_view, 'https://' ) ) {
537 $_view = apply_filters( 'pods_view_url_include', $_view );
538
539 if ( empty( $_view ) || ( defined( 'PODS_REMOTE_VIEWS' ) && PODS_REMOTE_VIEWS ) )
540 return '';
541
542 $response = wp_remote_get( $_view );
543
544 return wp_remote_retrieve_body( $response );
545 }
546 */
547
548 $_view = self::locate_template( $_view, $limited );
549
550 if ( empty( $_view ) ) {
551 return $_view;
552 }
553
554 if ( ! empty( $_data ) && is_array( $_data ) ) {
555 extract( $_data, EXTR_SKIP );
556 }
557
558 ob_start();
559 require $_view;
560 $output = ob_get_clean();
561
562 return $output;
563 }
564
565 /**
566 * @static
567 *
568 * @param array|string $_view
569 * @param bool $limited (optional) Whether to limit the view to only the theme directory, defaults to false
570 *
571 * @return bool|mixed|string|void
572 */
573 private static function locate_template( $_view, $limited = false ) {
574 if ( is_array( $_view ) ) {
575 $_views = array();
576
577 if ( isset( $_view[0] ) && false === strpos( $_view[0], '.php' ) ) {
578 $_view_count = count( $_view );
579
580 for ( $_view_x = $_view_count; 0 < $_view_x; $_view_x -- ) {
581 $_view_v = array_slice( $_view, 0, $_view_x );
582
583 $_views[] = implode( '-', $_view_v ) . '.php';
584 }
585 } else {
586 $_views = $_view;
587 }
588
589 $_view = false;
590
591 foreach ( $_views as $_view_check ) {
592 $_view = self::locate_template( $_view_check );
593
594 if ( ! empty( $_view ) ) {
595 break;
596 }
597 }
598
599 return $_view;
600 }//end if
601
602 // Keep it safe
603 $_view = trim( str_replace( array( '../', '\\' ), array( '', '/' ), (string) $_view ) );
604
605 if ( empty( $_view ) ) {
606 return false;
607 }
608
609 $_real_view = realpath( $_view );
610
611 if ( empty( $_real_view ) ) {
612 $_real_view = $_view;
613 }
614
615 $located = false;
616
617 // Is the view's file somewhere within the plugin directory tree?
618 // Note: we explicitly whitelist PODS_DIR for the case of symlinks (see issue #2945)
619 if (
620 ! $limited
621 && (
622 false !== strpos( $_real_view, realpath( WP_PLUGIN_DIR ) )
623 || false !== strpos( $_real_view, realpath( WPMU_PLUGIN_DIR ) )
624 || false !== strpos( $_real_view, PODS_DIR )
625 )
626 ) {
627 if ( file_exists( $_view ) ) {
628 $located = $_view;
629 } else {
630 $located = apply_filters( 'pods_view_locate_template', $located, $_view );
631 }
632 } else {
633 // The view's file is outside the plugin directory
634 $_real_view = trim( $_real_view, '/' );
635
636 if ( empty( $_real_view ) ) {
637 return false;
638 }
639
640 // Allow views in the theme or child theme
641 if ( file_exists( realpath( get_stylesheet_directory() . '/' . $_real_view ) ) ) {
642 $located = realpath( get_stylesheet_directory() . '/' . $_real_view );
643 } elseif ( file_exists( realpath( get_template_directory() . '/' . $_real_view ) ) ) {
644 $located = realpath( get_template_directory() . '/' . $_real_view );
645 }
646 }//end if
647
648 return $located;
649
650 }
651
652 /**
653 * Advanced $expires handling
654 *
655 * @param array|bool|int $expires
656 * @param string $cache_mode
657 *
658 * @return bool|int
659 *
660 * @since 2.7.0
661 * @static
662 */
663 public static function expires( $expires, $cache_mode = 'cache' ) {
664
665 // Different $expires if user is anonymous or logged in or specific capability
666 if ( is_array( $expires ) ) {
667 if ( ( isset( $expires['anonymous'] ) || isset( $expires['user_with_access'] ) ) && isset( $expires['user'] ) ) {
668 if ( isset( $expires['user_with_access'] ) ) {
669 $expires = array(
670 pods_var_raw( 'anonymous', $expires, false ),
671 pods_var_raw( 'user', $expires, false ),
672 pods_var_raw( 'user_with_access', $expires, false ),
673 pods_var_raw( 'capability', $expires, null, null, true ),
674 );
675 } elseif ( isset( $expires['anonymous'] ) ) {
676 $expires = array(
677 pods_var_raw( 'anonymous', $expires, false ),
678 pods_var_raw( 'user', $expires, false ),
679 pods_var_raw( 'capability', $expires, null, null, true ),
680 );
681 }
682 } else {
683 $expires = array_values( $expires );
684 }
685
686 if ( 4 == count( $expires ) ) {
687 if ( ! is_user_logged_in() ) {
688 $expires = pods_var_raw( 0, $expires, false );
689 } else {
690 $user_no_access = pods_var_raw( 1, $expires, false );
691 $user_with_access = pods_var_raw( 2, $expires, false );
692 $capability = pods_var_raw( 3, $expires, null, null, true );
693
694 $expires = pods_var_user( $user_no_access, $user_with_access, $capability );
695 }
696 } else {
697 $anon = pods_var_raw( 0, $expires, false );
698 $user = pods_var_raw( 1, $expires, false );
699 $capability = pods_var_raw( 2, $expires, null, null, true );
700
701 $expires = pods_var_user( $anon, $user, $capability );
702 }
703 }//end if
704
705 if ( 'none' === $cache_mode ) {
706 $expires = false;
707 } elseif ( false !== $expires ) {
708 $expires = (int) $expires;
709
710 if ( $expires < 1 ) {
711 $expires = 0;
712 }
713 }
714
715 return $expires;
716
717 }
718
719 }
720