PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 2.8.23.4
Pods – Custom Content Types and Fields v2.8.23.4
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 / includes / data.php
pods / includes Last commit date
compatibility 2 weeks ago access.php 2 weeks ago classes.php 2 weeks ago data.php 2 weeks ago forms.php 2 weeks ago general.php 2 weeks ago media.php 2 weeks ago
data.php
2685 lines
1 <?php
2 /**
3 * @package Pods\Global\Functions\Data
4 */
5 /**
6 * Filter input and return sanitized output
7 *
8 * @param mixed $input The string, array, or object to sanitize
9 * @param array $params Additional options
10 *
11 * @return array|mixed|object|string|void
12 *
13 * @since 1.2.0
14 *
15 * @see wp_slash
16 */
17 function pods_sanitize( $input, $params = array() ) {
18 if ( '' === $input || is_int( $input ) || is_float( $input ) || empty( $input ) ) {
19 return $input;
20 }
21
22 $output = array();
23
24 $defaults = array(
25 'nested' => false,
26 'type' => null,
27 // %s %d %f etc
28 );
29
30 if ( ! is_array( $params ) ) {
31 $defaults['type'] = $params;
32
33 $params = $defaults;
34 } else {
35 $params = array_merge( $defaults, (array) $params );
36 }
37
38 if ( is_object( $input ) ) {
39 $input = get_object_vars( $input );
40
41 $n_params = $params;
42 $n_params['nested'] = true;
43
44 foreach ( $input as $key => $val ) {
45 $output[ pods_sanitize( $key ) ] = pods_sanitize( $val, $n_params );
46 }
47
48 $output = (object) $output;
49 } elseif ( is_array( $input ) ) {
50 $n_params = $params;
51 $n_params['nested'] = true;
52
53 foreach ( $input as $key => $val ) {
54 $output[ pods_sanitize( $key ) ] = pods_sanitize( $val, $n_params );
55 }
56 } elseif ( ! empty( $params['type'] ) && false !== strpos( $params['type'], '%' ) ) {
57 /**
58 * @var $wpdb wpdb
59 */
60 global $wpdb;
61
62 $output = $wpdb->prepare( $params['type'], $output );
63 } elseif ( function_exists( 'wp_slash' ) ) {
64 // @todo Switch this full over to esc_sql once we get sanitization sane again in PodsAPI so we *don't* have to unsanitize in various places
65 $output = wp_slash( $input );
66 } else {
67 $output = esc_sql( $input );
68 }//end if
69
70 return $output;
71 }
72
73 /**
74 * Filter input and return sanitized SQL LIKE output
75 *
76 * @param mixed $input The string, array, or object to sanitize
77 *
78 * @return array|mixed|object|string|void
79 *
80 * @since 2.3.9
81 *
82 * @see like_escape
83 */
84 function pods_sanitize_like( $input ) {
85 if ( '' === $input || is_int( $input ) || is_float( $input ) || empty( $input ) ) {
86 return $input;
87 }
88
89 $output = array();
90
91 if ( is_object( $input ) ) {
92 $input = get_object_vars( $input );
93
94 foreach ( $input as $key => $val ) {
95 $output[ $key ] = pods_sanitize_like( $val );
96 }
97
98 $output = (object) $output;
99 } elseif ( is_array( $input ) ) {
100 foreach ( $input as $key => $val ) {
101 $output[ $key ] = pods_sanitize_like( $val );
102 }
103 } else {
104 global $wpdb;
105 $input = pods_unslash( $input );
106
107 $output = pods_sanitize( $wpdb->esc_like( $input ) );
108 }
109
110 return $output;
111 }
112
113 /**
114 * Filter input and return slashed output
115 *
116 * @param mixed $input The string, array, or object to sanitize
117 * @param array $params Additional options
118 *
119 * @return array|mixed|object|string|void
120 *
121 * @since 2.3.9
122 *
123 * @see wp_slash
124 */
125 function pods_slash( $input, $params = array() ) {
126 if ( '' === $input || is_int( $input ) || is_float( $input ) || is_bool( $input ) || empty( $input ) ) {
127 return $input;
128 }
129
130 $output = array();
131
132 $defaults = array(
133 'type' => null,
134 // %s %d %f etc
135 );
136
137 if ( ! is_array( $params ) ) {
138 $defaults['type'] = $params;
139
140 $params = $defaults;
141 } else {
142 $params = array_merge( $defaults, (array) $params );
143 }
144
145 if ( empty( $input ) ) {
146 $output = $input;
147 } elseif ( is_object( $input ) ) {
148 $input = get_object_vars( $input );
149
150 foreach ( $input as $key => $val ) {
151 $output[ $key ] = pods_slash( $val, $params );
152 }
153
154 $output = (object) $output;
155 } elseif ( is_array( $input ) ) {
156 foreach ( $input as $key => $val ) {
157 $output[ $key ] = pods_slash( $val, $params );
158 }
159 } elseif ( ! empty( $params['type'] ) && false !== strpos( $params['type'], '%' ) ) {
160 /**
161 * @var $wpdb wpdb
162 */
163 global $wpdb;
164
165 $output = $wpdb->prepare( $params['type'], $output );
166 } elseif ( function_exists( 'wp_slash' ) ) {
167 $output = wp_slash( $input );
168 } else {
169 $output = addslashes( $input );
170 }//end if
171
172 return $output;
173 }
174
175 /**
176 * Filter input and return unsanitized output
177 *
178 * @param mixed $input The string, array, or object to unsanitize
179 * @param array $params Additional options
180 *
181 * @return array|mixed|object|string|void
182 *
183 * @since 1.2.0
184 */
185 function pods_unsanitize( $input, $params = array() ) {
186 if ( '' === $input || is_int( $input ) || is_float( $input ) || empty( $input ) ) {
187 return $input;
188 }
189
190 $output = array();
191
192 if ( empty( $input ) ) {
193 $output = $input;
194 } elseif ( is_object( $input ) ) {
195 $input = get_object_vars( $input );
196
197 $n_params = (array) $params;
198 $n_params['nested'] = true;
199
200 foreach ( $input as $key => $val ) {
201 $output[ pods_unsanitize( $key ) ] = pods_unsanitize( $val, $n_params );
202 }
203
204 $output = (object) $output;
205 } elseif ( is_array( $input ) ) {
206 $n_params = (array) $params;
207 $n_params['nested'] = true;
208
209 foreach ( $input as $key => $val ) {
210 $output[ pods_unsanitize( $key ) ] = pods_unsanitize( $val, $n_params );
211 }
212 } else {
213 $output = wp_unslash( $input );
214 }//end if
215
216 return $output;
217 }
218
219 /**
220 * Filter input and return unslashed output
221 *
222 * @param mixed $input The string, array, or object to unsanitize
223 *
224 * @return array|mixed|object|string|void
225 *
226 * @since 2.3.9
227 *
228 * @see wp_unslash
229 */
230 function pods_unslash( $input ) {
231 if ( '' === $input || is_int( $input ) || is_float( $input ) || empty( $input ) ) {
232 return $input;
233 }
234
235 $output = array();
236
237 if ( empty( $input ) ) {
238 $output = $input;
239 } elseif ( is_object( $input ) ) {
240 $input = get_object_vars( $input );
241
242 foreach ( $input as $key => $val ) {
243 $output[ $key ] = pods_unslash( $val );
244 }
245
246 $output = (object) $output;
247 } elseif ( is_array( $input ) ) {
248 foreach ( $input as $key => $val ) {
249 $output[ $key ] = pods_unslash( $val );
250 }
251 } else {
252 $output = wp_unslash( $input );
253 }
254
255 return $output;
256 }
257
258 /**
259 * Filter input and return sanitized output
260 *
261 * @param mixed $input The string, array, or object to sanitize
262 * @param string $charlist (optional) List of characters to be stripped from the input.
263 * @param string $lr Direction of the trim, can either be 'l' or 'r'.
264 *
265 * @return array|object|string
266 * @since 1.2.0
267 */
268 function pods_trim( $input, $charlist = " \t\n\r\0\x0B", $lr = null ) {
269 $output = array();
270
271 if ( is_object( $input ) ) {
272 $input = get_object_vars( $input );
273
274 foreach ( $input as $key => $val ) {
275 $output[ pods_sanitize( $key ) ] = pods_trim( $val, $charlist, $lr );
276 }
277
278 $output = (object) $output;
279 } elseif ( is_array( $input ) ) {
280 foreach ( $input as $key => $val ) {
281 $output[ pods_sanitize( $key ) ] = pods_trim( $val, $charlist, $lr );
282 }
283 } else {
284 $args = array( $input );
285 if ( null !== $charlist ) {
286 $args[] = $charlist;
287 }
288 if ( 'l' === $lr ) {
289 $function = 'ltrim';
290 } elseif ( 'r' === $lr ) {
291 $function = 'rtrim';
292 } else {
293 $function = 'trim';
294 }
295 $output = call_user_func_array( $function, $args );
296 }//end if
297
298 return $output;
299 }
300
301 /**
302 * Traverse an array or object by array values order or a string (name.name.name).
303 *
304 * @since 2.7.18
305 *
306 * @param array|string|int $traverse The traversal names/keys.
307 * @param array|object $value The value to traverse into.
308 *
309 * @return mixed
310 */
311 function pods_traverse( $traverse, $value ) {
312 if ( ! $traverse && ! is_numeric( $traverse ) ) {
313 return $value;
314 }
315
316 if ( is_scalar( $value ) ) {
317 return null;
318 }
319
320 if ( is_object( $value ) ) {
321 $value = (array) $value;
322 }
323
324 if ( ! is_array( $traverse ) ) {
325 $traverse = explode( '.', $traverse );
326 }
327
328 $key = array_shift( $traverse );
329
330 if ( ! isset( $value[ $key ] ) ) {
331 return null;
332 }
333
334 $value = $value[ $key ];
335
336 if ( $traverse ) {
337 $value = pods_traverse( $traverse, $value );
338 }
339
340 return $value;
341 }
342
343 /**
344 * Return a variable (if exists)
345 *
346 * @param mixed $var The variable name, can also be a modifier for specific types
347 * @param string|array|object $type (optional) Super globals, url/url-relative, constants, globals, options,
348 * transients, cache, user data, Pod field values, dates
349 * @param mixed $default (optional) The default value to set if variable doesn't exist
350 * @param bool $strict (optional) Only allow values (must not be empty)
351 * @param array $params (optional) Set 'casting'=>true to cast value from $default, 'allowed'=>$allowed
352 * to restrict a value to what's allowed
353 *
354 * @return mixed The variable (if exists), or default value
355 * @since 2.3.10
356 */
357 function pods_v( $var = null, $type = 'get', $default = null, $strict = false, $params = array() ) {
358 $defaults = array(
359 'casting' => false,
360 'allowed' => null,
361 'source' => null,
362 );
363
364 $params = (object) array_merge( $defaults, (array) $params );
365
366 $output = null;
367
368 if ( null === $type || '' === $type ) {
369 // Invalid $type
370 } elseif ( is_array( $type ) ) {
371 if ( isset( $type[ $var ] ) ) {
372 $output = $type[ $var ];
373 }
374 } elseif ( is_object( $type ) ) {
375 if ( isset( $type->{$var} ) ) {
376 $output = $type->{$var};
377 }
378 } else {
379 $type = strtolower( (string) $type );
380
381 if ( $params->source ) {
382 // Using keys for faster isset() checks instead of in_array().
383 $disallowed_types = [];
384
385 if ( 'magic-tag' === $params->source ) {
386 $disallowed_types = [
387 'server' => false,
388 'session' => false,
389 'global' => false,
390 'globals' => false,
391 'cookie' => false,
392 'constant' => false,
393 'option' => false,
394 'site-option' => false,
395 'transient' => false,
396 'site-transient' => false,
397 'cache' => false,
398 'pods-transient' => false,
399 'pods-site-transient' => false,
400 'pods-cache' => false,
401 'pods-option-cache' => false,
402 ];
403 }
404
405 /**
406 * Allow filtering the list of disallowed variable types for the source.
407 *
408 * @since 2.9.4
409 *
410 * @param array $disallowed_types The list of disallowed variable types for the source.
411 * @param string $source The source calling pods_v().
412 */
413 $disallowed_types = apply_filters( "pods_v_disallowed_types_for_source_{$params->source}", $disallowed_types, $params->source );
414
415 if ( isset( $disallowed_types[ $type ] ) ) {
416 return $default;
417 }
418 }
419
420 switch ( $type ) {
421 case 'get':
422 if ( isset( $_GET[ $var ] ) ) {
423 $output = pods_unslash( $_GET[ $var ] );
424 }
425 break;
426 case 'post':
427 if ( isset( $_POST[ $var ] ) ) {
428 $output = pods_unslash( $_POST[ $var ] );
429 }
430 break;
431 case 'request':
432 if ( isset( $_REQUEST[ $var ] ) ) {
433 $output = pods_unslash( $_REQUEST[ $var ] );
434 }
435 break;
436 case 'query':
437 $output = get_query_var( $var, $default );
438 break;
439 case 'url':
440 case 'uri':
441 $url = parse_url( pods_current_url() );
442 $uri = trim( $url['path'], '/' );
443 $uri = array_filter( explode( '/', $uri ) );
444
445 if ( 'first' === $var ) {
446 $var = 0;
447 } elseif ( 'last' === $var ) {
448 $var = -1;
449 }
450
451 if ( is_numeric( $var ) ) {
452 $output = ( $var < 0 ) ? pods_v( count( $uri ) + $var, $uri ) : pods_v( $var, $uri );
453 }
454 break;
455 case 'url-relative':
456 $url_raw = pods_current_url();
457 $prefix = get_site_url();
458
459 if ( substr( $url_raw, 0, strlen( $prefix ) ) == $prefix ) {
460 $url_raw = substr( $url_raw, strlen( $prefix ) + 1, strlen( $url_raw ) );
461 }
462
463 $url = parse_url( $url_raw );
464 $uri = trim( $url['path'], '/' );
465 $uri = array_filter( explode( '/', $uri ) );
466
467 if ( 'first' === $var ) {
468 $var = 0;
469 } elseif ( 'last' === $var ) {
470 $var = -1;
471 }
472
473 if ( is_numeric( $var ) ) {
474 $output = ( $var < 0 ) ? pods_v( count( $uri ) + $var, $uri ) : pods_v( $var, $uri );
475 }
476 break;
477 case 'template-url':
478 $output = get_template_directory_uri();
479 break;
480 case 'stylesheet-url':
481 $output = get_stylesheet_directory_uri();
482 break;
483 case 'site-url':
484 $blog_id = null;
485 $scheme = null;
486 $path = '';
487
488 if ( is_array( $var ) ) {
489 if ( isset( $var[0] ) ) {
490 $blog_id = $var[0];
491 }
492 if ( isset( $var[1] ) ) {
493 $path = $var[1];
494 }
495 if ( isset( $var[2] ) ) {
496 $scheme = $var[2];
497 }
498 } else {
499 $blog_id = $var;
500 }
501
502 $output = get_site_url( $blog_id, $path, $scheme );
503 break;
504 case 'home-url':
505 $blog_id = null;
506 $scheme = null;
507 $path = '';
508
509 if ( is_array( $var ) ) {
510 if ( isset( $var[0] ) ) {
511 $blog_id = $var[0];
512 }
513 if ( isset( $var[1] ) ) {
514 $path = $var[1];
515 }
516 if ( isset( $var[2] ) ) {
517 $scheme = $var[2];
518 }
519 } else {
520 $blog_id = $var;
521 }
522
523 $output = get_home_url( $blog_id, $path, $scheme );
524 break;
525 case 'admin-url':
526 $blog_id = null;
527 $scheme = null;
528 $path = '';
529
530 if ( is_array( $var ) ) {
531 if ( isset( $var[0] ) ) {
532 $blog_id = $var[0];
533 }
534 if ( isset( $var[1] ) ) {
535 $path = $var[1];
536 }
537 if ( isset( $var[2] ) ) {
538 $scheme = $var[2];
539 }
540 } else {
541 $blog_id = $var;
542 }
543
544 $output = get_admin_url( $blog_id, $path, $scheme );
545 break;
546 case 'includes-url':
547 $output = includes_url( $var );
548 break;
549 case 'content-url':
550 $output = content_url( $var );
551 break;
552 case 'plugins-url':
553 $path = '';
554 $plugin = '';
555
556 if ( is_array( $var ) ) {
557 if ( isset( $var[0] ) ) {
558 $path = $var[0];
559 }
560 if ( isset( $var[1] ) ) {
561 $plugin = $var[1];
562 }
563 } else {
564 $path = $var;
565 }
566
567 $output = plugins_url( $path, $plugin );
568 break;
569 case 'network-site-url':
570 $path = '';
571 $scheme = null;
572
573 if ( is_array( $var ) ) {
574 if ( isset( $var[0] ) ) {
575 $path = $var[0];
576 }
577 if ( isset( $var[1] ) ) {
578 $scheme = $var[1];
579 }
580 } else {
581 $path = $var;
582 }
583
584 $output = network_site_url( $path, $scheme );
585 break;
586 case 'network-home-url':
587 $path = '';
588 $scheme = null;
589
590 if ( is_array( $var ) ) {
591 if ( isset( $var[0] ) ) {
592 $path = $var[0];
593 }
594 if ( isset( $var[1] ) ) {
595 $scheme = $var[1];
596 }
597 } else {
598 $path = $var;
599 }
600
601 $output = network_home_url( $path, $scheme );
602 break;
603 case 'network-admin-url':
604 $path = '';
605 $scheme = null;
606
607 if ( is_array( $var ) ) {
608 if ( isset( $var[0] ) ) {
609 $path = $var[0];
610 }
611 if ( isset( $var[1] ) ) {
612 $scheme = $var[1];
613 }
614 } else {
615 $path = $var;
616 }
617
618 $output = network_admin_url( $path, $scheme );
619 break;
620 case 'user-admin-url':
621 $path = '';
622 $scheme = null;
623
624 if ( is_array( $var ) ) {
625 if ( isset( $var[0] ) ) {
626 $path = $var[0];
627 }
628 if ( isset( $var[1] ) ) {
629 $scheme = $var[1];
630 }
631 } else {
632 $path = $var;
633 }
634
635 $output = user_admin_url( $path, $scheme );
636 break;
637 case 'prefix':
638 global $wpdb;
639
640 $output = $wpdb->prefix;
641 break;
642 case 'server':
643 if ( ! pods_strict( false ) ) {
644 if ( isset( $_SERVER[ $var ] ) ) {
645 $output = pods_unslash( $_SERVER[ $var ] );
646 } elseif ( isset( $_SERVER[ strtoupper( $var ) ] ) ) {
647 $output = pods_unslash( $_SERVER[ strtoupper( $var ) ] );
648 }
649 }
650 break;
651 case 'session':
652 if ( isset( $_SESSION[ $var ] ) ) {
653 $output = $_SESSION[ $var ];
654 }
655 break;
656 case 'global':
657 case 'globals':
658 if ( isset( $GLOBALS[ $var ] ) ) {
659 $output = $GLOBALS[ $var ];
660
661 $output = pods_access_bleep_data( $output );
662 }
663 break;
664 case 'cookie':
665 if ( isset( $_COOKIE[ $var ] ) ) {
666 $output = pods_unslash( $_COOKIE[ $var ] );
667 }
668 break;
669 case 'constant':
670 if ( defined( $var ) ) {
671 $output = constant( $var );
672 }
673 break;
674 case 'user':
675 // Prevent deprecation notice from WP.
676 if ( 'id' === $var ) {
677 $var = 'ID';
678 }
679
680 if ( is_user_logged_in() ) {
681 $user = get_userdata( get_current_user_id() );
682
683 $user = pods_access_bleep_data( $user );
684
685 if ( isset( $user->{$var} ) ) {
686 $value = $user->{$var};
687 } elseif ( 'role' === $var ) {
688 $value = '';
689
690 if ( ! empty( $user->roles ) ) {
691 $value = array_shift( $user->roles );
692 }
693 } else {
694 $value = get_user_meta( $user->ID, $var );
695 }
696
697 if ( is_array( $value ) && ! empty( $value ) ) {
698 $output = $value;
699 } elseif ( ! is_array( $value ) && 0 < strlen( $value ) ) {
700 $output = $value;
701 }
702 } elseif ( 'ID' === $var ) {
703 // Return 0 when logged out and calling the ID.
704 $output = 0;
705 }
706 break;
707 case 'option':
708 $output = get_option( $var, $default );
709 break;
710 case 'site-option':
711 $output = get_site_option( $var, $default );
712 break;
713 case 'transient':
714 $output = get_transient( $var );
715 break;
716 case 'site-transient':
717 $output = get_site_transient( $var );
718 break;
719 case 'cache':
720 if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
721 $group = 'default';
722 $force = false;
723
724 if ( ! is_array( $var ) ) {
725 $var = explode( '|', $var );
726 }
727
728 if ( isset( $var[0] ) ) {
729 if ( isset( $var[1] ) ) {
730 $group = $var[1];
731 }
732
733 if ( isset( $var[2] ) ) {
734 $force = $var[2];
735 }
736
737 $var = $var[0];
738
739 $output = wp_cache_get( $var, $group, $force );
740 }
741 }//end if
742 break;
743 case 'pods-transient':
744 $callback = null;
745
746 if ( ! is_array( $var ) ) {
747 $var = explode( '|', $var );
748 }
749
750 if ( isset( $var[0] ) ) {
751 if ( isset( $var[1] ) ) {
752 $callback = $var[1];
753 }
754
755 $var = $var[0];
756
757 $output = pods_transient_get( $var, $callback );
758 }
759 break;
760 case 'pods-site-transient':
761 $callback = null;
762
763 if ( ! is_array( $var ) ) {
764 $var = explode( '|', $var );
765 }
766
767 if ( isset( $var[0] ) ) {
768 if ( isset( $var[1] ) ) {
769 $callback = $var[1];
770 }
771
772 $var = $var[0];
773
774 $output = pods_site_transient_get( $var, $callback );
775 }
776 break;
777 case 'pods-cache':
778 if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
779 $group = 'default';
780 $callback = null;
781
782 if ( ! is_array( $var ) ) {
783 $var = explode( '|', $var );
784 }
785
786 if ( isset( $var[0] ) ) {
787 if ( isset( $var[1] ) ) {
788 $group = $var[1];
789 }
790
791 if ( isset( $var[2] ) ) {
792 $callback = $var[2];
793 }
794
795 $var = $var[0];
796
797 $output = pods_cache_get( $var, $group, $callback );
798 }
799 }//end if
800 break;
801 case 'pods-option-cache':
802 $group = 'default';
803 $callback = null;
804
805 if ( ! is_array( $var ) ) {
806 $var = explode( '|', $var );
807 }
808
809 if ( isset( $var[0] ) ) {
810 if ( isset( $var[1] ) ) {
811 $group = $var[1];
812 }
813
814 if ( isset( $var[2] ) ) {
815 $callback = $var[2];
816 }
817
818 $var = $var[0];
819
820 $output = pods_option_cache_get( $var, $group, $callback );
821 }
822 break;
823 case 'date':
824 $var = explode( '|', $var );
825
826 if ( ! empty( $var ) ) {
827 $output = date_i18n( $var[0], ( isset( $var[1] ) ? strtotime( $var[1] ) : false ) );
828 }
829 break;
830 case 'pods':
831 case 'pods_display':
832 /**
833 * @var $pods Pods
834 */
835 global $pods;
836
837 if ( is_object( $pods ) && 'Pods' == get_class( $pods ) ) {
838 if ( 'pods' === $type ) {
839 $output = $pods->field( $var );
840
841 if ( is_array( $output ) ) {
842 $options = array(
843 'field' => $var,
844 'fields' => $pods->fields,
845 );
846
847 $output = pods_serial_comma( $output, $options );
848 }
849 } elseif ( 'pods_display' === $type ) {
850 $output = $pods->display( $var );
851 }
852 }
853 break;
854 case 'post_id':
855 if ( empty( $var ) ) {
856 if ( ! empty( $default ) ) {
857 $post_id = $default;
858 } else {
859 // If no $var and no $default then use current post ID
860 $post_id = get_the_ID();
861 }
862 } else {
863 $post_id = $var;
864 }
865
866 // Add other translation plugin specific code here
867 /**
868 * Filter to override post_id
869 *
870 * Generally used with language translation plugins in order to return the post id of a
871 * translated post
872 *
873 * @param int $post_id The post ID of current post
874 * @param mixed $default The default value to set if variable doesn't exist
875 * @param mixed $var The variable name, can also be a modifier for specific types
876 * @param bool $strict Only allow values (must not be empty)
877 * @param array $params Set 'casting'=>true to cast value from $default, 'allowed'=>$allowed to restrict a value to what's allowed
878 *
879 * @since 2.6.6
880 */
881 $output = apply_filters( 'pods_var_post_id', $post_id, $default, $var, $strict, $params );
882 break;
883 default:
884 $output = apply_filters( "pods_var_{$type}", $default, $var, $strict, $params );
885 }//end switch
886 }//end if
887
888 if ( null !== $default ) {
889 // Set default
890 if ( null === $output ) {
891 $output = $default;
892 }
893
894 // Casting
895 if ( true === $params->casting ) {
896 $output = pods_cast( $output, $default );
897 }
898 }
899
900 // Strict defaults for empty values
901 if ( true === $strict ) {
902 if ( empty( $output ) ) {
903 $output = $default;
904 }
905 }
906
907 // Allowed values
908 if ( null !== $params->allowed ) {
909 if ( is_array( $params->allowed ) ) {
910 // Not in array and is not the same array
911 if ( ! in_array( $output, $params->allowed, true ) && ( ! is_array( $output ) || $output !== $params->allowed ) ) {
912 $output = $default;
913 }
914 } elseif ( $output !== $params->allowed ) {
915 // Value doesn't match
916 $output = $default;
917 }
918 }
919
920 return $output;
921 }
922
923 /**
924 * Return a sanitized variable (if exists)
925 *
926 * @param mixed $var The variable name, can also be a modifier for specific types
927 * @param string|array|object $type (optional) Super globals, url/url-relative, constants, globals, options,
928 * transients, cache, user data, Pod field values, dates
929 * @param mixed $default (optional) The default value to set if variable doesn't exist
930 * @param bool $strict (optional) Only allow values (must not be empty)
931 * @param array $params (optional) Set 'casting'=>true to cast value from $default, 'allowed'=>$allowed
932 * to restrict a value to what's allowed
933 *
934 * @return mixed The variable (if exists), or default value
935 * @since 2.3.10
936 *
937 * @see pods_v
938 */
939 function pods_v_sanitized( $var = null, $type = 'get', $default = null, $strict = false, $params = array() ) {
940 $output = pods_v( $var, $type, $default, $strict, $params );
941
942 $output = pods_sanitize( $output, $params );
943
944 return $output;
945 }
946
947 /**
948 * Set a variable
949 *
950 * @param mixed $value The value to be set
951 * @param mixed $var The variable name, or URI segment position / query var name (if $type is 'url')
952 * @param string|array|object $type (optional) Super globals, url/url-relative, constants, globals, user data, Pod
953 * field values
954 *
955 * @return mixed Updated URL (if $type is 'url'), $value (if $type is 'constant'), Item ID (if $type is 'pods'), $type,
956 * or false if not set
957 * @since 2.3.10
958 */
959 function pods_v_set( $value, $var, $type = 'get' ) {
960 $ret = false;
961
962 if ( null === $var || '' === $var ) {
963 // Invalid $var
964 } elseif ( null === $type || '' === $type ) {
965 // Invalid $type
966 } elseif ( is_array( $type ) ) {
967 $type[ $var ] = $value;
968
969 $ret = $type;
970 } elseif ( is_object( $type ) ) {
971 $type->{$var} = $value;
972
973 $ret = $type;
974 } else {
975 $type = strtolower( $type );
976
977 if ( 'get' === $type ) {
978 $_GET[ $var ] = $value;
979
980 $ret = $_GET;
981 } elseif ( 'post' === $type ) {
982 $_POST[ $var ] = $value;
983
984 $ret = $_POST;
985 } elseif ( 'request' === $type ) {
986 $_REQUEST[ $var ] = $value;
987
988 $ret = $_REQUEST;
989 } elseif ( 'url' === $type ) {
990 if ( is_numeric( $var ) && function_exists( 'http_build_url' ) ) {
991 $url = parse_url( pods_current_url() );
992 $uri = trim( $url['path'], '/' );
993 $uri = array_filter( explode( '/', $uri ) );
994
995 if ( 'first' === $var ) {
996 $var = 0;
997 } elseif ( 'last' === $var ) {
998 $var = - 1;
999 }
1000
1001 if ( $var < 0 ) {
1002 $uri[ count( $uri ) + $var ] = $value;
1003 } else {
1004 $uri[ $var ] = $value;
1005 }
1006
1007 $url['path'] = '/' . implode( '/', $uri ) . '/';
1008 $url['path'] = trim( $url['path'], '/' );
1009
1010 $ret = http_build_url( $url );
1011 } else {
1012 $ret = add_query_arg( array( $var => $value ) );
1013 }//end if
1014 } elseif ( 'server' === $type ) {
1015 $_SERVER[ $var ] = $value;
1016
1017 $ret = $_SERVER;
1018 } elseif ( in_array( $type, array( 'global', 'globals' ), true ) ) {
1019 $GLOBALS[ $var ] = $value;
1020
1021 $ret = $GLOBALS;
1022 } elseif ( 'session' === $type ) {
1023 // Session start
1024 pods_session_start();
1025
1026 $_SESSION[ $var ] = $value;
1027
1028 $ret = $_SESSION;
1029 } elseif ( 'cookie' === $type && ! headers_sent() ) {
1030 setcookie( $var, $value, time() + 10 * DAY_IN_SECONDS, COOKIEPATH );
1031
1032 $ret = $_COOKIE;
1033 } elseif ( 'constant' === $type && ! defined( $var ) && ( is_scalar( $value ) || null === $value ) ) {
1034 define( $var, $value );
1035
1036 $ret = constant( $var );
1037 } elseif ( 'user' === $type && is_user_logged_in() ) {
1038 $user = get_userdata( get_current_user_id() );
1039
1040 $user_data = $user->to_array();
1041
1042 if ( 'role' === $var ) {
1043 // Role
1044 $user->set_role( $value );
1045 } elseif ( isset( $user_data[ $var ] ) ) {
1046 // Core field
1047 wp_update_user( array(
1048 'ID' => $user->ID,
1049 $var => $value,
1050 ) );
1051 } else {
1052 // Meta field
1053 update_user_meta( $user->ID, $var, $value );
1054 }
1055
1056 $ret = get_userdata( $user->ID );
1057 } elseif ( 'pods' === $type ) {
1058 /**
1059 * @var $pods Pods
1060 */
1061 global $pods;
1062
1063 if ( is_object( $pods ) && 'Pods' == get_class( $pods ) && $pods->exists() ) {
1064 $ret = $pods->save( $var, $value );
1065 }
1066 } else {
1067 $ret = apply_filters( "pods_var_set_{$type}", $value, $var );
1068 }//end if
1069 }//end if
1070
1071 return $ret;
1072 }
1073
1074 /**
1075 * Return a variable (if exists)
1076 *
1077 * @param mixed $var The variable name or URI segment position
1078 * @param string $type (optional) Super globals, url/url-relative, constants, globals, options, transients, cache,
1079 * user data, Pod field values, dates
1080 * @param mixed $default (optional) The default value to set if variable doesn't exist
1081 * @param mixed $allowed (optional) The value(s) allowed
1082 * @param bool $strict (optional) Only allow values (must not be empty)
1083 * @param bool $casting (optional) Whether to cast the value returned like provided in $default
1084 * @param string $context (optional) All returned values are sanitized unless this is set to 'raw'
1085 *
1086 * @return mixed The variable (if exists), or default value
1087 * @since 1.10.6
1088 *
1089 * @deprecated 2.4.0 Use pods_v() or pods_v_sanitized() instead.
1090 * @see pods_v_sanitized
1091 */
1092 function pods_var( $var = 'last', $type = 'get', $default = null, $allowed = null, $strict = false, $casting = false, $context = 'display' ) {
1093 if ( 'raw' === $context ) {
1094 $output = pods_v( $var, $type, $default, $strict, array(
1095 'allowed' => $allowed,
1096 'casting' => $casting,
1097 ) );
1098 } else {
1099 $output = pods_v_sanitized( $var, $type, $default, $strict, array(
1100 'allowed' => $allowed,
1101 'casting' => $casting,
1102 ) );
1103 }
1104
1105 return $output;
1106 }
1107
1108 /**
1109 * Return a variable's raw value (if exists)
1110 *
1111 * @param mixed $var The variable name or URI segment position
1112 * @param string $type (optional) Super globals, url/url-relative, constants, globals, options, transients, cache,
1113 * user data, Pod field values, dates
1114 * @param mixed $default (optional) The default value to set if variable doesn't exist
1115 * @param mixed $allowed (optional) The value(s) allowed
1116 * @param bool $strict (optional) Only allow values (must not be empty)
1117 * @param bool $casting (optional) Whether to cast the value returned like provided in $default
1118 *
1119 * @return mixed The variable (if exists), or default value
1120 * @since 2.0.0
1121 *
1122 * @deprecated 2.4.0 Use pods_v() instead.
1123 * @see pods_v
1124 */
1125 function pods_var_raw( $var = 'last', $type = 'get', $default = null, $allowed = null, $strict = false, $casting = false ) {
1126 return pods_v( $var, $type, $default, $strict, array(
1127 'allowed' => $allowed,
1128 'casting' => $casting,
1129 ) );
1130 }
1131
1132 /**
1133 * Set a variable
1134 *
1135 * @param mixed $value The value to be set
1136 * @param mixed $var The variable name or URI segment position
1137 * @param string $type (optional) "url", "get", "post", "request", "server", "session", "cookie", "constant", or "user"
1138 *
1139 * @return mixed $value (if set), $type (if $type is array or object), or $url (if $type is 'url')
1140 * @since 1.10.6
1141 *
1142 * @deprecated 2.4.0 Use pods_v_set() instead.
1143 * @see pods_v_set
1144 */
1145 function pods_var_set( $value, $var = 'last', $type = 'url' ) {
1146 return pods_v_set( $value, $var, $type );
1147 }
1148
1149 /**
1150 * Create a new URL off of the current one, with updated parameters
1151 *
1152 * @param array $array Parameters to be set (empty will remove it)
1153 * @param array $allowed Parameters to keep (if empty, all are kept)
1154 * @param array $excluded Parameters to always remove
1155 * @param string $url URL to base update off of
1156 *
1157 * @return mixed
1158 *
1159 * @since 2.3.10
1160 *
1161 * @see add_query_arg
1162 */
1163 function pods_query_arg( $array = null, $allowed = null, $excluded = null, $url = null ) {
1164 $array = (array) $array;
1165 $allowed = (array) $allowed;
1166 $excluded = (array) $excluded;
1167
1168 // Support for globally defined arguments.
1169 global $pods_query_args;
1170
1171 if ( empty( $pods_query_args ) ) {
1172 $pods_query_args = [
1173 'allowed' => array(),
1174 'excluded' => array(),
1175 ];
1176 }
1177
1178 // Merge any global args that we need to.
1179 $allowed = array_unique( array_merge( $pods_query_args['allowed'], $allowed ) );
1180 $excluded = array_unique( array_merge( $pods_query_args['excluded'], $excluded ) );
1181
1182 if ( ! isset( $_GET ) || $url ) {
1183 $query_args = array();
1184 } else {
1185 $query_args = pods_unsanitize( $_GET );
1186 }
1187
1188 foreach ( $query_args as $key => $val ) {
1189 if ( is_array( $val ) && empty( $val ) ) {
1190 $query_args[ $key ] = false;
1191 } elseif ( ! is_array( $val ) && '' === $val ) {
1192 $query_args[ $key ] = false;
1193 } elseif ( ! empty( $allowed ) ) {
1194 $allow_it = false;
1195
1196 foreach ( $allowed as $allow ) {
1197 if ( $allow === $key ) {
1198 $allow_it = true;
1199 } elseif ( false !== strpos( $allow, '*' ) && 0 === strpos( $key, trim( $allow, '*' ) ) ) {
1200 $allow_it = true;
1201 }
1202 }
1203
1204 if ( ! $allow_it ) {
1205 $query_args[ $key ] = false;
1206 }
1207 }
1208 }//end foreach
1209
1210 if ( ! empty( $excluded ) ) {
1211 foreach ( $excluded as $exclusion ) {
1212 if ( isset( $query_args[ $exclusion ] ) && ! in_array( $exclusion, $allowed, true ) ) {
1213 $query_args[ $exclusion ] = false;
1214 }
1215 }
1216 }
1217
1218 if ( ! empty( $array ) ) {
1219 foreach ( $array as $key => $val ) {
1220 if ( null !== $val || false === strpos( $key, '*' ) ) {
1221 if ( is_array( $val ) && ! empty( $val ) ) {
1222 $query_args[ $key ] = $val;
1223 } elseif ( ! is_array( $val ) && 0 < strlen( $val ) ) {
1224 $query_args[ $key ] = $val;
1225 } else {
1226 $query_args[ $key ] = false;
1227 }
1228 } else {
1229 $key = str_replace( '*', '', $key );
1230
1231 foreach ( $query_args as $k => $v ) {
1232 if ( false !== strpos( $k, $key ) ) {
1233 $query_args[ $k ] = false;
1234 }
1235 }
1236 }
1237 }
1238 }//end if
1239
1240 if ( null === $url ) {
1241 $url = add_query_arg( $query_args );
1242 } else {
1243 $url = add_query_arg( $query_args, $url );
1244 }
1245
1246 return $url;
1247 }
1248
1249 /**
1250 * Create a new URL off of the current one, with updated parameters
1251 *
1252 * @param array $array Parameters to be set (empty will remove it)
1253 * @param array $allowed Parameters to keep (if empty, all are kept)
1254 * @param array $excluded Parameters to always remove
1255 * @param string $url URL to base update off of
1256 *
1257 * @return mixed
1258 *
1259 * @since 2.0.0
1260 *
1261 * @deprecated 2.4.0 Use pods_query_arg() instead.
1262 * @see pods_query_arg
1263 */
1264 function pods_var_update( $array = null, $allowed = null, $excluded = null, $url = null ) {
1265 return pods_query_arg( $array, $allowed, $excluded, $url );
1266 }
1267
1268 /**
1269 * Cast a value as a specific type
1270 *
1271 * @param mixed $value
1272 * @param mixed $cast_from
1273 *
1274 * @return bool
1275 *
1276 * @since 2.0.0
1277 */
1278 function pods_cast( $value, $cast_from = null ) {
1279 if ( null !== $cast_from ) {
1280 if ( is_object( $value ) && is_array( $cast_from ) ) {
1281 $value = get_object_vars( $value );
1282 } elseif ( is_array( $value ) && is_object( $cast_from ) ) {
1283 $value = (object) $value;
1284 } else {
1285 settype( $value, gettype( $cast_from ) );
1286 }
1287 }
1288
1289 return $value;
1290 }
1291
1292 /**
1293 * Create a slug from an input string
1294 *
1295 * @param string $orig Original string.
1296 * @param bool $strict Whether to only support 0-9, a-z, A-Z, and dash characters.
1297 *
1298 * @return string Sanitized slug
1299 *
1300 * @since 1.8.9
1301 */
1302 function pods_create_slug( $orig, $strict = true ) {
1303 $str = remove_accents( $orig );
1304 $str = preg_replace( '/([_ \\/])/', '-', trim( $orig ) );
1305
1306 if ( $strict ) {
1307 $str = preg_replace( '/([^0-9a-z\-])/', '', strtolower( $str ) );
1308 } else {
1309 $str = urldecode( sanitize_title( strtolower( $str ) ) );
1310 }
1311
1312 $str = preg_replace( '/(\-){2,}/', '-', $str );
1313 $str = trim( $str, '-' );
1314 $str = apply_filters( 'pods_create_slug', $str, $orig );
1315
1316 return $str;
1317 }
1318
1319 /**
1320 * Build a unique slug
1321 *
1322 * @param string $slug The slug value
1323 * @param string $column_name The column name
1324 * @param string|array $pod The Pod name or array of Pod data
1325 * @param int $pod_id The Pod ID
1326 * @param int $id The item ID
1327 * @param object $obj (optional)
1328 *
1329 * @param bool $strict
1330 *
1331 * @return string The unique slug name
1332 * @since 1.7.2
1333 */
1334 function pods_unique_slug( $slug, $column_name, $pod, $pod_id = 0, $id = 0, $obj = null, $strict = true ) {
1335 $slug = pods_create_slug( $slug, $strict );
1336
1337 $pod_data = array();
1338
1339 if ( is_array( $pod ) || $pod instanceof Pods\Whatsit ) {
1340 $pod_data = $pod;
1341 $pod_id = pods_v_sanitized( 'id', $pod_data, 0 );
1342 $pod = pods_v_sanitized( 'name', $pod_data );
1343 }
1344
1345 $pod_id = absint( $pod_id );
1346 $id = absint( $id );
1347
1348 if ( empty( $pod_data ) ) {
1349 $pod_data = pods_api()->load_pod( array(
1350 'id' => $pod_id,
1351 'name' => $pod,
1352 ), false );
1353 }
1354
1355 if ( empty( $pod_data ) || empty( $pod_id ) || empty( $pod ) ) {
1356 return $slug;
1357 }
1358
1359 if ( 'table' !== $pod_data['storage'] || ! in_array( $pod_data['type'], array( 'pod', 'table' ), true ) ) {
1360 return $slug;
1361 }
1362
1363 $check_sql = "
1364 SELECT DISTINCT `t`.`{$column_name}` AS `slug`
1365 FROM `@wp_pods_{$pod}` AS `t`
1366 WHERE `t`.`{$column_name}` = %s AND `t`.`id` != %d
1367 LIMIT 1
1368 ";
1369
1370 $slug_check = pods_query( array( $check_sql, $slug, $id ), $obj );
1371
1372 if ( ! empty( $slug_check ) || apply_filters( 'pods_unique_slug_is_bad_flat_slug', false, $slug, $column_name, $pod, $pod_id, $id, $pod_data, $obj ) ) {
1373 $suffix = 2;
1374
1375 do {
1376 $alt_slug = substr( $slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-{$suffix}";
1377
1378 $slug_check = pods_query( array( $check_sql, $alt_slug, $id ), $obj );
1379
1380 $suffix ++;
1381 } while ( ! empty( $slug_check ) || apply_filters( 'pods_unique_slug_is_bad_flat_slug', false, $alt_slug, $column_name, $pod, $pod_id, $id, $pod_data, $obj ) );
1382
1383 $slug = $alt_slug;
1384 }
1385
1386 $slug = apply_filters( 'pods_unique_slug', $slug, $id, $column_name, $pod, $pod_id, $obj );
1387
1388 return $slug;
1389 }
1390
1391 /**
1392 * Return a lowercase alphanumeric name (use pods_js_name if you want "_" instead of "-" )
1393 *
1394 * @param string $orig Input string to clean
1395 * @param boolean $lower Force lowercase
1396 * @param boolean $trim_underscores Whether to trim off underscores
1397 *
1398 * @return string Sanitized name
1399 *
1400 * @since 1.2.0
1401 */
1402 function pods_clean_name( $orig, $lower = true, $trim_underscores = false ) {
1403 if ( null === $orig ) {
1404 return '';
1405 }
1406
1407 $str = trim( (string) $orig );
1408 $str = remove_accents( $str );
1409 $str = preg_replace( '/([^0-9a-zA-Z\-_\s])/', '', $str );
1410 $str = preg_replace( '/(\s_)/', '_', $str );
1411 $str = preg_replace( '/(\s+)/', '_', $str );
1412 $str = preg_replace( '/(-){2,}/', '-', $str );
1413
1414 if ( $lower ) {
1415 $str = strtolower( $str );
1416 }
1417
1418 if ( $trim_underscores ) {
1419 $str = trim( $str, '_' );
1420 }
1421
1422 return $str;
1423 }
1424
1425 /**
1426 * Return a lowercase alphanumeric name (with underscores) for safe JavaScript variable names.
1427 *
1428 * @param string $orig Input string to clean.
1429 * @param boolean $lower Whether to force lowercase.
1430 *
1431 * @return string The sanitized name.
1432 *
1433 * @since 2.5.3
1434 */
1435 function pods_js_name( $orig, $lower = true ) {
1436 $str = pods_clean_name( $orig, $lower );
1437 $str = str_replace( '-', '_', $str );
1438
1439 return $str;
1440 }
1441
1442 /**
1443 * Return a camelCase alphanumeric name for safe JavaScript variable names.
1444 *
1445 * @param string $orig Input string to clean.
1446 *
1447 * @return string The sanitized name as camelCase.
1448 *
1449 * @since 2.8.0
1450 */
1451 function pods_js_camelcase_name( $orig ) {
1452 // Clean the name for JS.
1453 $str = pods_js_name( $orig, false );
1454
1455 // Replace _ with spaces and then Upper Case the words.
1456 $str = ucwords( str_replace( '_', ' ', $str ) );
1457
1458 // Remove the spaces and lower case the firstWord.
1459 return lcfirst( str_replace( ' ', '', $str ) );
1460 }
1461
1462 /**
1463 * Get the Absolute Integer of a value
1464 *
1465 * @param string $maybeint
1466 * @param bool $strict (optional) Check if $maybeint is a integer.
1467 * @param bool $allow_negative (optional)
1468 *
1469 * @return integer
1470 * @since 2.0.0
1471 */
1472 function pods_absint( $maybeint, $strict = true, $allow_negative = false ) {
1473 if ( is_null( $maybeint ) ) {
1474 $maybeint = 0;
1475 } elseif ( is_bool( $maybeint ) ) {
1476 $maybeint = (int) $maybeint;
1477 }
1478
1479 if ( true === $strict && ! is_numeric( trim( $maybeint ) ) ) {
1480 return 0;
1481 }
1482
1483 if ( false !== $allow_negative ) {
1484 return intval( $maybeint );
1485 }
1486
1487 return absint( $maybeint );
1488 }
1489
1490 /**
1491 * Functions like str_replace except it will restrict $occurrences
1492 *
1493 * @since 2.0
1494 *
1495 * @param mixed $find
1496 * @param mixed $replace
1497 * @param string $string
1498 * @param int $occurrences (optional)
1499 *
1500 * @return mixed
1501 */
1502 function pods_str_replace( $find, $replace, $string, $occurrences = - 1 ) {
1503 if ( is_array( $string ) ) {
1504 foreach ( $string as $k => $v ) {
1505 $string[ $k ] = pods_str_replace( $find, $replace, $v, $occurrences );
1506 }
1507
1508 return $string;
1509 } elseif ( is_object( $string ) ) {
1510 $string = get_object_vars( $string );
1511
1512 foreach ( $string as $k => $v ) {
1513 $string[ $k ] = pods_str_replace( $find, $replace, $v, $occurrences );
1514 }
1515
1516 return (object) $string;
1517 }
1518
1519 if ( is_array( $find ) ) {
1520 foreach ( $find as &$f ) {
1521 $f = '/' . preg_quote( $f, '/' ) . '/';
1522 }
1523 } else {
1524 $find = '/' . preg_quote( $find, '/' ) . '/';
1525 }
1526 if ( is_string( $string ) ) {
1527 return preg_replace( $find, $replace, $string, $occurrences );
1528 } else {
1529 // Occasionally we will receive non string values (true, false, null). Allow those to pass through
1530 return $string;
1531 }
1532 }
1533
1534 /**
1535 * Use mb_strlen if available, otherwise fallback to strlen
1536 *
1537 * @param string $string
1538 *
1539 * @return int
1540 */
1541 function pods_mb_strlen( $string ) {
1542 if ( function_exists( 'mb_strlen' ) ) {
1543 return mb_strlen( $string );
1544 }
1545
1546 return strlen( $string );
1547 }
1548
1549 /**
1550 * Use mb_substr if available, otherwise fallback to substr
1551 *
1552 * @param string $string
1553 * @param int $start
1554 * @param null|int $length
1555 * @param null|string $encoding
1556 *
1557 * @return string
1558 */
1559 function pods_mb_substr( $string, $start, $length = null, $encoding = null ) {
1560 if ( function_exists( 'mb_substr' ) ) {
1561 if ( null === $encoding ) {
1562 $encoding = mb_internal_encoding();
1563 }
1564
1565 return mb_substr( $string, $start, $length, $encoding );
1566 }
1567
1568 return substr( $string, $start, $length );
1569 }
1570
1571 /**
1572 * Evaluate tags like magic tags but through pods_v and sanitize for SQL with an empty double quote if needed.
1573 *
1574 * @since 2.7.23
1575 *
1576 * @param string|array|object $tags String to be evaluated.
1577 * @param array $args {
1578 * Function arguments.
1579 * @type bool $sanitize Whether to sanitize.
1580 * @type null|mixed $fallback The fallback value to use if not set, should already be sanitized.
1581 * @type Pods $pod Pod to parse the tags through.
1582 * @type bool $use_current_pod Whether to auto-detect the current Pod.
1583 * }
1584 *
1585 * @return string Evaluated string.
1586 *
1587 * @see pods_evaluate_tag
1588 */
1589 function pods_evaluate_tags_sql( $tags, $args = array() ) {
1590 // The temporary placeholder we will use.
1591 $placeholder = '__PODS__TMP__EMPTY_VALUE__';
1592
1593 // Store and overwrite fallback argument.
1594 $fallback = '""';
1595 if ( isset( $args['fallback'] ) ) {
1596 $fallback = $args['fallback'];
1597 $args['fallback'] = $placeholder;
1598 }
1599
1600 $defaults = array(
1601 'sanitize' => true,
1602 'fallback' => $placeholder,
1603 );
1604
1605 // Set default arguments to use.
1606 $args = array_merge( $defaults, $args );
1607
1608 // Evaluate the magic tags.
1609 $evaluated = pods_evaluate_tags( $tags, $args );
1610
1611 $find = array(
1612 '= ' . $placeholder,
1613 '=' . $placeholder,
1614 $placeholder,
1615 );
1616
1617 $replace = array(
1618 '= ' . $fallback,
1619 '=' . $fallback,
1620 '',
1621 );
1622
1623 // Finish sanitizing the string so it is SQL-safe.
1624 $sanitized = str_replace( $find, $replace, $evaluated );
1625
1626 /**
1627 * Allow filtering the result of how we evaluate and sanitize the SQL.
1628 *
1629 * @since 2.7.23
1630 *
1631 * @param string $sanitized The evaluated and sanitized string.
1632 * @param string $evaluated The evaluated string.
1633 * @param string|array|object $tags Original string to be evaluated.
1634 * @param array $args Additional function arguments.
1635 */
1636 return apply_filters( 'pods_evaluate_tags_sql', $sanitized, $evaluated, $tags, $args );
1637 }
1638
1639 /**
1640 * Evaluate tags like magic tags but through pods_v.
1641 *
1642 * @param string|array|object $tags String to be evaluated.
1643 * @param array $args {
1644 * Function arguments.
1645 * @type bool $sanitize Whether to sanitize.
1646 * @type null|mixed $fallback The fallback value to use if not set, should already be sanitized.
1647 * @type Pods $pod Pod to parse the tags through.
1648 * @type bool $use_current_pod Whether to auto-detect the current Pod.
1649 * }
1650 *
1651 * @return string
1652 *
1653 * @since 2.1
1654 *
1655 * @see pods_evaluate_tag
1656 */
1657 function pods_evaluate_tags( $tags, $args = array() ) {
1658
1659 // Back compat.
1660 if ( ! is_array( $args ) ) {
1661 $prev_args = array( 'tags', 'sanitize', 'fallback' );
1662 $args = func_get_args();
1663 $args = array_combine( array_slice( $prev_args, 0, count( $args ) ), $args );
1664 unset( $args['tags'] );
1665 }
1666
1667 if ( is_array( $tags ) ) {
1668 foreach ( $tags as $k => $tag ) {
1669 $tags[ $k ] = pods_evaluate_tags( $tag, $args );
1670 }
1671
1672 return $tags;
1673 }
1674
1675 if ( is_object( $tags ) ) {
1676 $tags = get_object_vars( $tags );
1677
1678 // Evaluate array and cast as object.
1679 $tags = (object) pods_evaluate_tags( $tags, $args );
1680
1681 return $tags;
1682 }
1683
1684 return preg_replace_callback(
1685 '/({@(.*?)})/m',
1686 function ( $tag ) use ( $args ) {
1687 return pods_evaluate_tag( $tag, $args );
1688 },
1689 (string) $tags
1690 );
1691 }
1692
1693 /**
1694 * Evaluate tag like magic tag but sanitized.
1695 *
1696 * @since 2.1
1697 *
1698 * @param string|array $tag String to be evaluated.
1699 * @param array $args {
1700 * Function arguments.
1701 * @type null|mixed $fallback The fallback value to use if not set, should already be sanitized.
1702 * @type Pods $pod Pod to parse the tags through.
1703 * @type bool $use_current_pod Whether to auto-detect the current Pod.
1704 * }
1705 *
1706 * @return string Evaluated content.
1707 *
1708 * @see pods_evaluate_tag
1709 */
1710 function pods_evaluate_tag_sanitized( $tag, $args = array() ) {
1711 if ( ! is_array( $args ) ) {
1712 $args = array();
1713 }
1714 $args['sanitize'] = true;
1715 return pods_evaluate_tag( $tag, $args );
1716 }
1717
1718 /**
1719 * Evaluate tag like magic tag but mapped through pods_v.
1720 *
1721 * @since 2.1
1722 *
1723 * @param string|array $tag String to be evaluated.
1724 * @param array $args {
1725 * Function arguments.
1726 * @type bool $sanitize Whether to sanitize.
1727 * @type null|mixed $fallback The fallback value to use if not set, should already be sanitized.
1728 * @type bool|Pods $pod Pod to parse the tags through.
1729 * @type bool $use_current_pod Whether to auto-detect the current Pod.
1730 * }
1731 *
1732 * @return string Evaluated content.
1733 */
1734 function pods_evaluate_tag( $tag, $args = array() ) {
1735 $defaults = array(
1736 'sanitize' => false,
1737 'fallback' => null,
1738 'pod' => null,
1739 'use_current_pod' => false,
1740 );
1741
1742 // Back compat.
1743 if ( ! is_array( $args ) ) {
1744 $prev_args = array( 'tag', 'sanitize', 'fallback' );
1745 $args = func_get_args();
1746 $args = array_combine( array_slice( $prev_args, 0, count( $args ) ), $args );
1747 unset( $args['tag'] );
1748 }
1749
1750 $args = wp_parse_args( $args, $defaults );
1751 $sanitize = $args['sanitize'];
1752 $fallback = $args['fallback'];
1753 $pod = $args['pod'];
1754
1755 // Handle pods_evaluate_tags
1756 if ( is_array( $tag ) ) {
1757 if ( ! isset( $tag[2] ) && '' === trim( $tag[2] ) ) {
1758 if ( null === $fallback ) {
1759 return '';
1760 }
1761
1762 return $fallback;
1763 }
1764
1765 $tag = $tag[2];
1766 }
1767
1768 if ( $args['use_current_pod'] ) {
1769 $pod = pods();
1770 }
1771
1772 // Handle Pod fields.
1773 // The Pod will call this function without Pod param if no field is found.
1774 if ( $pod instanceof Pods ) {
1775 $value = $pod->do_magic_tags( '{@' . $tag . '}' );
1776
1777 if ( ! $value ) {
1778 if ( null === $fallback ) {
1779 return '';
1780 }
1781
1782 return $fallback;
1783 }
1784
1785 if ( $sanitize ) {
1786 $value = pods_sanitize( $value );
1787 }
1788
1789 return $value;
1790 }
1791
1792 $tag = trim( $tag, ' {@}' );
1793 $tag = explode( ',', $tag );
1794 $tag = pods_trim( $tag );
1795
1796 $value = '';
1797 $helper = isset( $tag[1] ) ? $tag[1] : null;
1798 $before = isset( $tag[2] ) ? $tag[2] : '';
1799 $after = isset( $tag[3] ) ? $tag[3] : '';
1800
1801 $tag = explode( '.', $tag[0] );
1802
1803 if ( empty( $tag ) || ! isset( $tag[0] ) || '' === trim( $tag[0] ) ) {
1804 if ( null === $fallback ) {
1805 return '';
1806 }
1807
1808 return $fallback;
1809 }
1810
1811 // Fix formatting that may be after the first .
1812 if ( 2 < count( $tag ) ) {
1813 $first_tag = $tag[0];
1814 unset( $tag[0] );
1815
1816 $tag = array(
1817 $first_tag,
1818 implode( '.', $tag ),
1819 );
1820 }
1821
1822 $tag = pods_trim( $tag );
1823
1824 $single_supported = array(
1825 'template-url',
1826 'stylesheet-url',
1827 'site-url',
1828 'home-url',
1829 'admin-url',
1830 'includes-url',
1831 'content-url',
1832 'plugins-url',
1833 'network-site-url',
1834 'network-home-url',
1835 'network-admin-url',
1836 'user-admin-url',
1837 'prefix',
1838 );
1839
1840 $pods_v_var = '';
1841 $pods_v_type = 'get';
1842
1843 if ( in_array( $tag[0], $single_supported, true ) ) {
1844 $pods_v_type = $tag[0];
1845 } elseif ( 1 === count( $tag ) ) {
1846 $pods_v_var = $tag[0];
1847 } elseif ( 2 === count( $tag ) ) {
1848 $pods_v_var = $tag[1];
1849 $pods_v_type = $tag[0];
1850 } else {
1851 // Some magic tags support traversal.
1852 $pods_v_var = array_slice( $tag, 1 );
1853 $pods_v_type = $tag[0];
1854 }
1855
1856 $value = pods_v( $pods_v_var, $pods_v_type, null, false, [
1857 'source' => 'magic-tag',
1858 ] );
1859
1860 if ( $helper ) {
1861 if ( ! $pod instanceof Pods ) {
1862 $pod = pods();
1863 }
1864
1865 $value = $pod->helper( $helper, $value );
1866 }
1867
1868 /**
1869 * Allow filtering the evaluated tag value.
1870 *
1871 * @since unknown
1872 *
1873 * @param mixed $value The evaluated tag value.
1874 * @param string $tag The evaluated tag name.
1875 * @param null|mixed $fallback The fallback value to use if not set, should already be sanitized.
1876 */
1877 $value = apply_filters( 'pods_evaluate_tag', $value, $tag, $fallback );
1878
1879 if ( is_array( $value ) && 1 === count( $value ) ) {
1880 $value = current( $value );
1881 }
1882
1883 if ( is_array( $value ) ) {
1884 $value = pods_serial_comma( $value );
1885 }
1886
1887 if ( null === $value ) {
1888 $value = '';
1889 }
1890
1891 if ( $sanitize ) {
1892 $value = pods_sanitize( $value );
1893 }
1894
1895 if ( null !== $fallback && '' === $value ) {
1896 $value = $fallback;
1897 }
1898
1899 return $before . $value . $after;
1900 }
1901
1902 /**
1903 * Split an array into human readable text (Item, Item, and Item)
1904 *
1905 * @param array $value
1906 * @param string $field
1907 * @param array $fields
1908 * @param string $and
1909 * @param string $field_index
1910 *
1911 * @return string
1912 *
1913 * @since 2.0.0
1914 */
1915 function pods_serial_comma( $value, $field = null, $fields = null, $and = null, $field_index = null ) {
1916 if ( is_object( $value ) ) {
1917 $value = get_object_vars( $value );
1918 }
1919
1920 $defaults = array(
1921 'field' => $field,
1922 'fields' => $fields,
1923 'and' => $and,
1924 'field_index' => $field_index,
1925 'separator' => null,
1926 'serial' => true,
1927 );
1928
1929 if ( is_array( $field ) ) {
1930 $defaults['field'] = null;
1931
1932 $params = array_merge( $defaults, $field );
1933 } else {
1934 $params = $defaults;
1935 }
1936
1937 $params = (object) $params;
1938
1939 $simple = false;
1940
1941 if ( ! empty( $params->fields ) && is_array( $params->fields ) && isset( $params->fields[ $params->field ] ) ) {
1942 $params->field = $params->fields[ $params->field ];
1943
1944 $simple_tableless_objects = PodsForm::simple_tableless_objects();
1945
1946 if ( ! empty( $params->field ) && ! is_string( $params->field ) && in_array( $params->field['type'], PodsForm::tableless_field_types(), true ) ) {
1947 if ( in_array( $params->field['type'], PodsForm::file_field_types(), true ) ) {
1948 if ( null === $params->field_index ) {
1949 $params->field_index = 'guid';
1950 }
1951 } elseif ( in_array( $params->field['pick_object'], $simple_tableless_objects, true ) ) {
1952 $simple = true;
1953 } else {
1954 $pick_object = pods_v( 'pick_object', $params->field );
1955 $pick_val = pods_v( 'pick_val', $params->field );
1956 $table = null;
1957
1958 if ( ! empty( $pick_object ) && ( ! empty( $pick_val ) || in_array( $pick_object, array( 'user', 'media', 'comment' ), true ) ) ) {
1959 $table = pods_api()->get_table_info(
1960 $pick_object,
1961 $pick_val,
1962 null,
1963 null,
1964 $params->field
1965 );
1966 }
1967
1968 if ( ! empty( $table ) ) {
1969 if ( null === $params->field_index ) {
1970 $params->field_index = $table['field_index'];
1971 }
1972 }
1973 }
1974 }
1975 } else {
1976 $params->field = null;
1977 }//end if
1978
1979 if ( $simple && ! is_array( $value ) && '' !== $value && null !== $value ) {
1980 $value = PodsForm::field_method( 'pick', 'simple_value', $params->field['name'], $value, $params->field );
1981 }
1982
1983 if ( ! is_array( $value ) ) {
1984 return $value;
1985 }
1986
1987 $value = pods_access_bleep_data( $value );
1988
1989 $original_value = $value;
1990
1991 if ( in_array( $params->separator, array( '', null ), true ) ) {
1992 $params->separator = ', ';
1993 }
1994
1995 if ( null === $params->and ) {
1996 $params->and = ' ' . __( 'and', 'pods' ) . ' ';
1997 }
1998
1999 /**
2000 * Allow filtering the "and" content used for pods_serial_comma.
2001 *
2002 * @since 2.7.17
2003 *
2004 * @param string|null $and The "and" content used, return null to disable.
2005 * @param string $value The value input into pods_serial_comma.
2006 * @param object $params The list of the setup parameters for pods_serial_comma.
2007 */
2008 $params->and = apply_filters( 'pods_serial_comma_and', $params->and, $value, $params );
2009
2010 /**
2011 * Allow filtering the "separator" content used for pods_serial_comma.
2012 *
2013 * @since 2.7.17
2014 *
2015 * @param string $separator The "separator" content used (default ", ").
2016 * @param string $value The value input into pods_serial_comma.
2017 * @param object $params The list of the setup parameters for pods_serial_comma.
2018 */
2019 $params->separator = apply_filters( 'pods_serial_comma_separator', $params->separator, $value, $params );
2020
2021 $last = '';
2022
2023 if ( ! empty( $value ) ) {
2024 $last = array_pop( $value );
2025 }
2026
2027 if ( $simple && ! is_array( $last ) && '' !== $last && null !== $last ) {
2028 $last = PodsForm::field_method( 'pick', 'simple_value', $params->field['name'], $last, $params->field );
2029 }
2030
2031 if ( is_array( $last ) ) {
2032 if ( null !== $params->field_index && isset( $last[ $params->field_index ] ) ) {
2033 $last = $last[ $params->field_index ];
2034 } elseif ( isset( $last[0] ) ) {
2035 $last = $last[0];
2036 } elseif ( $simple ) {
2037 $last = current( $last );
2038 } else {
2039 $last = '';
2040 }
2041 }
2042
2043 if ( ! empty( $value ) ) {
2044 if ( null !== $params->field_index && isset( $original_value[ $params->field_index ] ) ) {
2045 return $original_value[ $params->field_index ];
2046 } elseif ( null !== $params->field_index && isset( $value[ $params->field_index ] ) ) {
2047 return $value[ $params->field_index ];
2048 } elseif ( ! is_array( $value ) ) {
2049 $value = array( $value );
2050 }
2051
2052 foreach ( $value as $k => $v ) {
2053 if ( $simple && ! is_array( $v ) && '' !== $v && null !== $v ) {
2054 $v = PodsForm::field_method( 'pick', 'simple_value', $params->field['name'], $v, $params->field );
2055 }
2056
2057 if ( is_array( $v ) ) {
2058 if ( null !== $params->field_index && isset( $v[ $params->field_index ] ) ) {
2059 $v = $v[ $params->field_index ];
2060 } elseif ( $simple ) {
2061 $v = trim( implode( $params->separator, $v ), $params->separator . ' ' );
2062 } else {
2063 unset( $value[ $k ] );
2064
2065 continue;
2066 }
2067 }
2068
2069 $value[ $k ] = $v;
2070 }
2071
2072 $has_serial_comma = $params->serial && 1 < count( $value );
2073
2074 $value = trim( implode( $params->separator, $value ), $params->separator . ' ' );
2075
2076 // Add final serial comma.
2077 if ( $has_serial_comma ) {
2078 /**
2079 * Allow filtering the final serial comma (before the "and") used for pods_serial_comma.
2080 *
2081 * @since unknown
2082 *
2083 * @param string $serial_comma The serial comma content used, return an empty string to disable (default ", ").
2084 * @param string $value The formatted value.
2085 * @param string $original_value The original value input into pods_serial_comma.
2086 * @param object $params The list of the setup parameters for pods_serial_comma.
2087 */
2088 $serial_comma = apply_filters( 'pods_serial_comma', $params->separator, $value, $original_value, $params );
2089
2090 if ( '' !== $serial_comma ) {
2091 $value .= $serial_comma;
2092 }
2093 }
2094
2095 $value = trim( $value );
2096 $last = trim( $last );
2097
2098 if ( 0 < strlen( $value ) && 0 < strlen( $last ) ) {
2099 $value = $value . $params->and . $last;
2100 } elseif ( 0 < strlen( $last ) ) {
2101 $value = $last;
2102 } else {
2103 $value = '';
2104 }
2105 } else {
2106 $value = $last;
2107 }//end if
2108
2109 $value = trim( $value, $params->separator . ' ' );
2110
2111 $value = apply_filters( 'pods_serial_comma_value', $value, $original_value, $params );
2112
2113 return (string) $value;
2114 }
2115
2116 /**
2117 * Return a variable if a user is logged in or anonymous, or a specific capability
2118 *
2119 * @param mixed $anon Variable to return if user is anonymous (not logged in)
2120 * @param mixed $user Variable to return if user is logged in
2121 * @param string|array $capability Capability or array of Capabilities to check to return $user on
2122 *
2123 * @return mixed $user Variable to return if user is logged in (if logged in), otherwise $anon
2124 *
2125 * @since 2.0.5
2126 */
2127 function pods_var_user( $anon = false, $user = true, $capability = null ) {
2128 $value = $anon;
2129
2130 if ( is_user_logged_in() ) {
2131 if ( empty( $capability ) ) {
2132 $value = $user;
2133 } else {
2134 $capabilities = (array) $capability;
2135
2136 foreach ( $capabilities as $capability ) {
2137 if ( current_user_can( $capability ) ) {
2138 $value = $user;
2139
2140 break;
2141 }
2142 }
2143 }
2144 }
2145
2146 return $value;
2147 }
2148
2149 /**
2150 * Take a one-level list of items and make it hierarchical
2151 *
2152 * @param array|object $list List of items
2153 * @param array $args Array of parent, children, and id keys to use
2154 *
2155 * @return array|object
2156 * @since 2.3.0
2157 */
2158 function pods_hierarchical_list( $list, $args = array() ) {
2159 if ( empty( $args ) || ( ! is_object( $list ) && ! is_array( $list ) ) ) {
2160 return $list;
2161 }
2162
2163 $defaults = array(
2164 'id' => 'id',
2165 'parent' => 'parent',
2166 'children' => 'children',
2167 'orphans' => true,
2168 'found' => array(),
2169 'list' => array(),
2170 'current_depth' => - 1,
2171 );
2172
2173 $args = array_merge( $defaults, (array) $args );
2174
2175 $list = pods_hierarchical_list_recurse( 0, $list, $args );
2176
2177 return $list;
2178 }
2179
2180 /**
2181 * Recurse list of items and make it hierarchical
2182 *
2183 * @param int $parent Parent ID
2184 * @param array|object $list List of items
2185 * @param array $args Array of parent, children, and id keys to use
2186 *
2187 * @return array|object
2188 * @since 2.3.0
2189 */
2190 function pods_hierarchical_list_recurse( $parent, $list, &$args ) {
2191 $new = array();
2192
2193 $object = false;
2194
2195 if ( is_object( $list ) ) {
2196 $object = true;
2197 $list = get_object_vars( $list );
2198 }
2199
2200 $args['current_depth'] ++;
2201
2202 $depth = $args['current_depth'];
2203
2204 if ( 0 == $depth ) {
2205 $args['list'] = $list;
2206 }
2207
2208 foreach ( $list as $k => $list_item ) {
2209 if ( is_object( $list_item ) && isset( $list_item->{$args['id']} ) ) {
2210 $list_item->{$args['parent']} = (int) pods_v( $args['parent'], $list_item );
2211
2212 if ( is_array( $list_item->{$args['parent']} ) && isset( $list_item->{$args['parent']}[ $args['id'] ] ) && $parent == $list_item->{$args['parent']}[ $args['id'] ] ) {
2213 $list_item->{$args['children']} = pods_hierarchical_list_recurse( $list_item->{$args['id']}, $list, $args );
2214 } elseif ( $parent == $list_item->{$args['parent']} || ( 0 == $depth && $parent == $list_item->{$args['id']} ) ) {
2215 $list_item->{$args['children']} = pods_hierarchical_list_recurse( $list_item->{$args['id']}, $list, $args );
2216 } else {
2217 continue;
2218 }
2219
2220 $args['found'][ $k ] = $list_item;
2221 } elseif ( is_array( $list_item ) && isset( $list_item[ $args['id'] ] ) ) {
2222 $list_item[ $args['parent'] ] = (int) pods_v( $args['parent'], $list_item );
2223
2224 if ( is_array( $list_item[ $args['parent'] ] ) && isset( $list_item[ $args['parent'] ][ $args['id'] ] ) && $parent == $list_item[ $args['parent'] ][ $args['id'] ] ) {
2225 $list_item[ $args['children'] ] = pods_hierarchical_list_recurse( $list_item[ $args['id'] ], $list, $args );
2226 } elseif ( $parent == $list_item[ $args['parent'] ] || ( 0 == $depth && $parent == $list_item[ $args['id'] ] ) ) {
2227 $list_item[ $args['children'] ] = pods_hierarchical_list_recurse( $list_item[ $args['id'] ], $list, $args );
2228 } else {
2229 continue;
2230 }
2231
2232 $args['found'][ $k ] = $list_item;
2233 } else {
2234 continue;
2235 }//end if
2236
2237 $new[ $k ] = $list_item;
2238
2239 $args['current_depth'] = $depth;
2240 }//end foreach
2241
2242 if ( 0 == $depth && empty( $new ) && ! empty( $list ) ) {
2243 $first = current( array_slice( $list, 0, 1 ) );
2244
2245 $new_parent = 0;
2246
2247 $args['current_depth'] = - 1;
2248
2249 if ( is_object( $first ) && isset( $first->{$args['parent']} ) ) {
2250 $new_parent = (int) $first->{$args['parent']};
2251 } elseif ( is_array( $first ) && isset( $first[ $args['parent'] ] ) ) {
2252 $new_parent = (int) $first[ $args['parent'] ];
2253 }
2254
2255 if ( ! empty( $new_parent ) ) {
2256 $new = pods_hierarchical_list_recurse( $new_parent, $list, $args );
2257 }
2258 }
2259
2260 if ( 0 == $depth ) {
2261 $orphans = array();
2262
2263 foreach ( $args['list'] as $k => $list_item ) {
2264 if ( ! isset( $args['found'][ $k ] ) ) {
2265 $orphans[ $k ] = $list_item;
2266 }
2267 }
2268
2269 if ( ! empty( $orphans ) ) {
2270 foreach ( $orphans as $orphan ) {
2271 $new[] = $orphan;
2272 }
2273 }
2274 }
2275
2276 if ( $object ) {
2277 $new = (object) $new;
2278 }
2279
2280 return $new;
2281 }
2282
2283 /**
2284 * Take a one-level list of items and make it hierarchical for <select>
2285 *
2286 * @param array|object $list List of items
2287 * @param array $args Array of index, parent, children, id, and prefix keys to use
2288 *
2289 * @return array|object
2290 * @internal param string $children_key Key to recurse children into
2291 *
2292 * @since 2.3.0
2293 */
2294 function pods_hierarchical_select( $list, $args = array() ) {
2295 $object = false;
2296
2297 if ( is_object( $list ) ) {
2298 $object = true;
2299 $list = get_object_vars( $list );
2300 }
2301
2302 $list = pods_hierarchical_list( $list, $args );
2303
2304 $defaults = array(
2305 'index' => 'name',
2306 'children' => 'children',
2307 'prefix' => '&nbsp;&nbsp;&nbsp;',
2308 );
2309
2310 $args = array_merge( $defaults, (array) $args );
2311
2312 $list = pods_hierarchical_select_recurse( $list, $args, 0 );
2313
2314 if ( $object ) {
2315 $list = (object) $list;
2316 }
2317
2318 return $list;
2319 }
2320
2321 /**
2322 * Recurse list of hierarchical data
2323 *
2324 * @param array $items Items to recurse.
2325 * @param array $args Array of children and prefix keys to use.
2326 * @param int $depth Current depth of recursion.
2327 *
2328 * @return array
2329 * @internal param array|object $list List of items
2330 * @internal param string $children_key Key to recurse children into
2331 *
2332 * @see pods_hierarchical_select
2333 * @since 2.3.0
2334 */
2335 function pods_hierarchical_select_recurse( $items, $args, $depth = 0 ) {
2336 $data = array();
2337
2338 foreach ( $items as $k => $v ) {
2339 $object = false;
2340
2341 if ( is_object( $v ) ) {
2342 $object = true;
2343 $v = get_object_vars( $v );
2344 }
2345
2346 if ( isset( $v[ $args['index'] ] ) ) {
2347 $v[ $args['index'] ] = ( 0 < $depth ? str_repeat( $args['prefix'], $depth ) : '' ) . $v[ $args['index'] ];
2348 }
2349
2350 $children = array();
2351
2352 if ( isset( $v[ $args['children'] ] ) ) {
2353 if ( ! empty( $v[ $args['children'] ] ) ) {
2354 $children = pods_hierarchical_select_recurse( $v[ $args['children'] ], $args, ( $depth + 1 ) );
2355 }
2356
2357 unset( $v[ $args['children'] ] );
2358 }
2359
2360 if ( $object ) {
2361 $v = (object) $v;
2362 }
2363
2364 $data[ $k ] = $v;
2365
2366 if ( ! empty( $children ) ) {
2367 foreach ( $children as $ck => $cv ) {
2368 $data[ $ck ] = $cv;
2369 }
2370 }
2371 }//end foreach
2372
2373 return $data;
2374 }
2375
2376 /**
2377 * Filters a list of objects or arrays, based on a set of key => value arguments.
2378 *
2379 * @param array|object $list An array or object, with objects/arrays to filter
2380 * @param array $args An array of key => value arguments to match against each object
2381 * @param string $operator The logical operation to perform:
2382 * 'AND' means all elements from the array must match;
2383 * 'OR' means only one element needs to match;
2384 * 'NOT' means no elements may match.
2385 * The default is 'AND'.
2386 *
2387 * @see wp_list_filter
2388 * @return array
2389 * @since 2.3.0
2390 */
2391 function pods_list_filter( $list, $args = array(), $operator = 'AND' ) {
2392 if ( empty( $args ) ) {
2393 return $list;
2394 }
2395
2396 $data = $list;
2397
2398 $object = false;
2399
2400 if ( is_object( $data ) ) {
2401 $object = true;
2402 $data = get_object_vars( $data );
2403 }
2404
2405 $filtered = wp_list_filter( $data, $args, $operator );
2406
2407 if ( $object ) {
2408 $filtered = (object) $filtered;
2409 }
2410
2411 return $filtered;
2412 }
2413
2414 /**
2415 * Clean extra line breaks to prevent empty <p></p> when it eventually goes into wpautop().
2416 *
2417 * @since 2.8.0
2418 *
2419 * @param string $content The content to be cleaned up.
2420 *
2421 * @return string The content that has been cleaned up.
2422 */
2423 function pods_clean_linebreaks( $content ) {
2424 // Replace \n\n\n (or more) with \n\n.
2425 $content = preg_replace( '/(\n+[ \t]*\n+[ \t]*\n+)+/m', "\n\n", $content );
2426
2427 // Replace extra whitespace at the end of lines.
2428 $content = preg_replace( '/([ \t]+\n)/m', "\n", $content );
2429
2430 if ( ! $content || ! is_string( $content ) ) {
2431 return '';
2432 }
2433
2434 return $content;
2435 }
2436
2437 add_filter( 'pods_template_content', 'pods_clean_linebreaks' );
2438
2439 /**
2440 * Convert the value from a boolean to an integer.
2441 *
2442 * @since 2.8.2
2443 *
2444 * @param bool|mixed $value The value to convert from boolean to integer.
2445 *
2446 * @return int|mixed The value as an integer if it was boolean, or the value as it was passed in.
2447 */
2448 function pods_bool_to_int( $value ) {
2449 if ( ! is_bool( $value ) ) {
2450 return $value;
2451 }
2452
2453 return (int) $value;
2454 }
2455
2456 /**
2457 * Make replacements to a string using key=>value pairs.
2458 *
2459 * @since 2.8.11
2460 *
2461 * @param string|array|mixed $value The value to do replacements on.
2462 * @param array $replacements The key=>value replacements to make.
2463 *
2464 * @return string|array|mixed The value with the replacements made.
2465 */
2466 function pods_replace_keys_to_values( $value, $replacements ) {
2467 if ( is_array( $value ) ) {
2468 return array_map( 'pods_replace_keys_to_values', $value );
2469 }
2470
2471 if ( ! is_string( $value ) ) {
2472 return $value;
2473 }
2474
2475 $replacements_prepared = array_map(
2476 static function( $replacement ) {
2477 return preg_quote( $replacement, '/' );
2478 },
2479 array_keys( $replacements )
2480 );
2481
2482 $replacements_prepared = implode( '|', $replacements_prepared );
2483
2484 $pattern = '/(?<!\\\\)(' . $replacements_prepared . ')/';
2485
2486 return preg_replace_callback(
2487 $pattern,
2488 static function( $data ) use ( $replacements ) {
2489 return $replacements[ $data[0] ];
2490 },
2491 $value
2492 );
2493 }
2494
2495 /**
2496 * Validate that a file path is safe and within the expected path(s).
2497 *
2498 * @since 2.8.18
2499 *
2500 * @param string $path The file path.
2501 * @param null|array|string $paths_to_check The list of path types to check, defaults to just checking 'pods'.
2502 * Available: 'pods', 'plugins', 'content', 'theme', 'abspath',
2503 * or 'all' to check all supported paths.
2504 *
2505 * @return false|string False if the path was not allowed or did not exist, otherwise it returns the normalized path.
2506 */
2507 function pods_validate_safe_path( $path, $paths_to_check = null ) {
2508 static $available_checks;
2509
2510 if ( null === $paths_to_check ) {
2511 $paths_to_check = [
2512 'pods',
2513 ];
2514 }
2515
2516 if ( ! $available_checks ) {
2517 $available_checks = [
2518 'pods' => realpath( PODS_DIR ),
2519 'plugins' => [
2520 realpath( WP_PLUGIN_DIR ),
2521 realpath( WPMU_PLUGIN_DIR ),
2522 ],
2523 'content' => realpath( WP_CONTENT_DIR ),
2524 'theme' => [
2525 realpath( get_stylesheet_directory() ),
2526 realpath( get_template_directory() ),
2527 ],
2528 'abspath' => realpath( ABSPATH ),
2529 ];
2530
2531 $available_checks['plugins'] = array_unique( array_filter( $available_checks['plugins'] ) );
2532 $available_checks['theme'] = array_unique( array_filter( $available_checks['theme'] ) );
2533 $available_checks = array_filter( $available_checks );
2534 }
2535
2536 if ( 'all' === $paths_to_check ) {
2537 $paths_to_check = array_keys( $available_checks );
2538 }
2539
2540 if ( empty( $paths_to_check ) ) {
2541 return false;
2542 }
2543
2544 $path = trim( str_replace( '\\', '/', (string) $path ) );
2545 $path = str_replace( '/', DIRECTORY_SEPARATOR, $path );
2546
2547 $match_count = 1;
2548
2549 // Replace the ../ usage as many times as it may need to be replaced.
2550 while ( $match_count ) {
2551 $path = str_replace( '..' . DIRECTORY_SEPARATOR, '', $path, $match_count );
2552 }
2553
2554 $real_path = realpath( $path );
2555
2556 $path_match = false;
2557
2558 foreach ( (array) $paths_to_check as $check_type ) {
2559 if ( ! isset( $available_checks[ $check_type ] ) ) {
2560 continue;
2561 }
2562
2563 $check_type_paths = (array) $available_checks[ $check_type ];
2564
2565 $is_theme = 'theme' === $check_type;
2566
2567 foreach ( $check_type_paths as $path_to_check ) {
2568 /*
2569 * Separator-anchored prefix so a sibling directory whose name merely
2570 * starts with the allowed path (e.g. ".../plugins/pods-evil" vs the
2571 * "pods" root ".../plugins/pods") cannot satisfy the check.
2572 */
2573 $path_to_check_prefix = rtrim( $path_to_check, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR;
2574
2575 if (
2576 $real_path
2577 && ( $real_path === $path_to_check || 0 === strpos( $real_path, $path_to_check_prefix ) )
2578 && file_exists( $real_path )
2579 ) {
2580 // Check the path starts with the one we are checking for and that the file exists.
2581 $path_match = true;
2582
2583 $path = $real_path;
2584
2585 break;
2586 } elseif ( $is_theme ) {
2587 // Check the theme directories.
2588 $path_localized_for_theme = trim( $path, DIRECTORY_SEPARATOR );
2589
2590 // Resolve the candidate with realpath() and confirm it still lives inside the theme directory before accepting it, to help prevent security issues.
2591 $theme_real_path = (string) realpath( $path_to_check . DIRECTORY_SEPARATOR . $path_localized_for_theme );
2592
2593 if (
2594 $theme_real_path
2595 && 0 === strpos( $theme_real_path, $path_to_check_prefix )
2596 && file_exists( $theme_real_path )
2597 ) {
2598 $path_match = true;
2599
2600 $path = $theme_real_path;
2601
2602 break;
2603 }
2604 }
2605 }
2606 }
2607
2608 if ( ! $path_match ) {
2609 return false;
2610 }
2611
2612 return $path;
2613 }
2614
2615 /**
2616 * Maybe sleep and help avoid hitting memory limit.
2617 *
2618 * @since 2.8.18
2619 *
2620 * @param int $sleep_time The amount of seconds to sleep (if sleep is needed).
2621 * @param int $after The number of triggers needed to run the logic.
2622 */
2623 function pods_maybe_clean_memory( $sleep_time = 0, $after = 100 ) {
2624 static $counter = 0;
2625
2626 $counter++;
2627
2628 if ( $after === $counter ) {
2629 $counter = 0;
2630
2631 pods_clean_memory( $sleep_time );
2632 }
2633 }
2634
2635 /**
2636 * Sleep and help avoid hitting memory limit.
2637 *
2638 * @since 2.8.18
2639 *
2640 * @param int $sleep_time The amount of seconds to sleep (if sleep is needed).
2641 */
2642 function pods_clean_memory( $sleep_time = 0 ) {
2643 if ( 0 < $sleep_time ) {
2644 sleep( $sleep_time );
2645 }
2646
2647 global $wpdb, $wp_object_cache;
2648
2649 $wpdb->queries = [];
2650
2651 if ( ! is_object( $wp_object_cache ) ) {
2652 return;
2653 }
2654
2655 $wp_object_cache->group_ops = [];
2656 $wp_object_cache->stats = [];
2657 $wp_object_cache->memcache_debug = [];
2658 $wp_object_cache->cache = [];
2659
2660 if ( is_callable( $wp_object_cache, '__remoteset' ) ) {
2661 call_user_func( [ $wp_object_cache, '__remoteset' ] ); // important
2662 }
2663 }
2664
2665 /**
2666 * Enforce a URL as safe and fallback to another URL if it is not safe.
2667 *
2668 * @since 2.8.23.3
2669 *
2670 * @param string $url The URL to enforce as safe.
2671 * @param string|null $fallback_url The fallback URL to use if the URL is not valid.
2672 *
2673 * @return string The safe URL or the fallback URL if that was not valid.
2674 */
2675 function pods_enforce_safe_url( $url, $fallback_url = null ) {
2676 $url = wp_sanitize_redirect( $url );
2677
2678 if ( null === $fallback_url ) {
2679 $fallback_url = pods_current_url();
2680 }
2681
2682 return wp_validate_redirect( $url, $fallback_url );
2683 }
2684
2685