Issues (2873)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/data.php (36 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
19
	if ( '' === $input || is_int( $input ) || is_float( $input ) || empty( $input ) ) {
20
		return $input;
21
	}
22
23
	$output = array();
24
25
	$defaults = array(
26
		'nested' => false,
27
		'type'   => null,
28
		// %s %d %f etc
29
	);
30
31
	if ( ! is_array( $params ) ) {
32
		$defaults['type'] = $params;
33
34
		$params = $defaults;
35
	} else {
36
		$params = array_merge( $defaults, (array) $params );
37
	}
38
39
	if ( is_object( $input ) ) {
40
		$input = get_object_vars( $input );
41
42
		$n_params           = $params;
43
		$n_params['nested'] = true;
44
45
		foreach ( $input as $key => $val ) {
46
			$output[ pods_sanitize( $key ) ] = pods_sanitize( $val, $n_params );
47
		}
48
49
		$output = (object) $output;
50
	} elseif ( is_array( $input ) ) {
51
		$n_params           = $params;
52
		$n_params['nested'] = true;
53
54
		foreach ( $input as $key => $val ) {
55
			$output[ pods_sanitize( $key ) ] = pods_sanitize( $val, $n_params );
56
		}
57
	} elseif ( ! empty( $params['type'] ) && false !== strpos( $params['type'], '%' ) ) {
58
		/**
59
		 * @var $wpdb wpdb
60
		 */
61
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
62
63
		$output = $wpdb->prepare( $params['type'], $output );
64
	} elseif ( function_exists( 'wp_slash' ) ) {
65
		// @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
66
		$output = wp_slash( $input );
67
	} else {
68
		$output = esc_sql( $input );
69
	}//end if
70
71
	return $output;
72
73
}
74
75
/**
76
 * Filter input and return sanitized SQL LIKE output
77
 *
78
 * @param mixed $input The string, array, or object to sanitize
79
 *
80
 * @return array|mixed|object|string|void
81
 *
82
 * @since 2.3.9
83
 *
84
 * @see   like_escape
85
 */
86
function pods_sanitize_like( $input ) {
87
88
	if ( '' === $input || is_int( $input ) || is_float( $input ) || empty( $input ) ) {
89
		return $input;
90
	}
91
92
	$output = array();
93
94
	if ( is_object( $input ) ) {
95
		$input = get_object_vars( $input );
96
97
		foreach ( $input as $key => $val ) {
98
			$output[ $key ] = pods_sanitize_like( $val );
99
		}
100
101
		$output = (object) $output;
102
	} elseif ( is_array( $input ) ) {
103
		foreach ( $input as $key => $val ) {
104
			$output[ $key ] = pods_sanitize_like( $val );
105
		}
106
	} else {
107
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
108
		$input = pods_unslash( $input );
109
110
		$output = pods_sanitize( $wpdb->esc_like( $input ) );
111
	}
112
113
	return $output;
114
115
}
116
117
/**
118
 * Filter input and return slashed output
119
 *
120
 * @param mixed $input  The string, array, or object to sanitize
121
 * @param array $params Additional options
122
 *
123
 * @return array|mixed|object|string|void
124
 *
125
 * @since 2.3.9
126
 *
127
 * @see   wp_slash
128
 */
129
function pods_slash( $input, $params = array() ) {
130
131
	if ( '' === $input || is_int( $input ) || is_float( $input ) || empty( $input ) ) {
132
		return $input;
133
	}
134
135
	$output = array();
136
137
	$defaults = array(
138
		'type' => null,
139
		// %s %d %f etc
140
	);
141
142
	if ( ! is_array( $params ) ) {
143
		$defaults['type'] = $params;
144
145
		$params = $defaults;
146
	} else {
147
		$params = array_merge( $defaults, (array) $params );
148
	}
149
150
	if ( empty( $input ) ) {
151
		$output = $input;
152
	} elseif ( is_object( $input ) ) {
153
		$input = get_object_vars( $input );
154
155
		foreach ( $input as $key => $val ) {
156
			$output[ $key ] = pods_slash( $val, $params );
157
		}
158
159
		$output = (object) $output;
160
	} elseif ( is_array( $input ) ) {
161
		foreach ( $input as $key => $val ) {
162
			$output[ $key ] = pods_slash( $val, $params );
163
		}
164
	} elseif ( ! empty( $params['type'] ) && false !== strpos( $params['type'], '%' ) ) {
165
		/**
166
		 * @var $wpdb wpdb
167
		 */
168
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
169
170
		$output = $wpdb->prepare( $params['type'], $output );
171
	} elseif ( function_exists( 'wp_slash' ) ) {
172
		$output = wp_slash( $input );
173
	} else {
174
		$output = addslashes( $input );
175
	}//end if
176
177
	return $output;
178
179
}
180
181
/**
182
 * Filter input and return unsanitized output
183
 *
184
 * @param mixed $input  The string, array, or object to unsanitize
185
 * @param array $params Additional options
186
 *
187
 * @return array|mixed|object|string|void
188
 *
189
 * @since 1.2.0
190
 */
191
function pods_unsanitize( $input, $params = array() ) {
192
193
	if ( '' === $input || is_int( $input ) || is_float( $input ) || empty( $input ) ) {
194
		return $input;
195
	}
196
197
	$output = array();
198
199
	if ( empty( $input ) ) {
200
		$output = $input;
201
	} elseif ( is_object( $input ) ) {
202
		$input = get_object_vars( $input );
203
204
		$n_params           = (array) $params;
205
		$n_params['nested'] = true;
206
207
		foreach ( $input as $key => $val ) {
208
			$output[ pods_unsanitize( $key ) ] = pods_unsanitize( $val, $n_params );
209
		}
210
211
		$output = (object) $output;
212
	} elseif ( is_array( $input ) ) {
213
		$n_params           = (array) $params;
214
		$n_params['nested'] = true;
215
216
		foreach ( $input as $key => $val ) {
217
			$output[ pods_unsanitize( $key ) ] = pods_unsanitize( $val, $n_params );
218
		}
219
	} else {
220
		$output = wp_unslash( $input );
221
	}//end if
222
223
	return $output;
224
225
}
226
227
/**
228
 * Filter input and return unslashed output
229
 *
230
 * @param mixed $input The string, array, or object to unsanitize
231
 *
232
 * @return array|mixed|object|string|void
233
 *
234
 * @since 2.3.9
235
 *
236
 * @see   wp_unslash
237
 */
238
function pods_unslash( $input ) {
239
240
	if ( '' === $input || is_int( $input ) || is_float( $input ) || empty( $input ) ) {
241
		return $input;
242
	}
243
244
	$output = array();
245
246
	if ( empty( $input ) ) {
247
		$output = $input;
248
	} elseif ( is_object( $input ) ) {
249
		$input = get_object_vars( $input );
250
251
		foreach ( $input as $key => $val ) {
252
			$output[ $key ] = pods_unslash( $val );
253
		}
254
255
		$output = (object) $output;
256
	} elseif ( is_array( $input ) ) {
257
		foreach ( $input as $key => $val ) {
258
			$output[ $key ] = pods_unslash( $val );
259
		}
260
	} else {
261
		$output = wp_unslash( $input );
262
	}
263
264
	return $output;
265
266
}
267
268
/**
269
 * Filter input and return sanitized output
270
 *
271
 * @param mixed  $input    The string, array, or object to sanitize
272
 * @param string $charlist (optional) List of characters to be stripped from the input.
0 ignored issues
show
Should the type for parameter $charlist not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
273
 * @param string $lr       Direction of the trim, can either be 'l' or 'r'.
0 ignored issues
show
Should the type for parameter $lr not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
274
 *
275
 * @return array|object|string
276
 * @since 1.2.0
277
 */
278
function pods_trim( $input, $charlist = null, $lr = null ) {
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $lr. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
279
280
	$output = array();
281
282
	if ( is_object( $input ) ) {
283
		$input = get_object_vars( $input );
284
285
		foreach ( $input as $key => $val ) {
286
			$output[ pods_sanitize( $key ) ] = pods_trim( $val, $charlist, $lr );
287
		}
288
289
		$output = (object) $output;
290
	} elseif ( is_array( $input ) ) {
291
		foreach ( $input as $key => $val ) {
292
			$output[ pods_sanitize( $key ) ] = pods_trim( $val, $charlist, $lr );
293
		}
294
	} else {
295
		if ( 'l' === $lr ) {
296
			$output = ltrim( $input, $charlist );
297
		} elseif ( 'r' === $lr ) {
298
			$output = rtrim( $input, $charlist );
299
		} else {
300
			$output = trim( $input, $charlist );
301
		}
302
	}//end if
303
304
	return $output;
305
306
}
307
308
/**
309
 * Return a variable (if exists)
310
 *
311
 * @param mixed               $var     The variable name, can also be a modifier for specific types
312
 * @param string|array|object $type    (optional) Super globals, url/url-relative, constants, globals, options,
313
 *                                     transients, cache, user data, Pod field values, dates
314
 * @param mixed               $default (optional) The default value to set if variable doesn't exist
315
 * @param bool                $strict  (optional) Only allow values (must not be empty)
316
 * @param array               $params  (optional) Set 'casting'=>true to cast value from $default, 'allowed'=>$allowed
317
 *                                     to restrict a value to what's allowed
318
 *
319
 * @return mixed The variable (if exists), or default value
320
 * @since 2.3.10
321
 */
322
function pods_v( $var = null, $type = 'get', $default = null, $strict = false, $params = array() ) {
323
324
	$defaults = array(
325
		'casting' => false,
326
		'allowed' => null,
327
	);
328
329
	$params = (object) array_merge( $defaults, (array) $params );
330
331
	$output = null;
332
333
	if ( null === $type || '' === $type ) {
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
334
		// Invalid $type
335
	} elseif ( is_array( $type ) ) {
336
		if ( isset( $type[ $var ] ) ) {
337
			$output = $type[ $var ];
338
		}
339
	} elseif ( is_object( $type ) ) {
340
		if ( isset( $type->{$var} ) ) {
341
			$output = $type->{$var};
342
		}
343
	} else {
344
		$type = strtolower( (string) $type );
345
		switch ( $type ) {
346
			case 'get':
347
				if ( isset( $_GET[ $var ] ) ) {
348
					$output = pods_unslash( $_GET[ $var ] );
349
				}
350
				break;
351
			case 'post':
352
				if ( isset( $_POST[ $var ] ) ) {
353
					$output = pods_unslash( $_POST[ $var ] );
354
				}
355
				break;
356
			case 'request':
357
				if ( isset( $_REQUEST[ $var ] ) ) {
358
					$output = pods_unslash( $_REQUEST[ $var ] );
359
				}
360
				break;
361
			case 'url':
362
			case 'uri':
363
				$url = parse_url( pods_current_url() );
364
				$uri = trim( $url['path'], '/' );
365
				$uri = array_filter( explode( '/', $uri ) );
366
367
				if ( 'first' === $var ) {
368
					$var = 0;
369
				} elseif ( 'last' === $var ) {
370
					$var = - 1;
371
				}
372
373
				if ( is_numeric( $var ) ) {
374
					$output = ( $var < 0 ) ? pods_v( count( $uri ) + $var, $uri ) : pods_v( $var, $uri );
375
				}
376
				break;
377
			case 'url-relative':
378
				$url_raw = pods_current_url();
379
				$prefix  = get_site_url();
380
381
				if ( substr( $url_raw, 0, strlen( $prefix ) ) == $prefix ) {
382
					$url_raw = substr( $url_raw, strlen( $prefix ) + 1, strlen( $url_raw ) );
383
				}
384
385
				$url = parse_url( $url_raw );
386
				$uri = trim( $url['path'], '/' );
387
				$uri = array_filter( explode( '/', $uri ) );
388
389
				if ( 'first' === $var ) {
390
					$var = 0;
391
				} elseif ( 'last' === $var ) {
392
					$var = - 1;
393
				}
394
395
				if ( is_numeric( $var ) ) {
396
					$output = ( $var < 0 ) ? pods_v( count( $uri ) + $var, $uri ) : pods_v( $var, $uri );
397
				}
398
				break;
399
			case 'template-url':
400
				$output = get_template_directory_uri();
401
				break;
402
			case 'stylesheet-url':
403
				$output = get_stylesheet_directory_uri();
404
				break;
405
			case 'site-url':
406
				$blog_id = $scheme = null;
407
				$path    = '';
408
409
				if ( is_array( $var ) ) {
410
					if ( isset( $var[0] ) ) {
411
						$blog_id = $var[0];
412
					} elseif ( isset( $var[1] ) ) {
413
						$path = $var[1];
414
					} elseif ( isset( $var[2] ) ) {
415
						$scheme = $var[2];
416
					}
417
				} else {
418
					$blog_id = $var;
419
				}
420
421
				$output = get_site_url( $blog_id, $path, $scheme );
422
				break;
423
			case 'home-url':
424
				$blog_id = $scheme = null;
425
				$path    = '';
426
427
				if ( is_array( $var ) ) {
428
					if ( isset( $var[0] ) ) {
429
						$blog_id = $var[0];
430
					} elseif ( isset( $var[1] ) ) {
431
						$path = $var[1];
432
					} elseif ( isset( $var[2] ) ) {
433
						$scheme = $var[2];
434
					}
435
				} else {
436
					$blog_id = $var;
437
				}
438
439
				$output = get_home_url( $blog_id, $path, $scheme );
440
				break;
441
			case 'admin-url':
442
				$blog_id = $scheme = null;
443
				$path    = '';
444
445
				if ( is_array( $var ) ) {
446
					if ( isset( $var[0] ) ) {
447
						$blog_id = $var[0];
448
					} elseif ( isset( $var[1] ) ) {
449
						$path = $var[1];
450
					} elseif ( isset( $var[2] ) ) {
451
						$scheme = $var[2];
452
					}
453
				} else {
454
					$blog_id = $var;
455
				}
456
457
				$output = get_admin_url( $blog_id, $path, $scheme );
458
				break;
459
			case 'includes-url':
460
				$output = includes_url( $var );
461
				break;
462
			case 'content-url':
463
				$output = content_url( $var );
464
				break;
465
			case 'plugins-url':
466
				$path = $plugin = '';
467
468
				if ( is_array( $var ) ) {
469
					if ( isset( $var[0] ) ) {
470
						$path = $var[0];
471
					} elseif ( isset( $var[1] ) ) {
472
						$plugin = $var[1];
473
					}
474
				} else {
475
					$path = $var;
476
				}
477
478
				$output = plugins_url( $path, $plugin );
479
				break;
480
			case 'network-site-url':
481
				$path   = '';
482
				$scheme = null;
483
484
				if ( is_array( $var ) ) {
485
					if ( isset( $var[0] ) ) {
486
						$path = $var[0];
487
					} elseif ( isset( $var[1] ) ) {
488
						$scheme = $var[1];
489
					}
490
				} else {
491
					$path = $var;
492
				}
493
494
				$output = network_site_url( $path, $scheme );
495
				break;
496
			case 'network-home-url':
497
				$path   = '';
498
				$scheme = null;
499
500
				if ( is_array( $var ) ) {
501
					if ( isset( $var[0] ) ) {
502
						$path = $var[0];
503
					} elseif ( isset( $var[1] ) ) {
504
						$scheme = $var[1];
505
					}
506
				} else {
507
					$path = $var;
508
				}
509
510
				$output = network_home_url( $path, $scheme );
511
				break;
512
			case 'network-admin-url':
513
				$path   = '';
514
				$scheme = null;
515
516
				if ( is_array( $var ) ) {
517
					if ( isset( $var[0] ) ) {
518
						$path = $var[0];
519
					} elseif ( isset( $var[1] ) ) {
520
						$scheme = $var[1];
521
					}
522
				} else {
523
					$path = $var;
524
				}
525
526
				$output = network_admin_url( $path, $scheme );
527
				break;
528
			case 'user-admin-url':
529
				$path   = '';
530
				$scheme = null;
531
532
				if ( is_array( $var ) ) {
533
					if ( isset( $var[0] ) ) {
534
						$path = $var[0];
535
					} elseif ( isset( $var[1] ) ) {
536
						$scheme = $var[1];
537
					}
538
				} else {
539
					$path = $var;
540
				}
541
542
				$output = user_admin_url( $path, $scheme );
543
				break;
544
			case 'prefix':
545
				global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
546
547
				$output = $wpdb->prefix;
548
				break;
549
			case 'server':
550
				if ( ! pods_strict() ) {
551
					if ( isset( $_SERVER[ $var ] ) ) {
552
						$output = pods_unslash( $_SERVER[ $var ] );
553
					} elseif ( isset( $_SERVER[ strtoupper( $var ) ] ) ) {
554
						$output = pods_unslash( $_SERVER[ strtoupper( $var ) ] );
555
					}
556
				}
557
				break;
558
			case 'session':
559
				if ( isset( $_SESSION[ $var ] ) ) {
0 ignored issues
show
Usage of $_SESSION variable is prohibited.
Loading history...
560
					$output = $_SESSION[ $var ];
0 ignored issues
show
Usage of $_SESSION variable is prohibited.
Loading history...
561
				}
562
				break;
563
			case 'global':
564
			case 'globals':
565
				if ( isset( $GLOBALS[ $var ] ) ) {
566
					$output = $GLOBALS[ $var ];
567
				}
568
				break;
569
			case 'cookie':
570
				if ( isset( $_COOKIE[ $var ] ) ) {
571
					$output = pods_unslash( $_COOKIE[ $var ] );
572
				}
573
				break;
574
			case 'constant':
575
				if ( defined( $var ) ) {
576
					$output = constant( $var );
577
				}
578
				break;
579
			case 'user':
580
				if ( is_user_logged_in() ) {
581
					$user = get_userdata( get_current_user_id() );
582
583
					if ( isset( $user->{$var} ) ) {
584
						$value = $user->{$var};
585
					} elseif ( 'role' === $var ) {
586
						$value = '';
587
588
						if ( ! empty( $user->roles ) ) {
589
							$value = array_shift( $user->roles );
590
						}
591
					} else {
592
						$value = get_user_meta( $user->ID, $var );
0 ignored issues
show
get_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
593
					}
594
595
					if ( is_array( $value ) && ! empty( $value ) ) {
596
						$output = $value;
597
					} elseif ( ! is_array( $value ) && 0 < strlen( $value ) ) {
598
						$output = $value;
599
					}
600
				}//end if
601
				break;
602
			case 'option':
603
				$output = get_option( $var, $default );
604
				break;
605
			case 'site-option':
606
				$output = get_site_option( $var, $default );
607
				break;
608
			case 'transient':
609
				$output = get_transient( $var );
610
				break;
611
			case 'site-transient':
612
				$output = get_site_transient( $var );
613
				break;
614
			case 'cache':
615
				if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
616
					$group = 'default';
617
					$force = false;
618
619
					if ( ! is_array( $var ) ) {
620
						$var = explode( '|', $var );
621
					}
622
623
					if ( isset( $var[0] ) ) {
624
						if ( isset( $var[1] ) ) {
625
							$group = $var[1];
626
						}
627
628
						if ( isset( $var[2] ) ) {
629
							$force = $var[2];
630
						}
631
632
						$var = $var[0];
633
634
						$output = wp_cache_get( $var, $group, $force );
635
					}
636
				}//end if
637
				break;
638
			case 'pods-transient':
639
				$callback = null;
640
641
				if ( ! is_array( $var ) ) {
642
					$var = explode( '|', $var );
643
				}
644
645
				if ( isset( $var[0] ) ) {
646
					if ( isset( $var[1] ) ) {
647
						$callback = $var[1];
648
					}
649
650
					$var = $var[0];
651
652
					$output = pods_transient_get( $var, $callback );
653
				}
654
				break;
655
			case 'pods-site-transient':
656
				$callback = null;
657
658
				if ( ! is_array( $var ) ) {
659
					$var = explode( '|', $var );
660
				}
661
662
				if ( isset( $var[0] ) ) {
663
					if ( isset( $var[1] ) ) {
664
						$callback = $var[1];
665
					}
666
667
					$var = $var[0];
668
669
					$output = pods_site_transient_get( $var, $callback );
670
				}
671
				break;
672
			case 'pods-cache':
673
				if ( isset( $GLOBALS['wp_object_cache'] ) && is_object( $GLOBALS['wp_object_cache'] ) ) {
674
					$group    = 'default';
675
					$callback = null;
676
677
					if ( ! is_array( $var ) ) {
678
						$var = explode( '|', $var );
679
					}
680
681
					if ( isset( $var[0] ) ) {
682
						if ( isset( $var[1] ) ) {
683
							$group = $var[1];
684
						}
685
686
						if ( isset( $var[2] ) ) {
687
							$callback = $var[2];
688
						}
689
690
						$var = $var[0];
691
692
						$output = pods_cache_get( $var, $group, $callback );
693
					}
694
				}//end if
695
				break;
696
			case 'pods-option-cache':
697
				$group    = 'default';
698
				$callback = null;
699
700
				if ( ! is_array( $var ) ) {
701
					$var = explode( '|', $var );
702
				}
703
704
				if ( isset( $var[0] ) ) {
705
					if ( isset( $var[1] ) ) {
706
						$group = $var[1];
707
					}
708
709
					if ( isset( $var[2] ) ) {
710
						$callback = $var[2];
711
					}
712
713
					$var = $var[0];
714
715
					$output = pods_option_cache_get( $var, $group, $callback );
716
				}
717
				break;
718
			case 'date':
719
				$var = explode( '|', $var );
720
721
				if ( ! empty( $var ) ) {
722
					$output = date_i18n( $var[0], ( isset( $var[1] ) ? strtotime( $var[1] ) : false ) );
723
				}
724
				break;
725
			case 'pods':
726
			case 'pods_display':
727
				/**
728
				 * @var $pods Pods
729
				 */
730
				global $pods;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
731
732
				if ( is_object( $pods ) && 'Pods' == get_class( $pods ) ) {
733
					if ( 'pods' === $type ) {
734
						$output = $pods->field( $var );
735
736
						if ( is_array( $output ) ) {
737
							$options = array(
738
								'field'  => $var,
739
								'fields' => $pods->fields,
740
							);
741
742
							$output = pods_serial_comma( $output, $options );
743
						}
744
					} elseif ( 'pods_display' === $type ) {
745
						$output = $pods->display( $var );
746
					}
747
				}
748
				break;
749
			case 'post_id':
750
				if ( empty( $var ) ) {
751
					if ( ! empty( $default ) ) {
752
						$post_id = $default;
753
					} else {
754
						// If no $var and no $default then use current post ID
755
						$post_id = get_the_ID();
756
					}
757
				} else {
758
					$post_id = $var;
759
				}
760
				if ( did_action( 'wpml_loaded' ) ) {
761
					/* Only call filter if WPML is installed */
762
					$post_type = get_post_type( $post_id );
763
					$post_id   = apply_filters( 'wpml_object_id', $post_id, $post_type, true );
764
				} elseif ( function_exists( 'pll_get_post' ) ) {
765
					$polylang_id = pll_get_post( $post_id );
766
					if ( ! empty( $polylang_id ) ) {
767
						$post_id = $polylang_id;
768
					}
769
				}
770
				// Add other translation plugin specific code here
771
				/**
772
				 * Filter to override post_id
773
				 *
774
				 * Generally used with language translation plugins in order to return the post id of a
775
				 * translated post
776
				 *
777
				 * @param  int   $post_id The post ID of current post
778
				 * @param  mixed $default The default value to set if variable doesn't exist
779
				 * @param  mixed $var     The variable name, can also be a modifier for specific types
780
				 * @param  bool  $strict  Only allow values (must not be empty)
781
				 * @param  array $params  Set 'casting'=>true to cast value from $default, 'allowed'=>$allowed to restrict a value to what's allowed
782
				 *
783
				 * @since 2.6.6
784
				 */
785
				$output = apply_filters( 'pods_var_post_id', $post_id, $default, $var, $strict, $params );
786
				break;
787
			default:
788
				$output = apply_filters( 'pods_var_' . $type, $default, $var, $strict, $params );
789
		}//end switch
790
	}//end if
791
792
	if ( null !== $default ) {
793
		// Set default
794
		if ( null === $output ) {
795
			$output = $default;
796
		}
797
798
		// Casting
799
		if ( true === $params->casting ) {
800
			$output = pods_cast( $output, $default );
801
		}
802
	}
803
804
	// Strict defaults for empty values
805
	if ( true === $strict ) {
806
		if ( empty( $output ) ) {
807
			$output = $default;
808
		}
809
	}
810
811
	// Allowed values
812
	if ( null !== $params->allowed ) {
813
		if ( is_array( $params->allowed ) ) {
814
			// Not in array and is not the same array
815
			if ( ! in_array( $output, $params->allowed, true ) && ( ! is_array( $output ) || $output !== $params->allowed ) ) {
816
				$output = $default;
817
			}
818
		} elseif ( $output !== $params->allowed ) {
819
			// Value doesn't match
820
			$output = $default;
821
		}
822
	}
823
824
	return $output;
825
}
826
827
/**
828
 * Return a sanitized variable (if exists)
829
 *
830
 * @param mixed               $var     The variable name, can also be a modifier for specific types
831
 * @param string|array|object $type    (optional) Super globals, url/url-relative, constants, globals, options,
832
 *                                     transients, cache, user data, Pod field values, dates
833
 * @param mixed               $default (optional) The default value to set if variable doesn't exist
834
 * @param bool                $strict  (optional) Only allow values (must not be empty)
835
 * @param array               $params  (optional) Set 'casting'=>true to cast value from $default, 'allowed'=>$allowed
836
 *                                     to restrict a value to what's allowed
837
 *
838
 * @return mixed The variable (if exists), or default value
839
 * @since 2.3.10
840
 *
841
 * @see   pods_v
842
 */
843
function pods_v_sanitized( $var = null, $type = 'get', $default = null, $strict = false, $params = array() ) {
844
845
	$output = pods_v( $var, $type, $default, $strict, $params );
846
847
	$output = pods_sanitize( $output, $params );
848
849
	return $output;
850
851
}
852
853
/**
854
 * Set a variable
855
 *
856
 * @param mixed               $value The value to be set
857
 * @param mixed               $var   The variable name, or URI segment position / query var name (if $type is 'url')
858
 * @param string|array|object $type  (optional) Super globals, url/url-relative, constants, globals, user data, Pod
859
 *                                   field values
860
 *
861
 * @return mixed Updated URL (if $type is 'url'), $value (if $type is 'constant'), Item ID (if $type is 'pods'), $type,
862
 *               or false if not set
863
 * @since 2.3.10
864
 */
865
function pods_v_set( $value, $var, $type = 'get' ) {
866
867
	$ret = false;
868
869
	if ( null === $var || '' === $var ) {
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
870
		// Invalid $var
871
	} elseif ( null === $type || '' === $type ) {
0 ignored issues
show
This elseif statement is empty, and could be removed.

This check looks for the bodies of elseif statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These elseif bodies can be removed. If you have an empty elseif but statements in the else branch, consider inverting the condition.

Loading history...
872
		// Invalid $type
873
	} elseif ( is_array( $type ) ) {
874
		$type[ $var ] = $value;
875
876
		$ret = $type;
877
	} elseif ( is_object( $type ) ) {
878
		$type->{$var} = $value;
879
880
		$ret = $type;
881
	} else {
882
		$type = strtolower( $type );
883
884
		if ( 'get' === $type ) {
885
			$_GET[ $var ] = $value;
886
887
			$ret = $_GET;
888
		} elseif ( 'post' === $type ) {
889
			$_POST[ $var ] = $value;
890
891
			$ret = $_POST;
892
		} elseif ( 'request' === $type ) {
893
			$_REQUEST[ $var ] = $value;
894
895
			$ret = $_REQUEST;
896
		} elseif ( 'url' === $type ) {
897
			if ( is_numeric( $var ) && function_exists( 'http_build_url' ) ) {
898
				$url = parse_url( pods_current_url() );
899
				$uri = trim( $url['path'], '/' );
900
				$uri = array_filter( explode( '/', $uri ) );
901
902
				if ( 'first' === $var ) {
903
					$var = 0;
904
				} elseif ( 'last' === $var ) {
905
					$var = - 1;
906
				}
907
908
				if ( $var < 0 ) {
909
					$uri[ count( $uri ) + $var ] = $value;
910
				} else {
911
					$uri[ $var ] = $value;
912
				}
913
914
				$url['path'] = '/' . implode( '/', $uri ) . '/';
915
				$url['path'] = trim( $url['path'], '/' );
916
917
				$ret = http_build_url( $url );
918
			} else {
919
				$ret = add_query_arg( array( $var => $value ) );
920
			}//end if
921
		} elseif ( 'server' === $type ) {
922
			$_SERVER[ $var ] = $value;
923
924
			$ret = $_SERVER;
925
		} elseif ( in_array( $type, array( 'global', 'globals' ), true ) ) {
926
			$GLOBALS[ $var ] = $value;
0 ignored issues
show
Overridding WordPress globals is prohibited
Loading history...
927
928
			$ret = $GLOBALS;
929
		} elseif ( 'session' === $type ) {
930
			// Session start
931
			pods_session_start();
932
933
			$_SESSION[ $var ] = $value;
0 ignored issues
show
Usage of $_SESSION variable is prohibited.
Loading history...
934
935
			$ret = $_SESSION;
0 ignored issues
show
Usage of $_SESSION variable is prohibited.
Loading history...
936
		} elseif ( 'cookie' === $type && ! headers_sent() ) {
937
			setcookie( $var, $value, time() + 10 * DAY_IN_SECONDS, COOKIEPATH );
0 ignored issues
show
Due to using Batcache, server side based client related logic will not work, use JS instead.
Loading history...
938
939
			$ret = $_COOKIE;
940
		} elseif ( 'constant' === $type && ! defined( $var ) && ( is_scalar( $value ) || null === $value ) ) {
941
			define( $var, $value );
942
943
			$ret = constant( $var );
944
		} elseif ( 'user' === $type && is_user_logged_in() ) {
945
			$user = get_userdata( get_current_user_id() );
946
947
			$user_data = $user->to_array();
948
949
			if ( 'role' === $var ) {
950
				// Role
951
				$user->set_role( $value );
952
			} elseif ( isset( $user_data[ $var ] ) ) {
953
				// Core field
954
				wp_update_user(
955
					array(
956
						'ID' => $user->ID,
957
						$var => $value,
958
					)
959
				);
960
			} else {
961
				// Meta field
962
				update_user_meta( $user->ID, $var, $value );
0 ignored issues
show
update_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
963
			}
964
965
			$ret = get_userdata( $user->ID );
966
		} elseif ( 'pods' === $type ) {
967
			/**
968
			 * @var $pods Pods
969
			 */
970
			global $pods;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
971
972
			if ( is_object( $pods ) && 'Pods' == get_class( $pods ) && $pods->exists() ) {
973
				$ret = $pods->save( $var, $value );
974
			}
975
		} else {
976
			$ret = apply_filters( 'pods_var_set_' . $type, $value, $var );
977
		}//end if
978
	}//end if
979
980
	return $ret;
981
982
}
983
984
/**
985
 * Return a variable (if exists)
986
 *
987
 * @param mixed  $var     The variable name or URI segment position
988
 * @param string $type    (optional) Super globals, url/url-relative, constants, globals, options, transients, cache,
989
 *                        user data, Pod field values, dates
990
 * @param mixed  $default (optional) The default value to set if variable doesn't exist
991
 * @param mixed  $allowed (optional) The value(s) allowed
992
 * @param bool   $strict  (optional) Only allow values (must not be empty)
993
 * @param bool   $casting (optional) Whether to cast the value returned like provided in $default
994
 * @param string $context (optional) All returned values are sanitized unless this is set to 'raw'
995
 *
996
 * @return mixed The variable (if exists), or default value
997
 * @since      1.10.6
998
 *
999
 * @deprecated 2.4 Use pods_v() or pods_v_sanitized() instead.
1000
 * @see        pods_v_sanitized
1001
 */
1002
function pods_var( $var = 'last', $type = 'get', $default = null, $allowed = null, $strict = false, $casting = false, $context = 'display' ) {
1003
1004
	if ( 'raw' === $context ) {
1005
		$output = pods_v(
1006
			$var, $type, $default, $strict, array(
1007
				'allowed' => $allowed,
1008
				'casting' => $casting,
1009
			)
1010
		);
1011
	} else {
1012
		$output = pods_v_sanitized(
1013
			$var, $type, $default, $strict, array(
1014
				'allowed' => $allowed,
1015
				'casting' => $casting,
1016
			)
1017
		);
1018
	}
1019
1020
	return $output;
1021
1022
}
1023
1024
/**
1025
 * Return a variable's raw value (if exists)
1026
 *
1027
 * @param mixed  $var     The variable name or URI segment position
1028
 * @param string $type    (optional) Super globals, url/url-relative, constants, globals, options, transients, cache,
1029
 *                        user data, Pod field values, dates
1030
 * @param mixed  $default (optional) The default value to set if variable doesn't exist
1031
 * @param mixed  $allowed (optional) The value(s) allowed
1032
 * @param bool   $strict  (optional) Only allow values (must not be empty)
1033
 * @param bool   $casting (optional) Whether to cast the value returned like provided in $default
1034
 *
1035
 * @return mixed The variable (if exists), or default value
1036
 * @since      2.0
1037
 *
1038
 * @deprecated 2.4 Use pods_v() instead.
1039
 * @see        pods_v
1040
 */
1041
function pods_var_raw( $var = 'last', $type = 'get', $default = null, $allowed = null, $strict = false, $casting = false ) {
1042
1043
	return pods_v(
1044
		$var, $type, $default, $strict, array(
1045
			'allowed' => $allowed,
1046
			'casting' => $casting,
1047
		)
1048
	);
1049
1050
}
1051
1052
/**
1053
 * Set a variable
1054
 *
1055
 * @param mixed  $value The value to be set
1056
 * @param mixed  $var   The variable name or URI segment position
1057
 * @param string $type  (optional) "url", "get", "post", "request", "server", "session", "cookie", "constant", or "user"
1058
 *
1059
 * @return mixed $value (if set), $type (if $type is array or object), or $url (if $type is 'url')
1060
 * @since      1.10.6
1061
 *
1062
 * @deprecated 2.4 Use pods_v_set() instead.
1063
 * @see        pods_v_set
1064
 */
1065
function pods_var_set( $value, $var = 'last', $type = 'url' ) {
1066
1067
	return pods_v_set( $value, $var, $type );
1068
1069
}
1070
1071
/**
1072
 * Create a new URL off of the current one, with updated parameters
1073
 *
1074
 * @param array  $array    Parameters to be set (empty will remove it)
0 ignored issues
show
Should the type for parameter $array not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1075
 * @param array  $allowed  Parameters to keep (if empty, all are kept)
0 ignored issues
show
Should the type for parameter $allowed not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1076
 * @param array  $excluded Parameters to always remove
0 ignored issues
show
Should the type for parameter $excluded not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1077
 * @param string $url      URL to base update off of
0 ignored issues
show
Should the type for parameter $url not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1078
 *
1079
 * @return mixed
1080
 *
1081
 * @since 2.3.10
1082
 *
1083
 * @see   add_query_arg
1084
 */
1085
function pods_query_arg( $array = null, $allowed = null, $excluded = null, $url = null ) {
1086
1087
	$array    = (array) $array;
1088
	$allowed  = (array) $allowed;
1089
	$excluded = (array) $excluded;
1090
1091
	if ( ! isset( $_GET ) ) {
1092
		$query_args = array();
1093
	} else {
1094
		$query_args = pods_unsanitize( $_GET );
1095
	}
1096
1097
	foreach ( $query_args as $key => $val ) {
1098
		if ( is_array( $val ) && empty( $val ) ) {
1099
			$query_args[ $key ] = false;
1100
		} elseif ( ! is_array( $val ) && strlen( $val ) < 1 ) {
1101
			$query_args[ $key ] = false;
1102
		} elseif ( ! empty( $allowed ) ) {
1103
			$allow_it = false;
1104
1105
			foreach ( $allowed as $allow ) {
1106
				if ( $allow == $key ) {
1107
					$allow_it = true;
1108
				} elseif ( false !== strpos( $allow, '*' ) && 0 === strpos( $key, trim( $allow, '*' ) ) ) {
1109
					$allow_it = true;
1110
				}
1111
			}
1112
1113
			if ( ! $allow_it ) {
1114
				$query_args[ $key ] = false;
1115
			}
1116
		}
1117
	}//end foreach
1118
1119
	if ( ! empty( $excluded ) ) {
1120
		foreach ( $excluded as $exclusion ) {
1121
			if ( isset( $query_args[ $exclusion ] ) && ! in_array( $exclusion, $allowed, true ) ) {
1122
				$query_args[ $exclusion ] = false;
1123
			}
1124
		}
1125
	}
1126
1127
	if ( ! empty( $array ) ) {
1128
		foreach ( $array as $key => $val ) {
1129
			if ( null !== $val || false === strpos( $key, '*' ) ) {
1130
				if ( is_array( $val ) && ! empty( $val ) ) {
1131
					$query_args[ $key ] = $val;
1132
				} elseif ( ! is_array( $val ) && 0 < strlen( $val ) ) {
1133
					$query_args[ $key ] = $val;
1134
				} elseif ( isset( $query_args[ $key ] ) ) {
1135
					$query_args[ $key ] = false;
1136
				}
1137
			} else {
1138
				$key = str_replace( '*', '', $key );
1139
1140
				foreach ( $query_args as $k => $v ) {
1141
					if ( false !== strpos( $k, $key ) ) {
1142
						$query_args[ $k ] = false;
1143
					}
1144
				}
1145
			}
1146
		}
1147
	}//end if
1148
1149
	if ( null === $url ) {
1150
		$url = add_query_arg( $query_args );
1151
	} else {
1152
		$url = add_query_arg( $query_args, $url );
1153
	}
1154
1155
	return $url;
1156
1157
}
1158
1159
/**
1160
 * Create a new URL off of the current one, with updated parameters
1161
 *
1162
 * @param array  $array    Parameters to be set (empty will remove it)
0 ignored issues
show
Should the type for parameter $array not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1163
 * @param array  $allowed  Parameters to keep (if empty, all are kept)
0 ignored issues
show
Should the type for parameter $allowed not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1164
 * @param array  $excluded Parameters to always remove
0 ignored issues
show
Should the type for parameter $excluded not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1165
 * @param string $url      URL to base update off of
0 ignored issues
show
Should the type for parameter $url not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1166
 *
1167
 * @return mixed
1168
 *
1169
 * @since      2.0
1170
 *
1171
 * @deprecated 2.4 Use pods_query_arg() instead.
1172
 * @see        pods_query_arg
1173
 */
1174
function pods_var_update( $array = null, $allowed = null, $excluded = null, $url = null ) {
1175
1176
	return pods_query_arg( $array, $allowed, $excluded, $url );
1177
1178
}
1179
1180
/**
1181
 * Cast a value as a specific type
1182
 *
1183
 * @param mixed $value
1184
 * @param mixed $cast_from
1185
 *
1186
 * @return bool
1187
 *
1188
 * @since 2.0
1189
 */
1190
function pods_cast( $value, $cast_from = null ) {
1191
1192
	if ( null !== $cast_from ) {
1193
		if ( is_object( $value ) && is_array( $cast_from ) ) {
1194
			$value = get_object_vars( $value );
1195
		} elseif ( is_array( $value ) && is_object( $cast_from ) ) {
1196
			$value = (object) $value;
1197
		} else {
1198
			settype( $value, gettype( $cast_from ) );
1199
		}
1200
	}
1201
1202
	return $value;
1203
1204
}
1205
1206
/**
1207
 * Create a slug from an input string
1208
 *
1209
 * @param string $orig   Original string.
1210
 * @param bool   $strict Whether to only support 0-9, a-z, A-Z, and dash characters.
1211
 *
1212
 * @return string Sanitized slug
1213
 *
1214
 * @since 1.8.9
1215
 */
1216
function pods_create_slug( $orig, $strict = true ) {
1217
1218
	$str = preg_replace( '/([_ \\/])/', '-', trim( $orig ) );
1219
1220
	if ( $strict ) {
1221
		$str = preg_replace( '/([^0-9a-z\-])/', '', strtolower( $str ) );
1222
	} else {
1223
		$str = urldecode( sanitize_title( strtolower( $str ) ) );
1224
	}
1225
1226
	$str = preg_replace( '/(\-){2,}/', '-', $str );
1227
	$str = trim( $str, '-' );
1228
	$str = apply_filters( 'pods_create_slug', $str, $orig );
1229
1230
	return $str;
1231
}
1232
1233
/**
1234
 * Build a unique slug
1235
 *
1236
 * @param string       $slug        The slug value
1237
 * @param string       $column_name The column name
1238
 * @param string|array $pod         The Pod name or array of Pod data
1239
 * @param int          $pod_id      The Pod ID
1240
 * @param int          $id          The item ID
1241
 * @param object       $obj         (optional)
0 ignored issues
show
Should the type for parameter $obj not be object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1242
 *
1243
 * @param bool         $strict
1244
 *
1245
 * @return string The unique slug name
1246
 * @since 1.7.2
1247
 */
1248
function pods_unique_slug( $slug, $column_name, $pod, $pod_id = 0, $id = 0, $obj = null, $strict = true ) {
1249
1250
	$slug = pods_create_slug( $slug, $strict );
1251
1252
	$pod_data = array();
1253
1254
	if ( is_array( $pod ) ) {
1255
		$pod_data = $pod;
1256
		$pod_id   = pods_v_sanitized( 'id', $pod_data, 0 );
1257
		$pod      = pods_v_sanitized( 'name', $pod_data );
1258
	}
1259
1260
	$pod_id = absint( $pod_id );
1261
	$id     = absint( $id );
1262
1263
	if ( empty( $pod_data ) ) {
1264
		$pod_data = pods_api()->load_pod(
1265
			array(
1266
				'id'   => $pod_id,
1267
				'name' => $pod,
1268
			), false
1269
		);
1270
	}
1271
1272
	if ( empty( $pod_data ) || empty( $pod_id ) || empty( $pod ) ) {
1273
		return $slug;
1274
	}
1275
1276
	if ( 'table' !== $pod_data['storage'] || ! in_array( $pod_data['type'], array( 'pod', 'table' ), true ) ) {
1277
		return $slug;
1278
	}
1279
1280
	$check_sql = "
1281
        SELECT DISTINCT `t`.`{$column_name}` AS `slug`
1282
        FROM `@wp_pods_{$pod}` AS `t`
1283
        WHERE `t`.`{$column_name}` = %s AND `t`.`id` != %d
1284
        LIMIT 1
1285
    ";
1286
1287
	$slug_check = pods_query( array( $check_sql, $slug, $id ), $obj );
1288
1289
	if ( ! empty( $slug_check ) || apply_filters( 'pods_unique_slug_is_bad_flat_slug', false, $slug, $column_name, $pod, $pod_id, $id, $pod_data, $obj ) ) {
1290
		$suffix = 2;
1291
1292
		do {
1293
			$alt_slug = substr( $slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-{$suffix}";
1294
1295
			$slug_check = pods_query( array( $check_sql, $alt_slug, $id ), $obj );
1296
1297
			$suffix ++;
1298
		} 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 ) );
1299
1300
		$slug = $alt_slug;
1301
	}
1302
1303
	$slug = apply_filters( 'pods_unique_slug', $slug, $id, $column_name, $pod, $pod_id, $obj );
1304
1305
	return $slug;
1306
}
1307
1308
/**
1309
 * Return a lowercase alphanumeric name (use pods_js_name if you want "_" instead of "-" )
1310
 *
1311
 * @param string  $orig             Input string to clean
1312
 * @param boolean $lower            Force lowercase
1313
 * @param boolean $trim_underscores Whether to trim off underscores
1314
 *
1315
 * @return string Sanitized name
1316
 *
1317
 * @since 1.2.0
1318
 */
1319
function pods_clean_name( $orig, $lower = true, $trim_underscores = false ) {
1320
1321
	$str = trim( $orig );
1322
	$str = preg_replace( '/(\s)/', '_', $str );
1323
	$str = preg_replace( '/([^0-9a-zA-Z\-_])/', '', $str );
1324
	$str = preg_replace( '/(_){2,}/', '_', $str );
1325
	$str = preg_replace( '/(-){2,}/', '-', $str );
1326
1327
	if ( $lower ) {
1328
		$str = strtolower( $str );
1329
	}
1330
1331
	if ( $trim_underscores ) {
1332
		$str = trim( $str, '_' );
1333
	}
1334
1335
	return $str;
1336
}
1337
1338
/**
1339
 * Return a lowercase alphanumeric name (with underscores) for safe Javascript variable names
1340
 *
1341
 * @param string  $orig  Input string to clean
1342
 * @param boolean $lower Force lowercase
1343
 *
1344
 * @return string Sanitized name
1345
 *
1346
 * @since 2.5.3
1347
 */
1348
function pods_js_name( $orig, $lower = true ) {
1349
1350
	$str = pods_clean_name( $orig, $lower );
1351
	$str = str_replace( '-', '_', $str );
1352
1353
	return $str;
1354
}
1355
1356
/**
1357
 * Get the Absolute Integer of a value
1358
 *
1359
 * @param string $maybeint
1360
 * @param bool   $strict         (optional) Check if $maybeint is a integer.
1361
 * @param bool   $allow_negative (optional)
1362
 *
1363
 * @return integer
1364
 * @since 2.0
1365
 */
1366
function pods_absint( $maybeint, $strict = true, $allow_negative = false ) {
1367
1368
	if ( true === $strict && ! is_numeric( trim( $maybeint ) ) ) {
1369
		return 0;
1370
	}
1371
1372
	if ( false !== $allow_negative ) {
1373
		return intval( $maybeint );
1374
	}
1375
1376
	return absint( $maybeint );
1377
}
1378
1379
/**
1380
 * Functions like str_replace except it will restrict $occurrences
1381
 *
1382
 * @param mixed  $find
1383
 * @param mixed  $replace
1384
 * @param string $string
1385
 * @param int    $occurrences (optional)
1386
 *
1387
 * @return mixed
1388
 * @version 2.0
1389
 */
1390
function pods_str_replace( $find, $replace, $string, $occurrences = - 1 ) {
1391
1392
	if ( is_array( $string ) ) {
1393
		foreach ( $string as $k => $v ) {
1394
			$string[ $k ] = pods_str_replace( $find, $replace, $v, $occurrences );
1395
		}
1396
1397
		return $string;
1398
	} elseif ( is_object( $string ) ) {
1399
		$string = get_object_vars( $string );
1400
1401
		foreach ( $string as $k => $v ) {
1402
			$string[ $k ] = pods_str_replace( $find, $replace, $v, $occurrences );
1403
		}
1404
1405
		return (object) $string;
1406
	}
1407
1408
	if ( is_array( $find ) ) {
1409
		foreach ( $find as &$f ) {
1410
			$f = '/' . preg_quote( $f, '/' ) . '/';
1411
		}
1412
	} else {
1413
		$find = '/' . preg_quote( $find, '/' ) . '/';
1414
	}
1415
1416
	return preg_replace( $find, $replace, $string, $occurrences );
1417
}
1418
1419
/**
1420
 * Use mb_strlen if available, otherwise fallback to strlen
1421
 *
1422
 * @param string $string
1423
 *
1424
 * @return int
1425
 */
1426
function pods_mb_strlen( $string ) {
1427
1428
	if ( function_exists( 'mb_strlen' ) ) {
1429
		return mb_strlen( $string );
1430
	}
1431
1432
	return strlen( $string );
1433
1434
}
1435
1436
/**
1437
 * Use mb_substr if available, otherwise fallback to substr
1438
 *
1439
 * @param string      $string
1440
 * @param int         $start
1441
 * @param null|int    $length
1442
 * @param null|string $encoding
1443
 *
1444
 * @return string
1445
 */
1446
function pods_mb_substr( $string, $start, $length = null, $encoding = null ) {
1447
1448
	if ( function_exists( 'mb_substr' ) ) {
1449
		if ( null === $encoding ) {
1450
			$encoding = mb_internal_encoding();
1451
		}
1452
1453
		return mb_substr( $string, $start, $length, $encoding );
1454
	}
1455
1456
	return substr( $string, $start, $length );
1457
1458
}
1459
1460
/**
1461
 * Evaluate tags like magic tags but through pods_v
1462
 *
1463
 * @param string|array|object $tags     String to be evaluated
1464
 * @param bool                $sanitize Whether to sanitize tags
1465
 *
1466
 * @return string
1467
 *
1468
 * @version 2.1
1469
 *
1470
 * @see     pods_evaluate_tag
1471
 */
1472
function pods_evaluate_tags( $tags, $sanitize = false ) {
1473
1474
	if ( is_array( $tags ) ) {
1475
		foreach ( $tags as $k => $tag ) {
1476
			$tags[ $k ] = pods_evaluate_tags( $tag, $sanitize );
1477
		}
1478
1479
		return $tags;
1480
	} elseif ( is_object( $tags ) ) {
1481
		$tags = get_object_vars( $tags );
1482
1483
		foreach ( $tags as $k => $tag ) {
1484
			$tags[ $k ] = pods_evaluate_tags( $tag, $sanitize );
1485
		}
1486
1487
		$tags = (object) $tags;
1488
1489
		return $tags;
1490
	}
1491
1492
	$callback = 'pods_evaluate_tag';
1493
1494
	if ( true === $sanitize ) {
1495
		$callback = 'pods_evaluate_tag_sanitized';
1496
	}
1497
1498
	return preg_replace_callback( '/({@(.*?)})/m', $callback, (string) $tags );
1499
1500
}
1501
1502
/**
1503
 * Evaluate tag like magic tag but mapped through pods_v_sanitized
1504
 *
1505
 * @param string|array $tag
1506
 *
1507
 * @return string
1508
 *
1509
 * @version 2.1
1510
 *
1511
 * @see     pods_evaluate_tag
1512
 */
1513
function pods_evaluate_tag_sanitized( $tag ) {
1514
1515
	return pods_evaluate_tag( $tag, true );
1516
1517
}
1518
1519
/**
1520
 * Evaluate tag like magic tag but mapped through pods_v
1521
 *
1522
 * @param string|array $tag
1523
 * @param bool         $sanitize Whether to sanitize tags
1524
 *
1525
 * @return string
1526
 *
1527
 * @version 2.1
1528
 */
1529
function pods_evaluate_tag( $tag, $sanitize = false ) {
1530
1531
	global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1532
1533
	// Handle pods_evaluate_tags
1534
	if ( is_array( $tag ) ) {
1535
		if ( ! isset( $tag[2] ) && strlen( trim( $tag[2] ) ) < 1 ) {
1536
			return '';
1537
		}
1538
1539
		$tag = $tag[2];
1540
	}
1541
1542
	$tag = trim( $tag, ' {@}' );
1543
	$tag = explode( '.', $tag );
1544
1545
	if ( empty( $tag ) || ! isset( $tag[0] ) || strlen( trim( $tag[0] ) ) < 1 ) {
1546
		return '';
1547
	}
1548
1549
	// Fix formatting that may be after the first .
1550
	if ( 2 < count( $tag ) ) {
1551
		$first_tag = $tag[0];
1552
		unset( $tag[0] );
1553
1554
		$tag = array(
1555
			$first_tag,
1556
			implode( '.', $tag ),
1557
		);
1558
	}
1559
1560
	foreach ( $tag as $k => $v ) {
1561
		$tag[ $k ] = trim( $v );
1562
	}
1563
1564
	$value = '';
1565
1566
	$single_supported = array(
1567
		'template-url',
1568
		'stylesheet-url',
1569
		'site-url',
1570
		'home-url',
1571
		'admin-url',
1572
		'includes-url',
1573
		'content-url',
1574
		'plugins-url',
1575
		'network-site-url',
1576
		'network-home-url',
1577
		'network-admin-url',
1578
		'user-admin-url',
1579
		'prefix',
1580
	);
1581
1582
	if ( in_array( $tag[0], $single_supported, true ) ) {
1583
		$value = pods_v( '', $tag[0], '', true );
1584
	} elseif ( 1 == count( $tag ) ) {
1585
		$value = pods_v( $tag[0], 'get', '', true );
1586
	} elseif ( 2 == count( $tag ) ) {
1587
		$value = pods_v( $tag[1], $tag[0], '', true );
1588
	}
1589
1590
	$value = apply_filters( 'pods_evaluate_tag', $value, $tag );
1591
1592
	if ( is_array( $value ) && 1 == count( $value ) ) {
1593
		$value = current( $value );
1594
	}
1595
1596
	if ( is_array( $value ) ) {
1597
		$value = pods_serial_comma( $value );
1598
	}
1599
1600
	if ( $sanitize ) {
1601
		$value = pods_sanitize( $value );
1602
	}
1603
1604
	return $value;
1605
1606
}
1607
1608
/**
1609
 * Split an array into human readable text (Item, Item, and Item)
1610
 *
1611
 * @param array  $value
1612
 * @param string $field
0 ignored issues
show
Should the type for parameter $field not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1613
 * @param array  $fields
0 ignored issues
show
Should the type for parameter $fields not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1614
 * @param string $and
0 ignored issues
show
Should the type for parameter $and not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1615
 * @param string $field_index
0 ignored issues
show
Should the type for parameter $field_index not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1616
 *
1617
 * @return string
1618
 *
1619
 * @since 2.0
1620
 */
1621
function pods_serial_comma( $value, $field = null, $fields = null, $and = null, $field_index = null ) {
1622
1623
	if ( is_object( $value ) ) {
1624
		$value = get_object_vars( $value );
1625
	}
1626
1627
	$defaults = array(
1628
		'field'       => $field,
1629
		'fields'      => $fields,
1630
		'and'         => $and,
1631
		'field_index' => $field_index,
1632
		'separator'   => ',',
1633
		'serial'      => true,
1634
	);
1635
1636
	if ( is_array( $field ) ) {
1637
		$defaults['field'] = null;
1638
1639
		$params = array_merge( $defaults, $field );
1640
	} else {
1641
		$params = $defaults;
1642
	}
1643
1644
	$params = (object) $params;
1645
1646
	$simple = false;
1647
1648
	if ( ! empty( $params->fields ) && is_array( $params->fields ) && isset( $params->fields[ $params->field ] ) ) {
1649
		$params->field = $params->fields[ $params->field ];
1650
1651
		$simple_tableless_objects = PodsForm::simple_tableless_objects();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $simple_tableless_objects exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
1652
1653
		if ( ! empty( $params->field ) && is_array( $params->field ) && in_array( $params->field['type'], PodsForm::tableless_field_types(), true ) ) {
1654
			if ( in_array( $params->field['type'], PodsForm::file_field_types(), true ) ) {
1655
				if ( null === $params->field_index ) {
1656
					$params->field_index = 'guid';
1657
				}
1658
			} elseif ( in_array( $params->field['pick_object'], $simple_tableless_objects, true ) ) {
1659
				$simple = true;
1660
			} else {
1661
				$table = pods_api()->get_table_info( $params->field['pick_object'], $params->field['pick_val'], null, null, $params->field );
1662
1663
				if ( ! empty( $table ) ) {
1664
					if ( null === $params->field_index ) {
1665
						$params->field_index = $table['field_index'];
1666
					}
1667
				}
1668
			}
1669
		}
1670
	} else {
1671
		$params->field = null;
1672
	}//end if
1673
1674
	if ( $simple && is_array( $params->field ) && ! is_array( $value ) && '' !== $value && null !== $value ) {
1675
		$value = PodsForm::field_method( 'pick', 'simple_value', $params->field['name'], $value, $params->field );
1676
	}
1677
1678
	if ( ! is_array( $value ) ) {
1679
		return $value;
1680
	}
1681
1682
	if ( null === $params->and ) {
1683
		$params->and = ' ' . __( 'and', 'pods' ) . ' ';
1684
	}
1685
1686
	$last = '';
1687
1688
	$original_value = $value;
1689
1690
	if ( ! empty( $value ) ) {
1691
		$last = array_pop( $value );
1692
	}
1693
1694
	if ( $simple && is_array( $params->field ) && ! is_array( $last ) && '' !== $last && null !== $last ) {
1695
		$last = PodsForm::field_method( 'pick', 'simple_value', $params->field['name'], $last, $params->field );
1696
	}
1697
1698
	if ( is_array( $last ) ) {
1699
		if ( null !== $params->field_index && isset( $last[ $params->field_index ] ) ) {
1700
			$last = $last[ $params->field_index ];
1701
		} elseif ( isset( $last[0] ) ) {
1702
			$last = $last[0];
1703
		} elseif ( $simple ) {
1704
			$last = current( $last );
1705
		} else {
1706
			$last = '';
1707
		}
1708
	}
1709
1710
	if ( ! empty( $value ) ) {
1711
		if ( null !== $params->field_index && isset( $original_value[ $params->field_index ] ) ) {
1712
			return $original_value[ $params->field_index ];
1713
		} elseif ( null !== $params->field_index && isset( $value[ $params->field_index ] ) ) {
1714
			return $value[ $params->field_index ];
1715
		} elseif ( ! is_array( $value ) ) {
1716
			$value = array( $value );
1717
		}
1718
1719
		foreach ( $value as $k => $v ) {
1720
			if ( $simple && is_array( $params->field ) && ! is_array( $v ) && '' !== $v && null !== $v ) {
1721
				$v = PodsForm::field_method( 'pick', 'simple_value', $params->field['name'], $v, $params->field );
1722
			}
1723
1724
			if ( is_array( $v ) ) {
1725
				if ( null !== $params->field_index && isset( $v[ $params->field_index ] ) ) {
1726
					$v = $v[ $params->field_index ];
1727
				} elseif ( $simple ) {
1728
					$v = trim( implode( $params->separator . ' ', $v ), $params->separator . ' ' );
1729
				} else {
1730
					unset( $value[ $k ] );
1731
1732
					continue;
1733
				}
1734
			}
1735
1736
			$value[ $k ] = $v;
1737
		}
1738
1739
		if ( 1 == count( $value ) || ! $params->serial ) {
1740
			$value = trim( implode( $params->separator . ' ', $value ), $params->separator . ' ' );
1741
		} else {
1742
			$value = trim( implode( $params->separator . ' ', $value ), $params->separator . ' ' ) . apply_filters( 'pods_serial_comma', $params->separator . ' ', $value, $original_value, $params );
1743
		}
1744
1745
		$value = trim( $value );
1746
		$last  = trim( $last );
1747
1748
		if ( 0 < strlen( $value ) && 0 < strlen( $last ) ) {
1749
			$value = $value . $params->and . $last;
1750
		} elseif ( 0 < strlen( $last ) ) {
1751
			$value = $last;
1752
		} else {
1753
			$value = '';
1754
		}
1755
	} else {
1756
		$value = $last;
1757
	}//end if
1758
1759
	$value = trim( $value, $params->separator . ' ' );
1760
1761
	$value = apply_filters( 'pods_serial_comma_value', $value, $original_value, $params );
1762
1763
	return (string) $value;
1764
}
1765
1766
/**
1767
 * Return a variable if a user is logged in or anonymous, or a specific capability
1768
 *
1769
 * @param mixed        $anon       Variable to return if user is anonymous (not logged in)
1770
 * @param mixed        $user       Variable to return if user is logged in
1771
 * @param string|array $capability Capability or array of Capabilities to check to return $user on
0 ignored issues
show
Should the type for parameter $capability not be string|array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1772
 *
1773
 * @return mixed $user Variable to return if user is logged in (if logged in), otherwise $anon
1774
 *
1775
 * @since 2.0.5
1776
 */
1777
function pods_var_user( $anon = false, $user = true, $capability = null ) {
1778
1779
	$value = $anon;
1780
1781
	if ( is_user_logged_in() ) {
1782
		if ( empty( $capability ) ) {
1783
			$value = $user;
1784
		} else {
1785
			$capabilities = (array) $capability;
1786
1787
			foreach ( $capabilities as $capability ) {
1788
				if ( current_user_can( $capability ) ) {
1789
					$value = $user;
1790
1791
					break;
1792
				}
1793
			}
1794
		}
1795
	}
1796
1797
	return $value;
1798
}
1799
1800
/**
1801
 * Take a one-level list of items and make it hierarchical
1802
 *
1803
 * @param array|object $list List of items
1804
 * @param array        $args Array of parent, children, and id keys to use
1805
 *
1806
 * @return array|object
1807
 * @since 2.3
1808
 */
1809
function pods_hierarchical_list( $list, $args = array() ) {
1810
1811
	if ( empty( $args ) || ( ! is_object( $list ) && ! is_array( $list ) ) ) {
1812
		return $list;
1813
	}
1814
1815
	$defaults = array(
1816
		'id'            => 'id',
1817
		'parent'        => 'parent',
1818
		'children'      => 'children',
1819
		'orphans'       => true,
1820
		'found'         => array(),
1821
		'list'          => array(),
1822
		'current_depth' => - 1,
1823
	);
1824
1825
	$args = array_merge( $defaults, (array) $args );
1826
1827
	$list = pods_hierarchical_list_recurse( 0, $list, $args );
1828
1829
	return $list;
1830
}
1831
1832
/**
1833
 * Recurse list of items and make it hierarchical
1834
 *
1835
 * @param int          $parent Parent ID
1836
 * @param array|object $list   List of items
1837
 * @param array        $args   Array of parent, children, and id keys to use
1838
 *
1839
 * @return array|object
1840
 * @since 2.3
1841
 */
1842
function pods_hierarchical_list_recurse( $parent, $list, &$args ) {
1843
1844
	$new = array();
1845
1846
	$object = false;
1847
1848
	if ( is_object( $list ) ) {
1849
		$object = true;
1850
		$list   = get_object_vars( $list );
1851
	}
1852
1853
	$args['current_depth'] ++;
1854
1855
	$depth = $args['current_depth'];
1856
1857
	if ( 0 == $depth ) {
1858
		$args['list'] = $list;
1859
	}
1860
1861
	foreach ( $list as $k => $list_item ) {
1862
		if ( is_object( $list_item ) && isset( $list_item->{$args['id']} ) ) {
1863
			$list_item->{$args['parent']} = (int) pods_v( $args['parent'], $list_item );
1864
1865
			if ( is_array( $list_item->{$args['parent']} ) && isset( $list_item->{$args['parent']}[ $args['id'] ] ) && $parent == $list_item->{$args['parent']}[ $args['id'] ] ) {
1866
				$list_item->{$args['children']} = pods_hierarchical_list_recurse( $list_item->{$args['id']}, $list, $args );
1867
			} elseif ( $parent == $list_item->{$args['parent']} || ( 0 == $depth && $parent == $list_item->{$args['id']} ) ) {
1868
				$list_item->{$args['children']} = pods_hierarchical_list_recurse( $list_item->{$args['id']}, $list, $args );
1869
			} else {
1870
				continue;
1871
			}
1872
1873
			$args['found'][ $k ] = $list_item;
1874
		} elseif ( is_array( $list_item ) && isset( $list_item[ $args['id'] ] ) ) {
1875
			$list_item[ $args['parent'] ] = (int) pods_v( $args['parent'], $list_item );
1876
1877
			if ( is_array( $list_item[ $args['parent'] ] ) && isset( $list_item[ $args['parent'] ][ $args['id'] ] ) && $parent == $list_item[ $args['parent'] ][ $args['id'] ] ) {
1878
				$list_item[ $args['children'] ] = pods_hierarchical_list_recurse( $list_item[ $args['id'] ], $list, $args );
1879
			} elseif ( $parent == $list_item[ $args['parent'] ] || ( 0 == $depth && $parent == $list_item[ $args['id'] ] ) ) {
1880
				$list_item[ $args['children'] ] = pods_hierarchical_list_recurse( $list_item[ $args['id'] ], $list, $args );
1881
			} else {
1882
				continue;
1883
			}
1884
1885
			$args['found'][ $k ] = $list_item;
1886
		} else {
1887
			continue;
1888
		}//end if
1889
1890
		$new[ $k ] = $list_item;
1891
1892
		$args['current_depth'] = $depth;
1893
	}//end foreach
1894
1895
	if ( 0 == $depth && empty( $new ) && ! empty( $list ) ) {
1896
		$first = current( array_slice( $list, 0, 1 ) );
1897
1898
		$new_parent = 0;
1899
1900
		$args['current_depth'] = - 1;
1901
1902
		if ( is_object( $first ) && isset( $first->{$args['parent']} ) ) {
1903
			$new_parent = (int) $first->{$args['parent']};
1904
		} elseif ( is_array( $first ) && isset( $first[ $args['parent'] ] ) ) {
1905
			$new_parent = (int) $first[ $args['parent'] ];
1906
		}
1907
1908
		if ( ! empty( $new_parent ) ) {
1909
			$new = pods_hierarchical_list_recurse( $new_parent, $list, $args );
1910
		}
1911
	}
1912
1913
	if ( 0 == $depth ) {
1914
		$orphans = array();
1915
1916
		foreach ( $args['list'] as $k => $list_item ) {
1917
			if ( ! isset( $args['found'][ $k ] ) ) {
1918
				$orphans[ $k ] = $list_item;
1919
			}
1920
		}
1921
1922
		if ( ! empty( $orphans ) ) {
1923
			foreach ( $orphans as $orphan ) {
1924
				$new[] = $orphan;
1925
			}
1926
		}
1927
	}
1928
1929
	if ( $object ) {
1930
		$new = (object) $new;
1931
	}
1932
1933
	return $new;
1934
}
1935
1936
/**
1937
 * Take a one-level list of items and make it hierarchical for <select>
1938
 *
1939
 * @param array|object $list List of items
1940
 * @param array        $args Array of index, parent, children, id, and prefix keys to use
1941
 *
1942
 * @return array|object
1943
 * @internal param string $children_key Key to recurse children into
1944
 *
1945
 * @since    2.3
1946
 */
1947
function pods_hierarchical_select( $list, $args = array() ) {
1948
1949
	$object = false;
1950
1951
	if ( is_object( $list ) ) {
1952
		$object = true;
1953
		$list   = get_object_vars( $list );
1954
	}
1955
1956
	$list = pods_hierarchical_list( $list, $args );
1957
1958
	$defaults = array(
1959
		'index'    => 'name',
1960
		'children' => 'children',
1961
		'prefix'   => '&nbsp;&nbsp;&nbsp;',
1962
	);
1963
1964
	$args = array_merge( $defaults, (array) $args );
1965
1966
	$list = pods_hierarchical_select_recurse( $list, $args, 0 );
1967
1968
	if ( $object ) {
1969
		$list = (object) $list;
1970
	}
1971
1972
	return $list;
1973
}
1974
1975
/**
1976
 * Recurse list of hierarchical data
1977
 *
1978
 * @param array $items Items to recurse.
1979
 * @param array $args  Array of children and prefix keys to use.
1980
 * @param int   $depth Current depth of recursion.
1981
 *
1982
 * @return array
1983
 * @internal param array|object $list List of items
1984
 * @internal param string $children_key Key to recurse children into
1985
 *
1986
 * @see      pods_hierarchical_select
1987
 * @since    2.3
1988
 */
1989
function pods_hierarchical_select_recurse( $items, $args, $depth = 0 ) {
1990
1991
	$data = array();
1992
1993
	foreach ( $items as $k => $v ) {
1994
		$object = false;
1995
1996
		if ( is_object( $v ) ) {
1997
			$object = true;
1998
			$v      = get_object_vars( $v );
1999
		}
2000
2001
		if ( isset( $v[ $args['index'] ] ) ) {
2002
			$v[ $args['index'] ] = ( 0 < $depth ? str_repeat( $args['prefix'], $depth ) : '' ) . $v[ $args['index'] ];
2003
		}
2004
2005
		$children = array();
2006
2007
		if ( isset( $v[ $args['children'] ] ) ) {
2008
			if ( ! empty( $v[ $args['children'] ] ) ) {
2009
				$children = pods_hierarchical_select_recurse( $v[ $args['children'] ], $args, ( $depth + 1 ) );
2010
			}
2011
2012
			unset( $v[ $args['children'] ] );
2013
		}
2014
2015
		if ( $object ) {
2016
			$v = (object) $v;
2017
		}
2018
2019
		$data[ $k ] = $v;
2020
2021
		if ( ! empty( $children ) ) {
2022
			foreach ( $children as $ck => $cv ) {
2023
				$data[ $ck ] = $cv;
2024
			}
2025
		}
2026
	}//end foreach
2027
2028
	return $data;
2029
}
2030
2031
/**
2032
 * Filters a list of objects or arrays, based on a set of key => value arguments.
2033
 *
2034
 * @param array|object $list     An array or object, with objects/arrays to filter
2035
 * @param array        $args     An array of key => value arguments to match against each object
2036
 * @param string       $operator The logical operation to perform:
2037
 *                               'AND' means all elements from the array must match;
2038
 *                               'OR' means only one element needs to match;
2039
 *                               'NOT' means no elements may match.
2040
 *                               The default is 'AND'.
2041
 *
2042
 * @see   wp_list_filter
2043
 * @return array
2044
 * @since 2.3
2045
 */
2046
function pods_list_filter( $list, $args = array(), $operator = 'AND' ) {
2047
2048
	if ( empty( $args ) ) {
2049
		return $list;
2050
	}
2051
2052
	$data = $list;
2053
2054
	$object = false;
2055
2056
	if ( is_object( $data ) ) {
2057
		$object = true;
2058
		$data   = get_object_vars( $data );
2059
	}
2060
2061
	$operator = strtoupper( $operator );
2062
	$count    = count( $args );
2063
	$filtered = array();
2064
2065
	foreach ( $data as $key => $obj ) {
2066
		$to_match = $obj;
2067
2068
		if ( is_object( $to_match ) ) {
2069
			$to_match = get_object_vars( $to_match );
2070
		} elseif ( ! is_array( $to_match ) ) {
2071
			continue;
2072
		}
2073
2074
		$matched = 0;
2075
2076
		foreach ( $args as $m_key => $m_value ) {
2077
			if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] ) {
2078
				$matched ++;
2079
			}
2080
		}
2081
2082
		if ( 'AND' === $operator && $matched == $count ) {
2083
			$filtered[ $key ] = $obj;
2084
		} elseif ( 'OR' === $operator && $matched > 0 ) {
2085
			$filtered[ $key ] = $obj;
2086
		} elseif ( 'NOT' === $operator && 0 == $matched ) {
2087
			$filtered[ $key ] = $obj;
2088
		} else {
2089
			continue;
2090
		}
2091
	}//end foreach
2092
2093
	if ( $object ) {
2094
		$filtered = (object) $filtered;
2095
	}
2096
2097
	return $filtered;
2098
}
2099