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.

classes/PodsForm.php (54 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
/**
4
 * @package Pods
5
 */
6
class PodsForm {
0 ignored issues
show
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
7
8
	/**
9
	 * @var PodsForm
10
	 */
11
	protected static $instance = null;
12
13
	/**
14
	 * @var string
15
	 */
16
	public static $field = null;
17
18
	/**
19
	 * @var string
20
	 */
21
	public static $field_group = null;
22
23
	/**
24
	 * @var string
25
	 */
26
	public static $field_type = null;
27
28
	/**
29
	 * @var array
30
	 */
31
	public static $field_types = array();
32
33
	/**
34
	 * @var array
35
	 */
36
	public static $loaded = array();
37
38
	/**
39
	 * @var int
40
	 */
41
	public static $form_counter = 0;
42
43
	/**
44
	 * Singleton handling for a basic pods_form() request
45
	 *
46
	 * @return \PodsForm
47
	 *
48
	 * @since 2.3.5
49
	 */
50
	public static function init() {
51
52
		if ( ! is_object( self::$instance ) ) {
53
			self::$instance = new self();
54
		}
55
56
		return self::$instance;
57
	}
58
59
	/**
60
	 * Master handler for all field / form methods
61
	 *
62
	 * @return \PodsForm
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
63
	 *
64
	 * @license http://www.gnu.org/licenses/gpl-2.0.html
65
	 * @since   2.0
66
	 */
67
	private function __construct() {
68
69
		add_action( 'admin_init', array( $this, 'admin_init' ), 14 );
70
	}
71
72
	/**
73
	 * Prevent clones
74
	 *
75
	 * @since 2.3
76
	 */
77
	private function __clone() {
78
		// Hulk smash
79
	}
80
81
	/**
82
	 * Output a field's label
83
	 *
84
	 * @since 2.0
85
	 */
86
87
	/**
88
	 * Output a field's label
89
	 *
90
	 * @param string $name    Field name
91
	 * @param string $label   Label text
92
	 * @param string $help    Help text
93
	 * @param array  $options Field options
0 ignored issues
show
Should the type for parameter $options 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...
94
	 *
95
	 * @return string Label HTML
96
	 *
97
	 * @since 2.0
98
	 */
99
	public static function label( $name, $label, $help = '', $options = null ) {
100
101
		if ( is_array( $label ) || is_object( $label ) ) {
102
			$options = $label;
103
			$label   = $options['label'];
104
105
			if ( empty( $label ) ) {
106
				$label = ucwords( str_replace( '_', ' ', $name ) );
107
			}
108
109
			$help = $options['help'];
110
		} else {
111
			$options = self::options( null, $options );
112
		}
113
114
		$label = apply_filters( 'pods_form_ui_label_text', $label, $name, $help, $options );
115
		$help  = apply_filters( 'pods_form_ui_label_help', $help, $name, $label, $options );
116
117
		ob_start();
118
119
		$name_clean      = self::clean( $name );
120
		$name_more_clean = self::clean( $name, true );
121
122
		$type                = 'label';
123
		$attributes          = array();
124
		$attributes['class'] = 'pods-form-ui-' . $type . ' pods-form-ui-' . $type . '-' . $name_more_clean;
125
		$attributes['for']   = ( false === strpos( $name_clean, 'pods-form-ui-' ) ? 'pods-form-ui-' : '' ) . $name_clean;
126
		$attributes          = self::merge_attributes( $attributes, $name, $type, $options, false );
127
128
		pods_view( PODS_DIR . 'ui/fields/_label.php', compact( array_keys( get_defined_vars() ) ) );
129
130
		$output = ob_get_clean();
131
132
		return apply_filters( 'pods_form_ui_' . $type, $output, $name, $label, $help, $attributes, $options );
133
	}
134
135
	/**
136
	 * Output a Field Comment Paragraph
137
	 *
138
	 * @param string $name    Field name
139
	 * @param string $message Field comments
0 ignored issues
show
Should the type for parameter $message 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...
140
	 * @param array  $options Field options
0 ignored issues
show
Should the type for parameter $options 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...
141
	 *
142
	 * @return string Comment HTML
143
	 *
144
	 * @since 2.0
145
	 */
146
	public static function comment( $name, $message = null, $options = null ) {
147
148
		$options = self::options( null, $options );
149
150
		$name_more_clean = self::clean( $name, true );
151
152
		if ( ! empty( $options['description'] ) ) {
153
			$message = $options['description'];
154
		} elseif ( empty( $message ) ) {
155
			return '';
156
		}
157
158
		$message = apply_filters( 'pods_form_ui_comment_text', $message, $name, $options );
159
160
		ob_start();
161
162
		$type                = 'comment';
163
		$attributes          = array();
164
		$attributes['class'] = 'description pods-form-ui-' . $type . ' pods-form-ui-' . $type . '-' . $name_more_clean;
165
		$attributes          = self::merge_attributes( $attributes, $name, $type, $options, false );
166
167
		pods_view( PODS_DIR . 'ui/fields/_comment.php', compact( array_keys( get_defined_vars() ) ) );
168
169
		$output = ob_get_clean();
170
171
		return apply_filters( 'pods_form_ui_' . $type, $output, $name, $message, $attributes, $options );
172
	}
173
174
	/**
175
	 * Output a field
176
	 *
177
	 * @param string $name    Field name
178
	 * @param mixed  $value   Field value
179
	 * @param string $type    Field type
180
	 * @param array  $options Field options
0 ignored issues
show
Should the type for parameter $options 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...
181
	 * @param array  $pod     Pod data
0 ignored issues
show
Should the type for parameter $pod 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...
182
	 * @param int    $id      Item ID
0 ignored issues
show
Should the type for parameter $id not be integer|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...
183
	 *
184
	 * @return string Field HTML
185
	 *
186
	 * @since 2.0
187
	 */
188
	public static function field( $name, $value, $type = 'text', $options = null, $pod = null, $id = null ) {
189
190
		// Take a field array
191
		if ( is_array( $name ) || is_object( $name ) ) {
192
			$options = $name;
193
194
			if ( is_object( $type ) ) {
195
				$pod = $type;
196
				$id  = $options;
197
			}
198
199
			$name = pods_v( 'name', $options );
200
			$type = pods_v( 'type', $options );
201
		}
202
203
		$options = self::options( $type, $options );
204
		$options = apply_filters( 'pods_form_ui_field_' . $type . '_options', $options, $value, $name, $pod, $id );
205
206
		if ( null === $value || ( '' === $value && 'boolean' === $type ) || ( ! empty( $pod ) && empty( $id ) ) ) {
207
			$value = self::default_value( $value, $type, $name, $options, $pod, $id );
208
		}
209
210
		// Fix double help qtip when using single checkboxes (boolean type)
211
		if ( 'boolean' === $type ) {
212
			$options['help'] = '';
213
		}
214
215
		if ( false === self::permission( $type, $name, $options, null, $pod, $id ) ) {
216
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by PodsForm::field of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
217
		}
218
219
		$value           = apply_filters( 'pods_form_ui_field_' . $type . '_value', $value, $name, $options, $pod, $id );
220
		$form_field_type = self::$field_type;
221
222
		ob_start();
223
224
		$helper = false;
225
226
		/**
227
		 * Input helpers are deprecated and not guaranteed to work properly.
228
		 *
229
		 * They will be entirely removed in Pods 3.0.
230
		 *
231
		 * @deprecated 2.7
232
		 */
233
		if ( 0 < strlen( pods_v( 'input_helper', $options ) ) ) {
234
			$helper = pods_api()->load_helper( array( 'name' => $options['input_helper'] ) );
235
		}
236
237
		// @todo Move into DFV field method or PodsObject later
238
		if ( ( ! isset( $options['data'] ) || empty( $options['data'] ) ) && is_object( self::$loaded[ $type ] ) && method_exists( self::$loaded[ $type ], 'data' ) ) {
239
			$data = $options['data'] = self::$loaded[ $type ]->data( $name, $value, $options, $pod, $id, true );
240
		}
241
242
		/**
243
		 * pods_form_ui_field_{$type}_override filter leaves too much to be done by developer.
244
		 *
245
		 * It will be replaced in Pods 3.0 with better documentation.
246
		 *
247
		 * @deprecated 2.7
248
		 */
249
		if ( true === apply_filters( 'pods_form_ui_field_' . $type . '_override', false, $name, $value, $options, $pod, $id ) ) {
250
			/**
251
			 * pods_form_ui_field_{$type} action leaves too much to be done by developer.
252
			 *
253
			 * It will be replaced in Pods 3.0 with better documentation.
254
			 *
255
			 * @deprecated 2.7
256
			 */
257
			do_action( 'pods_form_ui_field_' . $type, $name, $value, $options, $pod, $id );
258
		} elseif ( ! empty( $helper ) && 0 < strlen( pods_v( 'code', $helper ) ) && false === strpos( $helper['code'], '$this->' ) && ( ! defined( 'PODS_DISABLE_EVAL' ) || ! PODS_DISABLE_EVAL ) ) {
259
			/**
260
			 * Input helpers are deprecated and not guaranteed to work properly.
261
			 *
262
			 * They will be entirely removed in Pods 3.0.
263
			 *
264
			 * @deprecated 2.7
265
			 */
266
			eval( '?>' . $helper['code'] );
0 ignored issues
show
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
eval is prohibited, please use Anonymous functions instead.
Loading history...
267
		} elseif ( method_exists( get_class(), 'field_' . $type ) ) {
268
			// @todo Move these custom field methods into real/faux field classes
269
			echo call_user_func( array( get_class(), 'field_' . $type ), $name, $value, $options );
270
		} elseif ( is_object( self::$loaded[ $type ] ) && method_exists( self::$loaded[ $type ], 'input' ) ) {
271
			self::$loaded[ $type ]->input( $name, $value, $options, $pod, $id );
272
		} else {
273
			/**
274
			 * pods_form_ui_field_{$type} action leaves too much to be done by developer.
275
			 *
276
			 * It will be replaced in Pods 3.0 with better documentation.
277
			 *
278
			 * @deprecated 2.7
279
			 */
280
			do_action( 'pods_form_ui_field_' . $type, $name, $value, $options, $pod, $id );
281
		}//end if
282
283
		$output = ob_get_clean();
284
285
		/**
286
		 * pods_form_ui_field_{$type} filter will remain supported.
287
		 *
288
		 * It is not intended for replacing but augmenting input markup.
289
		 */
290
		return apply_filters( 'pods_form_ui_field_' . $type, $output, $name, $value, $options, $pod, $id );
291
	}
292
293
	/**
294
	 * Output field type 'db'
295
	 *
296
	 * Used for field names and other places where only [a-z0-9_] is accepted
297
	 *
298
	 * @since 2.0
299
	 *
300
	 * @param      $name
301
	 * @param null $value
302
	 * @param null $options
303
	 *
304
	 * @return mixed|void
305
	 */
306
	protected static function field_db( $name, $value = null, $options = null ) {
307
308
		$form_field_type = self::$field_type;
309
310
		ob_start();
311
312
		pods_view( PODS_DIR . 'ui/fields/_db.php', compact( array_keys( get_defined_vars() ) ) );
313
314
		$output = ob_get_clean();
315
316
		return apply_filters( 'pods_form_ui_field_db', $output, $name, $value, $options );
317
	}
318
319
	/**
320
	 * Output a hidden field
321
	 *
322
	 * @param      $name
323
	 * @param null $value
324
	 * @param null $options
325
	 *
326
	 * @return mixed|void
327
	 */
328
	protected static function field_hidden( $name, $value = null, $options = null ) {
329
330
		$form_field_type = self::$field_type;
331
332
		ob_start();
333
334
		pods_view( PODS_DIR . 'ui/fields/_hidden.php', compact( array_keys( get_defined_vars() ) ) );
335
336
		$output = ob_get_clean();
337
338
		return apply_filters( 'pods_form_ui_field_hidden', $output, $name, $value, $options );
339
	}
340
341
	/**
342
	 * Returns a submit button, with provided text and appropriate class, copied from WP Core for use on the frontend
343
	 *
344
	 * @see   get_submit_button
345
	 *
346
	 * @param string       $text             The text of the button (defaults to 'Save Changes')
0 ignored issues
show
Should the type for parameter $text 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...
347
	 * @param string       $type             The type of button. One of: primary, secondary, delete
348
	 * @param string       $name             The HTML name of the submit button. Defaults to "submit". If no id
349
	 *                                       attribute is given in $other_attributes below, $name will be used as the
350
	 *                                       button's id.
351
	 * @param bool         $wrap             True if the output button should be wrapped in a paragraph tag,
352
	 *                                       false otherwise. Defaults to true
353
	 * @param array|string $other_attributes Other attributes that should be output with the button,
0 ignored issues
show
Should the type for parameter $other_attributes not be array|string|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...
354
	 *                                       mapping attributes to their values, such as array( 'tabindex' => '1' ).
355
	 *                                       These attributes will be output as attribute="value", such as
356
	 *                                       tabindex="1".
357
	 *                                       Defaults to no other attributes. Other attributes can also be provided as
358
	 *                                       a
359
	 *                                       string such as 'tabindex="1"', though the array format is typically
360
	 *                                       cleaner.
361
	 *
362
	 * @since 2.7
363
	 * @return string
364
	 */
365
	public static function submit_button( $text = null, $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = null ) {
366
367
		if ( function_exists( 'get_submit_button' ) ) {
368
			return get_submit_button( $text, $type, $name, $wrap, $other_attributes );
369
		}
370
371
		if ( ! is_array( $type ) ) {
372
			$type = explode( ' ', $type );
373
		}
374
375
		$button_shorthand = array(
376
			'primary',
377
			'small',
378
			'large',
379
		);
380
381
		$classes = array(
382
			'button',
383
		);
384
385
		foreach ( $type as $t ) {
386
			if ( 'secondary' === $t || 'button-secondary' === $t ) {
387
				continue;
388
			}
389
390
			$classes[] = in_array( $t, $button_shorthand ) ? 'button-' . $t : $t;
391
		}
392
393
		$class = implode( ' ', array_unique( $classes ) );
394
395
		if ( 'delete' === $type ) {
396
			$class = 'button-secondary delete';
397
		}
398
399
		$text = $text ? $text : __( 'Save Changes' );
400
401
		// Default the id attribute to $name unless an id was specifically provided in $other_attributes
402
		$id = $name;
403
404
		if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
405
			$id = $other_attributes['id'];
406
			unset( $other_attributes['id'] );
407
		}
408
409
		$attributes = '';
410
411
		if ( is_array( $other_attributes ) ) {
412
			foreach ( $other_attributes as $attribute => $value ) {
413
				$attributes .= $attribute . '="' . esc_attr( $value ) . '" ';
414
				// Trailing space is important
415
			}
416
		} elseif ( ! empty( $other_attributes ) ) {
417
			// Attributes provided as a string
418
			$attributes = $other_attributes;
419
		}
420
421
		$button  = '<input type="submit" name="' . esc_attr( $name ) . '" id="' . esc_attr( $id ) . '" class="' . esc_attr( $class );
422
		$button .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
423
424
		if ( $wrap ) {
425
			$button = '<p class="submit">' . $button . '</p>';
426
		}
427
428
		return $button;
429
430
	}
431
432
	/**
433
	 * Output a row (label, field, and comment)
434
	 *
435
	 * @param string $name    Field name
436
	 * @param mixed  $value   Field value
437
	 * @param string $type    Field type
438
	 * @param array  $options Field options
0 ignored issues
show
Should the type for parameter $options 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...
439
	 * @param array  $pod     Pod data
0 ignored issues
show
Should the type for parameter $pod 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...
440
	 * @param int    $id      Item ID
0 ignored issues
show
Should the type for parameter $id not be integer|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...
441
	 *
442
	 * @return string Row HTML
443
	 *
444
	 * @since 2.0
445
	 */
446
	public static function row( $name, $value, $type = 'text', $options = null, $pod = null, $id = null ) {
447
448
		$options = self::options( null, $options );
449
450
		ob_start();
451
452
		pods_view( PODS_DIR . 'ui/fields/_row.php', compact( array_keys( get_defined_vars() ) ) );
453
454
		$output = ob_get_clean();
455
456
		return apply_filters( 'pods_form_ui_field_row', $output, $name, $value, $options, $pod, $id );
457
	}
458
459
	/**
460
	 * Output a field's attributes
461
	 *
462
	 * @since 2.0
463
	 *
464
	 * @param      $attributes
465
	 * @param null       $name
466
	 * @param null       $type
467
	 * @param null       $options
468
	 */
469
	public static function attributes( $attributes, $name = null, $type = null, $options = null ) {
470
471
		$attributes = (array) apply_filters( 'pods_form_ui_field_' . $type . '_attributes', $attributes, $name, $options );
472
473
		foreach ( $attributes as $attribute => $value ) {
474
			if ( null === $value ) {
475
				continue;
476
			}
477
478
			echo ' ' . esc_attr( (string) $attribute ) . '="' . esc_attr( (string) $value ) . '"';
479
		}
480
	}
481
482
	/**
483
	 * Output a field's data (for use with jQuery)
484
	 *
485
	 * @since 2.0
486
	 *
487
	 * @param      $data
488
	 * @param null $name
489
	 * @param null $type
490
	 * @param null $options
491
	 */
492
	public static function data( $data, $name = null, $type = null, $options = null ) {
493
494
		$data = (array) apply_filters( 'pods_form_ui_field_' . $type . '_data', $data, $name, $options );
495
496
		foreach ( $data as $key => $value ) {
497
			if ( null === $value ) {
498
				continue;
499
			}
500
501
			$key = sanitize_title( $key );
502
503
			if ( is_array( $value ) ) {
504
				$value = implode( ',', $value );
505
			}
506
507
			echo ' data-' . esc_attr( (string) $key ) . '="' . esc_attr( (string) $value ) . '"';
508
		}
509
	}
510
511
	/**
512
	 * Merge attributes and handle classes
513
	 *
514
	 * @since 2.0
515
	 *
516
	 * @param        $attributes
517
	 * @param null       $name
518
	 * @param null       $type
519
	 * @param null       $options
520
	 * @param string     $classes
521
	 *
522
	 * @return array
523
	 */
524
	public static function merge_attributes( $attributes, $name = null, $type = null, $options = null, $classes = '' ) {
525
526
		$options = (array) $options;
527
528
		if ( ! in_array( $type, array( 'label', 'comment' ) ) ) {
529
			$name_clean                     = self::clean( $name );
530
			$name_more_clean                = self::clean( $name, true );
531
			$_attributes                    = array();
532
			$_attributes['name']            = $name;
533
			$_attributes['data-name-clean'] = $name_more_clean;
534
535
			if ( 0 < strlen( pods_v( 'label', $options, '' ) ) ) {
536
				$_attributes['data-label'] = strip_tags( pods_v( 'label', $options ) );
537
			}
538
539
			$_attributes['id']    = 'pods-form-ui-' . $name_clean . ( self::$form_counter > 1 ? '-' . self::$form_counter : '' );
540
			$_attributes['class'] = 'pods-form-ui-field pods-form-ui-field-type-' . $type . ' pods-form-ui-field-name-' . $name_more_clean;
541
542
			if ( isset( $options['dependency'] ) && false !== $options['dependency'] ) {
543
				$_attributes['class'] .= ' pods-dependent-toggle';
544
			}
545
546
			$attributes = array_merge( $_attributes, (array) $attributes );
547
548
			if ( isset( $options['attributes'] ) && is_array( $options['attributes'] ) && ! empty( $options['attributes'] ) ) {
549
				$attributes = array_merge( $attributes, $options['attributes'] );
550
			}
551
		} elseif ( isset( $options[ $type . '_attributes' ] ) && is_array( $options[ $type . '_attributes' ] ) && ! empty( $options[ $type . '_attributes' ] ) ) {
552
			$attributes = array_merge( $attributes, $options[ $type . '_attributes' ] );
553
		}//end if
554
555
		if ( isset( $options['class'] ) && ! empty( $options['class'] ) ) {
556
			if ( is_array( $options['class'] ) ) {
557
				$options['class'] = implode( ' ', $options['class'] );
558
			}
559
560
			$options['class'] = (string) $options['class'];
561
			if ( isset( $attributes['class'] ) ) {
562
				$attributes['class'] = $attributes['class'] . ' ' . $options['class'];
563
			} else {
564
				$attributes['class'] = $options['class'];
565
			}
566
567
			$attributes['class'] = trim( $attributes['class'] );
568
		}
569
570
		if ( ! empty( $classes ) ) {
571
			if ( isset( $attributes['class'] ) ) {
572
				$attributes['class'] = $attributes['class'] . ' ' . $classes;
573
			} else {
574
				$attributes['class'] = $classes;
575
			}
576
		}
577
578
		$placeholder = trim( pods_v( 'placeholder', $options, pods_v( $type . '_placeholder', $options ) ) );
579
580
		if ( ! empty( $placeholder ) ) {
581
			$attributes['placeholder'] = $placeholder;
582
		}
583
584
		if ( 1 === (int) pods_v( 'required', $options, 0 ) ) {
585
			$attributes['class'] .= ' pods-validate pods-validate-required';
586
		}
587
588
		$max_length = (int) pods_v( 'maxlength', $options, pods_v( $type . '_max_length', $options, 0 ) );
589
590
		if ( 0 < $max_length ) {
591
			$attributes['maxlength'] = $max_length;
592
		}
593
594
		$attributes = (array) apply_filters( 'pods_form_ui_field_' . $type . '_merge_attributes', $attributes, $name, $options );
595
596
		return $attributes;
597
	}
598
599
	/**
600
	 * Setup options for a field and store them for later use
601
	 *
602
	 * @param $type
603
	 * @param $options
604
	 *
605
	 * @return array
606
	 *
607
	 * @static
608
	 *
609
	 * @since 2.0
610
	 */
611
	public static function options( $type, $options ) {
612
613
		$options = (array) $options;
614
615
		if ( ! is_object( $options ) && isset( $options['options'] ) ) {
616
			$options_temp = $options['options'];
617
618
			unset( $options['options'] );
619
620
			$options = array_merge( $options_temp, $options );
621
622
			$override = array(
623
				'class',
624
			);
625
626
			foreach ( $override as $check ) {
627
				if ( isset( $options_temp[ $check ] ) ) {
628
					$options[ $check ] = $options_temp[ $check ];
629
				}
630
			}
631
		}
632
633
		$defaults = self::options_setup( $type, $options );
634
635
		$core_defaults = array(
636
			'id'          => 0,
637
			'label'       => '',
638
			'description' => '',
639
			'help'        => '',
640
			'default'     => null,
641
			'attributes'  => array(),
642
			'class'       => '',
643
			'grouped'     => 0,
644
		);
645
646
		$defaults = array_merge( $core_defaults, $defaults );
647
648
		foreach ( $defaults as $option => $settings ) {
649
			$default = $settings;
650
651
			if ( is_array( $settings ) && isset( $settings['default'] ) ) {
652
				$default = $settings['default'];
653
			}
654
655
			if ( ! isset( $options[ $option ] ) ) {
656
				$options[ $option ] = $default;
657
			}
658
		}
659
660
		return $options;
661
	}
662
663
	/**
664
	 * Get options for a field type and setup defaults
665
	 *
666
	 * @static
667
	 *
668
	 * @param      $type
669
	 *
670
	 * @param null $options
671
	 *
672
	 * @return array|null
673
	 * @since 2.0
674
	 */
675
	public static function options_setup( $type = null, $options = null ) {
676
677
		$core_defaults = array(
678
			'id'             => 0,
679
			'name'           => '',
680
			'label'          => '',
681
			'description'    => '',
682
			'help'           => '',
683
			'default'        => null,
684
			'attributes'     => array(),
685
			'class'          => '',
686
			'type'           => 'text',
687
			'group'          => 0,
688
			'grouped'        => 0,
689
			'developer_mode' => false,
690
			'dependency'     => false,
691
			'depends-on'     => array(),
692
			'excludes-on'    => array(),
693
			'options'        => array(),
694
		);
695
696
		if ( ! empty( $options ) && is_array( $options ) ) {
697
			$core_defaults = array_merge( $core_defaults, $options );
698
		}
699
700
		if ( null === $type ) {
701
			return $core_defaults;
702
		} else {
703
			self::field_loader( $type );
704
		}
705
706
		$options = apply_filters( 'pods_field_' . $type . '_options', (array) self::$loaded[ $type ]->options(), $type );
707
708
		$first_field = current( $options );
709
710
		if ( ! empty( $options ) && ! isset( $first_field['name'] ) && ! isset( $first_field['label'] ) ) {
711
			$all_options = array();
712
713
			foreach ( $options as $group => $group_options ) {
714
				$all_options = array_merge( $all_options, self::fields_setup( $group_options, $core_defaults ) );
715
			}
716
717
			$options = $all_options;
718
		} else {
719
			$options = self::fields_setup( $options, $core_defaults );
720
		}
721
722
		return $options;
723
	}
724
725
	/**
726
	 * Get Admin options for a field type and setup defaults
727
	 *
728
	 * @static
729
	 *
730
	 * @param $type
731
	 *
732
	 * @return array|null
733
	 *
734
	 * @since 2.0
735
	 */
736
	public static function ui_options( $type ) {
737
738
		$core_defaults = array(
739
			'id'             => 0,
740
			'name'           => '',
741
			'label'          => '',
742
			'description'    => '',
743
			'help'           => '',
744
			'default'        => null,
745
			'attributes'     => array(),
746
			'class'          => '',
747
			'type'           => 'text',
748
			'group'          => 0,
749
			'grouped'        => 0,
750
			'developer_mode' => false,
751
			'dependency'     => false,
752
			'depends-on'     => array(),
753
			'excludes-on'    => array(),
754
			'options'        => array(),
755
		);
756
757
		self::field_loader( $type );
758
759
		$options = apply_filters( 'pods_field_' . $type . '_ui_options', (array) self::$loaded[ $type ]->ui_options(), $type );
760
761
		$first_field = current( $options );
762
763
		if ( ! empty( $options ) && ! isset( $first_field['name'] ) && ! isset( $first_field['label'] ) ) {
764
			foreach ( $options as $group => $group_options ) {
765
				$options[ $group ] = self::fields_setup( $group_options, $core_defaults );
766
			}
767
		} else {
768
			$options = self::fields_setup( $options, $core_defaults );
769
		}
770
771
		return $options;
772
	}
773
774
	/**
775
	 * Get options for a field and setup defaults
776
	 *
777
	 * @param null $fields
778
	 * @param null $core_defaults
779
	 * @param bool $single
780
	 *
781
	 * @return array|null
782
	 *
783
	 * @static
784
	 * @since 2.0
785
	 */
786
	public static function fields_setup( $fields = null, $core_defaults = null, $single = false ) {
787
788
		if ( empty( $core_defaults ) ) {
789
			$core_defaults = array(
790
				'id'             => 0,
791
				'name'           => '',
792
				'label'          => '',
793
				'description'    => '',
794
				'help'           => '',
795
				'default'        => null,
796
				'attributes'     => array(),
797
				'class'          => '',
798
				'type'           => 'text',
799
				'group'          => 0,
800
				'grouped'        => 0,
801
				'developer_mode' => false,
802
				'dependency'     => false,
803
				'depends-on'     => array(),
804
				'excludes-on'    => array(),
805
				'options'        => array(),
806
			);
807
		}
808
809
		if ( $single ) {
810
			$fields = array( $fields );
811
		}
812
813
		foreach ( $fields as $f => $field ) {
0 ignored issues
show
The expression $fields of type array<integer,null,{"0":"null"}>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
814
			$fields[ $f ] = self::field_setup( $field, $core_defaults, pods_v( 'type', $field, 'text' ) );
815
816
			if ( ! $single && strlen( $fields[ $f ]['name'] ) < 1 ) {
817
				$fields[ $f ]['name'] = $f;
818
			}
819
		}
820
821
		if ( $single ) {
822
			$fields = $fields[0];
823
		}
824
825
		return $fields;
826
	}
827
828
	/**
829
	 * Get options for a field and setup defaults
830
	 *
831
	 * @static
832
	 *
833
	 * @param null $field
834
	 * @param null $core_defaults
835
	 * @param null $type
836
	 *
837
	 * @return array|null
838
	 *
839
	 * @since 2.0
840
	 */
841
	public static function field_setup( $field = null, $core_defaults = null, $type = null ) {
842
843
		$options = array();
844
845
		if ( empty( $core_defaults ) ) {
846
			$core_defaults = array(
847
				'id'             => 0,
848
				'name'           => '',
849
				'label'          => '',
850
				'description'    => '',
851
				'help'           => '',
852
				'default'        => null,
853
				'attributes'     => array(),
854
				'class'          => '',
855
				'type'           => 'text',
856
				'group'          => 0,
857
				'grouped'        => 0,
858
				'developer_mode' => false,
859
				'dependency'     => false,
860
				'depends-on'     => array(),
861
				'excludes-on'    => array(),
862
				'options'        => array(),
863
			);
864
865
			if ( null !== $type ) {
866
				self::field_loader( $type );
867
868
				if ( method_exists( self::$loaded[ $type ], 'options' ) ) {
869
					$options = apply_filters( 'pods_field_' . $type . '_options', (array) self::$loaded[ $type ]->options(), $type );
870
				}
871
			}
872
		}//end if
873
874
		if ( ! is_array( $field ) ) {
875
			$field = array( 'default' => $field );
876
		}
877
878
		if ( isset( $field['group'] ) && is_array( $field['group'] ) ) {
879
			foreach ( $field['group'] as $g => $group_option ) {
880
				$field['group'][ $g ] = array_merge( $core_defaults, $group_option );
881
882
				if ( strlen( $field['group'][ $g ]['name'] ) < 1 ) {
883
					$field['group'][ $g ]['name'] = $g;
884
				}
885
			}
886
		}
887
888
		$field = array_merge( $core_defaults, $field );
889
890
		foreach ( $options as $option => $settings ) {
891
			$v = null;
892
893
			if ( isset( $settings['default'] ) ) {
894
				$v = $settings['default'];
895
			}
896
897
			if ( ! isset( $field['options'][ $option ] ) ) {
898
				$field['options'][ $option ] = $v;
899
			}
900
		}
901
902
		return $field;
903
	}
904
905
	/**
906
	 * Setup dependency / exclusion classes
907
	 *
908
	 * @param array  $options array( 'depends-on' => ..., 'excludes-on' => ...)
909
	 * @param string $prefix
910
	 *
911
	 * @return array
0 ignored issues
show
Consider making the return type a bit more specific; maybe use array<string,string|array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
912
	 * @static
913
	 * @since 2.0
914
	 */
915
	public static function dependencies( $options, $prefix = '' ) {
916
917
		$options    = (array) $options;
918
		$classes    = $data = array();
919
		$depends_on = $excludes_on = $wildcard_on = array();
920
921
		if ( isset( $options['depends-on'] ) ) {
922
			$depends_on = (array) $options['depends-on'];
923
924
			if ( ! empty( $depends_on ) ) {
925
				$classes[] = 'pods-depends-on';
926
927
				foreach ( $depends_on as $depends => $on ) {
928
					$classes[] = 'pods-depends-on-' . $prefix . self::clean( $depends, true );
929
930
					if ( ! is_bool( $on ) ) {
931
						$on = (array) $on;
932
933
						foreach ( $on as $o ) {
934
							$classes[] = 'pods-depends-on-' . $prefix . self::clean( $depends, true ) . '-' . self::clean( $o, true );
935
						}
936
					}
937
				}
938
			}
939
		}
940
941
		if ( isset( $options['excludes-on'] ) ) {
942
			$excludes_on = (array) $options['excludes-on'];
943
944
			if ( ! empty( $excludes_on ) ) {
945
				$classes[] = 'pods-excludes-on';
946
947
				foreach ( $excludes_on as $excludes => $on ) {
948
					$classes[] = 'pods-excludes-on-' . $prefix . self::clean( $excludes, true );
949
950
					$on = (array) $on;
951
952
					foreach ( $on as $o ) {
953
						$classes[] = 'pods-excludes-on-' . $prefix . self::clean( $excludes, true ) . '-' . self::clean( $o, true );
954
					}
955
				}
956
			}
957
		}
958
959
		if ( isset( $options['wildcard-on'] ) ) {
960
			$wildcard_on = (array) $options['wildcard-on'];
961
962
			if ( ! empty( $wildcard_on ) ) {
963
				$classes[] = 'pods-wildcard-on';
964
965
				// Add the appropriate classes and data attribs per value dependency
966
				foreach ( $wildcard_on as $target => $wildcards ) {
967
					$target                             = $prefix . self::clean( $target, true );
968
					$classes[]                          = 'pods-wildcard-on-' . $target;
969
					$data[ 'pods-wildcard-' . $target ] = $wildcards;
970
				}
971
			}
972
		}
973
974
		$classes = implode( ' ', $classes );
975
976
		return array(
977
			'classes' => $classes,
978
			'data'    => $data,
979
		);
980
	}
981
982
	/**
983
	 * Change the value of the field
984
	 *
985
	 * @param        $type
986
	 * @param mixed  $value
987
	 * @param string $name
0 ignored issues
show
Should the type for parameter $name 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...
988
	 * @param array  $options
0 ignored issues
show
Should the type for parameter $options 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...
989
	 * @param array  $pod
0 ignored issues
show
Should the type for parameter $pod 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...
990
	 * @param int    $id
0 ignored issues
show
Should the type for parameter $id not be integer|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...
991
	 * @param array  $traverse
0 ignored issues
show
Should the type for parameter $traverse 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...
992
	 *
993
	 * @return array|mixed|null|object
994
	 * @internal param array $fields
995
	 * @since    2.3
996
	 */
997
	public static function value( $type, $value = null, $name = null, $options = null, $pod = null, $id = null, $traverse = null ) {
998
999
		self::field_loader( $type );
1000
1001
		if ( in_array( $type, self::repeatable_field_types() ) && 1 == pods_v( $type . '_repeatable', $options, 0 ) && ! is_array( $value ) ) {
1002
			if ( 0 < strlen( $value ) ) {
1003
				$simple = @json_decode( $value, true );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
1004
1005
				if ( is_array( $simple ) ) {
1006
					$value = $simple;
1007
				} else {
1008
					$value = (array) $value;
1009
				}
1010
			} else {
1011
				$value = array();
1012
			}
1013
		}
1014
1015
		if ( is_array( $value ) && in_array( $type, self::tableless_field_types(), true ) ) {
1016
			foreach ( $value as &$display_value ) {
1017
				$display_value = call_user_func( array(
1018
					self::$loaded[ $type ],
1019
					'value',
1020
				), $display_value, $name, $options, $pod, $id, $traverse );
1021
			}
1022
		} else {
1023
			$value = call_user_func( array(
1024
				self::$loaded[ $type ],
1025
				'value',
1026
			), $value, $name, $options, $pod, $id, $traverse );
1027
		}//end if
1028
1029
		return $value;
1030
	}
1031
1032
	/**
1033
	 * Change the way the value of the field is displayed with Pods::get
1034
	 *
1035
	 * @param        $type
1036
	 * @param mixed  $value
1037
	 * @param string $name
0 ignored issues
show
Should the type for parameter $name 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...
1038
	 * @param array  $options
0 ignored issues
show
Should the type for parameter $options 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...
1039
	 * @param array  $pod
0 ignored issues
show
Should the type for parameter $pod 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...
1040
	 * @param int    $id
0 ignored issues
show
Should the type for parameter $id not be integer|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...
1041
	 * @param array  $traverse
0 ignored issues
show
Should the type for parameter $traverse 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...
1042
	 *
1043
	 * @return array|mixed|null|void
1044
	 * @internal param array $fields
1045
	 * @since    2.0
1046
	 */
1047
	public static function display( $type, $value = null, $name = null, $options = null, $pod = null, $id = null, $traverse = null ) {
1048
1049
		self::field_loader( $type );
1050
1051
		$tableless_field_types = self::tableless_field_types();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $tableless_field_types 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...
1052
1053
		if ( method_exists( self::$loaded[ $type ], 'display_list' ) ) {
1054
			$value = call_user_func_array(
1055
				array( self::$loaded[ $type ], 'display_list' ), array(
1056
					$value,
1057
					$name,
1058
					$options,
1059
					$pod,
1060
					$id,
1061
					$traverse,
1062
				)
1063
			);
1064
		} elseif ( method_exists( self::$loaded[ $type ], 'display' ) ) {
1065
			if ( is_array( $value ) && ! in_array( $type, $tableless_field_types ) ) {
1066
				foreach ( $value as $k => $display_value ) {
1067
					$value[ $k ] = call_user_func_array(
1068
						array( self::$loaded[ $type ], 'display' ), array(
1069
							$display_value,
1070
							$name,
1071
							$options,
1072
							$pod,
1073
							$id,
1074
							$traverse,
1075
						)
1076
					);
1077
				}
1078
			} else {
1079
				$value = call_user_func_array(
1080
					array( self::$loaded[ $type ], 'display' ), array(
1081
						$value,
1082
						$name,
1083
						$options,
1084
						$pod,
1085
						$id,
1086
						$traverse,
1087
					)
1088
				);
1089
			}//end if
1090
		}//end if
1091
1092
		$value = apply_filters( 'pods_form_display_' . $type, $value, $name, $options, $pod, $id, $traverse );
1093
1094
		return $value;
1095
	}
1096
1097
	/**
1098
	 * Setup regex for JS / PHP
1099
	 *
1100
	 * @static
1101
	 *
1102
	 * @param $type
1103
	 * @param $options
1104
	 *
1105
	 * @return mixed|void
1106
	 * @since 2.0
1107
	 */
1108
	public static function regex( $type, $options ) {
1109
1110
		self::field_loader( $type );
1111
1112
		$regex = false;
1113
1114
		if ( method_exists( self::$loaded[ $type ], 'regex' ) ) {
1115
			$regex = self::$loaded[ $type ]->regex( $options );
1116
		}
1117
1118
		$regex = apply_filters( 'pods_field_' . $type . '_regex', $regex, $options, $type );
1119
1120
		return $regex;
1121
	}
1122
1123
	/**
1124
	 * Setup value preparation for sprintf
1125
	 *
1126
	 * @static
1127
	 *
1128
	 * @param $type
1129
	 * @param $options
1130
	 *
1131
	 * @return mixed|void
1132
	 * @since 2.0
1133
	 */
1134
	public static function prepare( $type, $options ) {
1135
1136
		self::field_loader( $type );
1137
1138
		$prepare = '%s';
1139
1140
		if ( method_exists( self::$loaded[ $type ], 'prepare' ) ) {
1141
			$prepare = self::$loaded[ $type ]->prepare( $options );
1142
		}
1143
1144
		$prepare = apply_filters( 'pods_field_' . $type . '_prepare', $prepare, $options, $type );
1145
1146
		return $prepare;
1147
	}
1148
1149
	/**
1150
	 * Validate a value before it's saved
1151
	 *
1152
	 * @param string       $type
1153
	 * @param mixed        $value
1154
	 * @param string       $name
0 ignored issues
show
Should the type for parameter $name 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...
1155
	 * @param array        $options
0 ignored issues
show
Should the type for parameter $options 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...
1156
	 * @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...
1157
	 * @param array        $pod
0 ignored issues
show
Should the type for parameter $pod 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...
1158
	 * @param int          $id
0 ignored issues
show
Should the type for parameter $id not be integer|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...
1159
	 * @param array|object $params
0 ignored issues
show
Should the type for parameter $params not be array|object|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...
1160
	 *
1161
	 * @static
1162
	 *
1163
	 * @since 2.0
1164
	 * @return bool|mixed|void
1165
	 */
1166
	public static function validate( $type, $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
1167
1168
		self::field_loader( $type );
1169
1170
		$validate = true;
1171
1172
		if ( 1 == pods_v( 'pre_save', $options, 1 ) && method_exists( self::$loaded[ $type ], 'validate' ) ) {
1173
			$validate = self::$loaded[ $type ]->validate( $value, $name, $options, $fields, $pod, $id, $params );
1174
		}
1175
1176
		$validate = apply_filters( 'pods_field_' . $type . '_validate', $validate, $value, $name, $options, $fields, $pod, $id, $type, $params );
1177
1178
		return $validate;
1179
	}
1180
1181
	/**
1182
	 * Change the value or perform actions after validation but before saving to the DB
1183
	 *
1184
	 * @param string $type
1185
	 * @param mixed  $value
1186
	 * @param int    $id
0 ignored issues
show
Should the type for parameter $id not be integer|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...
1187
	 * @param string $name
0 ignored issues
show
Should the type for parameter $name 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...
1188
	 * @param array  $options
0 ignored issues
show
Should the type for parameter $options 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...
1189
	 * @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...
1190
	 * @param array  $pod
0 ignored issues
show
Should the type for parameter $pod 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...
1191
	 * @param object $params
0 ignored issues
show
Should the type for parameter $params 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...
1192
	 *
1193
	 * @static
1194
	 *
1195
	 * @since 2.0
1196
	 * @return mixed
1197
	 */
1198
	public static function pre_save( $type, $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
1199
1200
		self::field_loader( $type );
1201
1202
		if ( 1 == pods_v( 'field_pre_save', $options, 1 ) && method_exists( self::$loaded[ $type ], 'pre_save' ) ) {
1203
			$value = self::$loaded[ $type ]->pre_save( $value, $id, $name, $options, $fields, $pod, $params );
1204
		}
1205
1206
		return $value;
1207
	}
1208
1209
	/**
1210
	 * Save the value to the DB
1211
	 *
1212
	 * @param string $type
1213
	 * @param mixed  $value
1214
	 * @param int    $id
0 ignored issues
show
Should the type for parameter $id not be integer|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...
1215
	 * @param string $name
0 ignored issues
show
Should the type for parameter $name 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...
1216
	 * @param array  $options
0 ignored issues
show
Should the type for parameter $options 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...
1217
	 * @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...
1218
	 * @param array  $pod
0 ignored issues
show
Should the type for parameter $pod 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...
1219
	 * @param object $params
0 ignored issues
show
Should the type for parameter $params 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...
1220
	 *
1221
	 * @static
1222
	 *
1223
	 * @since 2.3
1224
	 * @return null
1225
	 */
1226
	public static function save( $type, $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
1227
1228
		self::field_loader( $type );
1229
1230
		$saved = null;
1231
1232
		if ( 1 == pods_v( 'field_save', $options, 1 ) && method_exists( self::$loaded[ $type ], 'save' ) ) {
1233
			$saved = self::$loaded[ $type ]->save( $value, $id, $name, $options, $fields, $pod, $params );
1234
		}
1235
1236
		return $saved;
1237
	}
1238
1239
	/**
1240
	 * Delete the value from the DB
1241
	 *
1242
	 * @param string $type
1243
	 * @param int    $id
0 ignored issues
show
Should the type for parameter $id not be integer|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...
1244
	 * @param string $name
0 ignored issues
show
Should the type for parameter $name 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...
1245
	 * @param array  $options
0 ignored issues
show
Should the type for parameter $options 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...
1246
	 * @param array  $pod
0 ignored issues
show
Should the type for parameter $pod 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...
1247
	 *
1248
	 * @static
1249
	 *
1250
	 * @since 2.3
1251
	 * @return null
1252
	 */
1253
	public static function delete( $type, $id = null, $name = null, $options = null, $pod = null ) {
1254
1255
		self::field_loader( $type );
1256
1257
		$deleted = null;
1258
1259
		if ( 1 == pods_v( 'field_delete', $options, 1 ) && method_exists( self::$loaded[ $type ], 'delete' ) ) {
1260
			$deleted = self::$loaded[ $type ]->delete( $id, $name, $options, $pod );
1261
		}
1262
1263
		return $deleted;
1264
	}
1265
1266
	/**
1267
	 * Check if a user has permission to be editing a field
1268
	 *
1269
	 * @param      $type
1270
	 * @param null $name
1271
	 * @param null $options
1272
	 * @param null $fields
1273
	 * @param null $pod
1274
	 * @param null $id
1275
	 * @param null $params
1276
	 *
1277
	 * @static
1278
	 *
1279
	 * @since 2.0
1280
	 * @return bool
1281
	 */
1282
	public static function permission( $type, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
1283
1284
		$permission = pods_permission( $options );
1285
1286
		$permission = (boolean) apply_filters( 'pods_form_field_permission', $permission, $type, $name, $options, $fields, $pod, $id, $params );
1287
1288
		return $permission;
1289
	}
1290
1291
	/**
1292
	 * Parse the default the value
1293
	 *
1294
	 * @since 2.0
1295
	 *
1296
	 * @param        $value
1297
	 * @param string $type
1298
	 * @param null   $name
1299
	 * @param null   $options
1300
	 * @param null   $pod
1301
	 * @param null   $id
1302
	 *
1303
	 * @return mixed|void
1304
	 */
1305
	public static function default_value( $value, $type = 'text', $name = null, $options = null, $pod = null, $id = null ) {
1306
1307
		$default_value = pods_v( 'default_value', $options );
1308
1309
		if ( '' === $default_value || null === $default_value ) {
1310
			$default_value = $value;
1311
		}
1312
1313
		$default = pods_v( 'default', $options, $default_value, true );
1314
1315
		if ( is_string( $default ) ) {
1316
			$default_value = str_replace( array( '{@', '}' ), '', trim( $default ) );
1317
		}
1318
1319
		if ( $default != $default_value && 1 == (int) pods_v( 'default_evaluate_tags', $options, 1 ) ) {
1320
			$default = pods_evaluate_tags( $default );
1321
		}
1322
1323
		$default = pods_v( pods_v( 'default_value_parameter', $options ), 'request', $default, true );
1324
1325
		if ( $default != $value ) {
1326
			$value = $default;
1327
		}
1328
1329
		if ( is_array( $value ) ) {
1330
			$value = pods_serial_comma( $value );
1331
		}
1332
1333
		return apply_filters( 'pods_form_field_default_value', $value, $default, $type, $options, $pod, $id );
1334
	}
1335
1336
	/**
1337
	 * Clean a value for use in class / id
1338
	 *
1339
	 * @since 2.0
1340
	 *
1341
	 * @param      $input
1342
	 * @param bool  $noarray
1343
	 * @param bool  $db_field
1344
	 *
1345
	 * @return mixed|string
0 ignored issues
show
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1346
	 */
1347
	public static function clean( $input, $noarray = false, $db_field = false ) {
1348
1349
		$output = trim( (string) $input );
1350
1351
		$output = str_replace( '--1', 'podsfixtemp1', $output );
1352
		$output = str_replace( '__1', 'podsfixtemp2', $output );
1353
1354
		if ( false !== $noarray ) {
1355
			$output = preg_replace( '/\[podsfixtemp\d+\]/', '-', $output );
1356
			$output = preg_replace( '/\[\d*\]/', '-', $output );
1357
		}
1358
1359
		$output = str_replace( array( '[', ']' ), '-', $output );
1360
1361
		$output = pods_clean_name( $output );
1362
1363
		$output = preg_replace( '/([^a-z0-9\-_])/', '', $output );
1364
		$output = preg_replace( '/(_){2,}/', '_', $output );
1365
		$output = preg_replace( '/(-){2,}/', '-', $output );
1366
1367
		if ( true !== $db_field ) {
1368
			$output = str_replace( '_', '-', $output );
1369
		}
1370
1371
		$output = rtrim( $output, '-' );
1372
1373
		$output = str_replace( 'podsfixtemp1', '--1', $output );
1374
		$output = str_replace( 'podsfixtemp2', '__1', $output );
1375
1376
		return $output;
1377
	}
1378
1379
	/**
1380
	 * Run admin_init methods for each field type
1381
	 *
1382
	 * @since 2.3
1383
	 */
1384
	public function admin_init() {
1385
1386
		$admin_field_types = pods_transient_get( 'pods_form_admin_init_field_types' );
1387
1388
		if ( empty( $admin_field_types ) ) {
1389
			$admin_field_types = array();
1390
1391
			$field_types = self::field_types();
1392
1393
			foreach ( $field_types as $field_type => $field_type_data ) {
1394
				$has_admin_init = self::field_method( $field_type_data['type'], 'admin_init' );
1395
1396
				if ( false !== $has_admin_init ) {
1397
					$admin_field_types[] = $field_type;
1398
				}
1399
			}
1400
1401
			pods_transient_set( 'pods_form_admin_init_field_types', $admin_field_types );
1402
		} else {
1403
			foreach ( $admin_field_types as $field_type ) {
1404
				self::field_method( $field_type, 'admin_init' );
1405
			}
1406
		}
1407
	}
1408
1409
	/**
1410
	 * Autoload a Field Type's class
1411
	 *
1412
	 * @param string $field_type Field Type indentifier
1413
	 * @param string $file       The Field Type class file location
1414
	 *
1415
	 * @return string
1416
	 * @access public
1417
	 * @static
1418
	 * @since  2.0
1419
	 */
1420
	public static function field_loader( $field_type, $file = '' ) {
1421
1422
		if ( isset( self::$loaded[ $field_type ] ) ) {
1423
			$class_vars = get_class_vars( get_class( self::$loaded[ $field_type ] ) );
1424
			// PHP 5.2.x workaround
1425
			self::$field_group = ( isset( $class_vars['group'] ) ? $class_vars['group'] : '' );
1426
			self::$field_type  = $class_vars['type'];
1427
1428
			if ( 'Unknown' !== $class_vars['label'] ) {
1429
				return self::$loaded[ $field_type ];
1430
			}
1431
		}
1432
1433
		include_once PODS_DIR . 'classes/PodsField.php';
1434
1435
		$field_type = self::clean( $field_type, true, true );
1436
1437
		$class_name = ucfirst( $field_type );
1438
		$class_name = "PodsField_{$class_name}";
1439
1440
		$content_dir   = realpath( WP_CONTENT_DIR );
1441
		$plugins_dir   = realpath( WP_PLUGIN_DIR );
1442
		$muplugins_dir = realpath( WPMU_PLUGIN_DIR );
1443
		$abspath_dir   = realpath( ABSPATH );
1444
		$pods_dir      = realpath( PODS_DIR );
1445
1446
		if ( ! class_exists( $class_name ) ) {
1447
			if ( isset( self::$field_types[ $field_type ] ) && ! empty( self::$field_types[ $field_type ]['file'] ) ) {
1448
				$file = realpath( self::$field_types[ $field_type ]['file'] );
1449
			}
1450
1451
			if ( ! empty( $file ) && 0 === strpos( $file, $abspath_dir ) && file_exists( $file ) ) {
1452
				include_once $file;
1453
			} else {
1454
				$file = str_replace( '../', '', apply_filters( 'pods_form_field_include', PODS_DIR . 'classes/fields/' . basename( $field_type ) . '.php', $field_type ) );
1455
				$file = realpath( $file );
1456
1457
				if ( file_exists( $file ) && ( 0 === strpos( $file, $pods_dir ) || 0 === strpos( $file, $content_dir ) || 0 === strpos( $file, $plugins_dir ) || 0 === strpos( $file, $muplugins_dir ) || 0 === strpos( $file, $abspath_dir ) ) ) {
1458
					include_once $file;
1459
				}
1460
			}
1461
		}
1462
1463
		if ( class_exists( $class_name ) ) {
1464
			$class = new $class_name();
1465
		} else {
1466
			$class      = new PodsField();
1467
			$class_name = 'PodsField';
1468
		}
1469
1470
		$class_vars = get_class_vars( $class_name );
1471
		// PHP 5.2.x workaround
1472
		self::$field_group = ( isset( $class_vars['group'] ) ? $class_vars['group'] : '' );
1473
		self::$field_type  = $class_vars['type'];
1474
1475
		self::$loaded[ $field_type ] =& $class;
1476
1477
		return self::$loaded[ $field_type ];
1478
	}
1479
1480
	/**
1481
	 * Run a method from a Field Type's class
1482
	 *
1483
	 * @return mixed
1484
	 * @internal param string $field_type Field Type indentifier
1485
	 * @internal param string $method Method name
1486
	 * @internal param mixed $arg More arguments
1487
	 *
1488
	 * @access   public
1489
	 * @static
1490
	 * @since    2.0
1491
	 */
1492
	public static function field_method() {
1493
1494
		$args = func_get_args();
1495
1496
		if ( empty( $args ) && count( $args ) < 2 ) {
1497
			return false;
1498
		}
1499
1500
		$field_type = array_shift( $args );
1501
		$method     = array_shift( $args );
1502
1503
		$class = self::field_loader( $field_type );
1504
1505
		if ( method_exists( $class, $method ) ) {
1506
			return call_user_func_array( array( $class, $method ), $args );
1507
		}
1508
1509
		return false;
1510
	}
1511
1512
	/**
1513
	 * Add a new Pod field type
1514
	 *
1515
	 * @param string $type The new field type identifier
1516
	 * @param string $file The new field type class file location
0 ignored issues
show
Should the type for parameter $file 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...
1517
	 *
1518
	 * @return array Field Type data
1519
	 *
1520
	 * @since 2.3
1521
	 */
1522
	public static function register_field_type( $type, $file = null ) {
1523
1524
		$field_type = pods_transient_get( 'pods_field_type_' . $type );
1525
1526
		if ( empty( $field_type ) || $field_type['type'] != $type || $field_type['file'] != $file ) {
1527
			self::field_loader( $type, $file );
1528
1529
			$class_vars = get_class_vars( get_class( self::$loaded[ $type ] ) );
1530
			// PHP 5.2.x workaround
1531
			self::$field_types[ $type ]         = $class_vars;
1532
			self::$field_types[ $type ]['file'] = $file;
1533
1534
			pods_transient_set( 'pods_field_type_' . $type, self::$field_types[ $type ] );
1535
		} else {
1536
			self::$field_types[ $type ] = $field_type;
1537
		}
1538
1539
		return self::$field_types[ $type ];
1540
	}
1541
1542
	/**
1543
	 * Get a list of all available field types and include
1544
	 *
1545
	 * @return array Registered Field Types data
1546
	 *
1547
	 * @since 2.3
1548
	 */
1549
	public static function field_types() {
1550
1551
		$field_types = array(
1552
			'text',
1553
			'website',
1554
			// 'link',
1555
			'phone',
1556
			'email',
1557
			'password',
1558
			'paragraph',
1559
			'wysiwyg',
1560
			'code',
1561
			'datetime',
1562
			'date',
1563
			'time',
1564
			'number',
1565
			'currency',
1566
			'file',
1567
			'avatar',
1568
			'oembed',
1569
			'pick',
1570
			'boolean',
1571
			'color',
1572
			'slug',
1573
		);
1574
1575
		$field_types = array_merge( $field_types, array_keys( self::$field_types ) );
1576
1577
		$field_types = array_filter( array_unique( $field_types ) );
1578
1579
		$types = apply_filters( 'pods_api_field_types', $field_types );
1580
1581
		$field_types = pods_transient_get( 'pods_field_types' );
1582
1583
		if ( empty( $field_types ) || count( $types ) != count( $field_types ) ) {
1584
			$field_types = array();
1585
1586
			foreach ( $types as $field_type ) {
1587
				$file = null;
1588
1589
				if ( isset( self::$field_types[ $field_type ] ) ) {
1590
					$file = self::$field_types[ $field_type ]['file'];
1591
				}
1592
1593
				self::field_loader( $field_type, $file );
1594
1595
				if ( ! isset( self::$loaded[ $field_type ] ) || ! is_object( self::$loaded[ $field_type ] ) ) {
1596
					continue;
1597
				}
1598
1599
				$class_vars = get_class_vars( get_class( self::$loaded[ $field_type ] ) );
1600
				// PHP 5.2.x workaround
1601
				$field_types[ $field_type ]         = $class_vars;
1602
				$field_types[ $field_type ]['file'] = $file;
1603
			}
1604
1605
			self::$field_types = $field_types;
1606
1607
			pods_transient_set( 'pods_field_types', self::$field_types );
1608
		} else {
1609
			self::$field_types = array_merge( $field_types, self::$field_types );
1610
		}//end if
1611
1612
		return self::$field_types;
1613
	}
1614
1615
	/**
1616
	 * Get list of available tableless field types
1617
	 *
1618
	 * @return array Tableless field types
1619
	 *
1620
	 * @since 2.3
1621
	 */
1622
	public static function tableless_field_types() {
1623
1624
		static $field_types = null;
1625
1626
		if ( null === $field_types ) {
1627
			$field_types = array(
1628
				'pick',
1629
				'file',
1630
				'avatar',
1631
				'taxonomy',
1632
				'comment',
1633
			);
1634
1635
			$field_types = apply_filters( 'pods_tableless_field_types', $field_types );
1636
		}
1637
1638
		return $field_types;
1639
	}
1640
1641
	/**
1642
	 * Get list of available file field types
1643
	 *
1644
	 * @return array File field types
1645
	 *
1646
	 * @since 2.3
1647
	 */
1648
	public static function file_field_types() {
1649
1650
		static $field_types = null;
1651
1652
		if ( null === $field_types ) {
1653
			$field_types = array( 'file', 'avatar' );
1654
1655
			$field_types = apply_filters( 'pods_file_field_types', $field_types );
1656
		}
1657
1658
		return $field_types;
1659
	}
1660
1661
	/**
1662
	 * Get list of available repeatable field types
1663
	 *
1664
	 * @return array Repeatable field types
1665
	 *
1666
	 * @since 2.3
1667
	 */
1668
	public static function repeatable_field_types() {
1669
1670
		static $field_types = null;
1671
1672
		if ( null === $field_types ) {
1673
			$field_types = array(
1674
				'code',
1675
				'color',
1676
				'currency',
1677
				'date',
1678
				'datetime',
1679
				'email',
1680
				'number',
1681
				'paragraph',
1682
				'phone',
1683
				'text',
1684
				'time',
1685
				'website',
1686
				'wysiwyg',
1687
			);
1688
1689
			$field_types = apply_filters( 'pods_repeatable_field_types', $field_types );
1690
		}
1691
1692
		return $field_types;
1693
	}
1694
1695
	/**
1696
	 * Get list of available number field types
1697
	 *
1698
	 * @return array Number field types
1699
	 *
1700
	 * @since 2.3
1701
	 */
1702
	public static function number_field_types() {
1703
1704
		static $field_types = null;
1705
1706
		if ( null === $field_types ) {
1707
			$field_types = array( 'currency', 'number' );
1708
1709
			$field_types = apply_filters( 'pods_tableless_field_types', $field_types );
1710
		}
1711
1712
		return $field_types;
1713
	}
1714
1715
	/**
1716
	 * Get list of available date field types
1717
	 *
1718
	 * @return array Date field types
1719
	 *
1720
	 * @since 2.3
1721
	 */
1722
	public static function date_field_types() {
1723
1724
		static $field_types = null;
1725
1726
		if ( null === $field_types ) {
1727
			$field_types = array( 'date', 'datetime', 'time' );
1728
1729
			$field_types = apply_filters( 'pods_tableless_field_types', $field_types );
1730
		}
1731
1732
		return $field_types;
1733
	}
1734
1735
	/**
1736
	 * Get list of available text field types
1737
	 *
1738
	 * @return array Text field types
1739
	 *
1740
	 * @since 2.3
1741
	 */
1742
	public static function text_field_types() {
1743
1744
		static $field_types = null;
1745
1746
		if ( null === $field_types ) {
1747
			$field_types = array( 'code', 'paragraph', 'slug', 'password', 'text', 'wysiwyg' );
1748
1749
			$field_types = apply_filters( 'pods_text_field_types', $field_types );
1750
		}
1751
1752
		return $field_types;
1753
	}
1754
1755
	/**
1756
	 * Get list of available text field types
1757
	 *
1758
	 * @return array Text field types
1759
	 *
1760
	 * @since 2.3
1761
	 */
1762
	public static function block_field_types() {
1763
1764
		static $field_types = null;
1765
1766
		if ( null === $field_types ) {
1767
			$field_types = array( 'heading', 'html' );
1768
1769
			/**
1770
			 * Returns the available text field types
1771
			 *
1772
			 * @since unknown
1773
			 *
1774
			 * @param object $field_types Outputs the field types
1775
			 */
1776
1777
			$field_types = apply_filters( 'pods_block_field_types', $field_types );
1778
		}
1779
1780
		return $field_types;
1781
	}
1782
1783
	/**
1784
	 * Get list of available text field types
1785
	 *
1786
	 * @return array Text field types
1787
	 *
1788
	 * @since 2.3
1789
	 */
1790
	public static function simple_tableless_objects() {
1791
1792
		static $object_types = null;
1793
1794
		if ( null === $object_types ) {
1795
			$object_types = self::field_method( 'pick', 'simple_objects' );
1796
		}
1797
1798
		return $object_types;
1799
	}
1800
1801
}
1802