PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.3.5
Pods – Custom Content Types and Fields v3.3.5
trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / classes / PodsForm.php
pods / classes Last commit date
cli 4 months ago fields 4 months ago widgets 4 months ago Pods.php 4 months ago PodsAPI.php 4 months ago PodsAdmin.php 4 months ago PodsArray.php 4 months ago PodsComponent.php 4 months ago PodsComponents.php 4 months ago PodsData.php 4 months ago PodsField.php 4 months ago PodsForm.php 4 months ago PodsI18n.php 4 months ago PodsInit.php 4 months ago PodsMeta.php 4 months ago PodsMigrate.php 4 months ago PodsRESTFields.php 4 months ago PodsRESTHandlers.php 4 months ago PodsTermSplitting.php 4 months ago PodsUI.php 4 months ago PodsView.php 4 months ago
PodsForm.php
2108 lines
1 <?php
2
3 // Don't load directly.
4 if ( ! defined( 'ABSPATH' ) ) {
5 die( '-1' );
6 }
7
8 use Pods\Whatsit\Field;
9 use Pods\API\Whatsit\Value_Field;
10
11 /**
12 * @package Pods
13 */
14 class PodsForm {
15
16 /**
17 * @var PodsForm
18 */
19 protected static $instance = null;
20
21 /**
22 * @var string
23 */
24 public static $field = null;
25
26 /**
27 * @var string
28 */
29 public static $field_group = null;
30
31 /**
32 * @var string
33 */
34 public static $field_type = null;
35
36 /**
37 * @var array
38 */
39 public static $field_types = array();
40
41 /**
42 * @var array
43 */
44 public static $loaded = array();
45
46 /**
47 * @var int
48 */
49 public static $form_counter = 0;
50
51 /**
52 * Singleton handling for a basic pods_form() request
53 *
54 * @return \PodsForm
55 *
56 * @since 2.3.5
57 */
58 public static function init() {
59
60 if ( ! is_object( self::$instance ) ) {
61 self::$instance = new self();
62 }
63
64 return self::$instance;
65 }
66
67 /**
68 * Master handler for all field / form methods
69 *
70 * @return \PodsForm
71 *
72 * @license http://www.gnu.org/licenses/gpl-2.0.html
73 * @since 2.0.0
74 */
75 private function __construct() {
76
77 add_action( 'admin_init', array( $this, 'admin_init' ), 14 );
78 }
79
80 /**
81 * Prevent clones
82 *
83 * @since 2.3.0
84 */
85 #[\ReturnTypeWillChange]
86 private function __clone() {
87 // Hulk smash
88 }
89
90 /**
91 * Output a label container.
92 *
93 * @since 3.3.5
94 *
95 * @param string $name Field name
96 * @param string $label Label text
97 * @param string $help Help text
98 * @param array $options Field options
99 */
100 public static function output_label( $name, $label, $help = '', $options = null ) {
101 echo self::label( $name, $label, $help, $options ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
102 }
103
104 /**
105 * Return a field's label
106 *
107 * @param string $name Field name
108 * @param string $label Label text
109 * @param string $help Help text
110 * @param array $options Field options
111 *
112 * @return string Label HTML
113 *
114 * @since 2.0.0
115 */
116 public static function label( $name, $label, $help = '', $options = null ) {
117 $prefix = pods_v( 'name_prefix', $options );
118
119 if ( is_array( $label ) || is_object( $label ) ) {
120 $options = $label;
121 $label = $options['label'];
122
123 if ( empty( $label ) ) {
124 $label = ucwords( str_replace( '_', ' ', $name ) );
125 }
126
127 $help = $options['help'];
128 } else {
129 $options = self::options( null, $options );
130 }
131
132 $label = apply_filters( 'pods_form_ui_label_text', $label, $name, $help, $options );
133 $help = apply_filters( 'pods_form_ui_label_help', $help, $name, $label, $options );
134
135 ob_start();
136
137 $name_clean = self::clean( $prefix . $name );
138 $name_more_clean = self::clean( $prefix . $name, true );
139
140 $type = 'label';
141 $attributes = array();
142 $attributes['class'] = 'pods-form-ui-' . $type . ' pods-form-ui-' . $type . '-' . $name_more_clean;
143 $attributes['for'] = ( false === strpos( $name_clean, 'pods-form-ui-' ) ? 'pods-form-ui-' : '' ) . $name_clean;
144 $attributes = self::merge_attributes( $attributes, $name, $type, $options, false );
145
146 pods_view( PODS_DIR . 'ui/fields/_label.php', compact( array_keys( get_defined_vars() ) ) );
147
148 $output = ob_get_clean();
149
150 return apply_filters( "pods_form_ui_{$type}", $output, $name, $label, $help, $attributes, $options );
151 }
152
153 /**
154 * Output a comment container.
155 *
156 * @since 3.3.5
157 *
158 * @param string $name Field name
159 * @param string $message Field comments
160 * @param array $options Field options
161 */
162 public static function output_comment( $name, $message = null, $options = null ) {
163 echo self::comment( $name, $message, $options ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
164 }
165
166 /**
167 * Return a Field Comment Paragraph
168 *
169 * @param string $name Field name
170 * @param string $message Field comments
171 * @param array $options Field options
172 *
173 * @return string Comment HTML
174 *
175 * @since 2.0.0
176 */
177 public static function comment( $name, $message = null, $options = null ) {
178 $prefix = pods_v( 'name_prefix', $options );
179
180 $options = self::options( null, $options );
181
182 $name_more_clean = self::clean( $prefix . $name, true );
183
184 if ( ! empty( $options['description'] ) ) {
185 $message = $options['description'];
186 } elseif ( empty( $message ) ) {
187 return '';
188 }
189
190 $message = apply_filters( 'pods_form_ui_comment_text', $message, $name, $options );
191
192 ob_start();
193
194 $type = 'comment';
195 $attributes = array();
196 $attributes['class'] = 'description pods-form-ui-' . $type . ' pods-form-ui-' . $type . '-' . $name_more_clean;
197 $attributes = self::merge_attributes( $attributes, $name, $type, $options, false );
198
199 pods_view( PODS_DIR . 'ui/fields/_comment.php', compact( array_keys( get_defined_vars() ) ) );
200
201 $output = ob_get_clean();
202
203 return apply_filters( "pods_form_ui_{$type}", $output, $name, $message, $attributes, $options );
204 }
205
206 /**
207 * Output a field
208 *
209 * @since 3.3.5
210 *
211 * @param string $name Field name
212 * @param mixed $value Field value
213 * @param string $type Field type
214 * @param array $options Field options
215 * @param array|Pods $pod Pod data or the Pods object.
216 * @param int $id Item ID
217 */
218 public static function output_field( $name, $value, $type = 'text', $options = null, $pod = null, $id = null ) {
219 echo self::field( $name, $value, $type, $options, $pod, $id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
220 }
221
222 /**
223 * Return a field
224 *
225 * @param string $name Field name
226 * @param mixed $value Field value
227 * @param string $type Field type
228 * @param array $options Field options
229 * @param array|Pods $pod Pod data or the Pods object.
230 * @param int $id Item ID
231 *
232 * @return string Field HTML
233 *
234 * @since 2.0.0
235 */
236 public static function field( $name, $value, $type = 'text', $options = null, $pod = null, $id = null ) {
237 // Take a field array
238 if ( is_array( $name ) || is_object( $name ) ) {
239 $options = $name;
240
241 if ( is_object( $type ) ) {
242 $pod = $type;
243 $id = $options;
244 }
245
246 $name = pods_v( 'name', $options );
247 $type = pods_v( 'type', $options );
248 }
249
250 $options = self::options( $type, $options );
251 $options = apply_filters( "pods_form_ui_field_{$type}_options", $options, $value, $name, $pod, $id );
252
253 if ( empty( $options['type'] ) ) {
254 $options['type'] = $type;
255 }
256
257 if ( null === $value || ( '' === $value && 'boolean' === $type ) || ( ! empty( $pod ) && empty( $id ) ) ) {
258 $value = self::default_value( $value, $type, $name, $options, $pod, $id );
259 }
260
261 // Fix double help qtip when using single checkboxes (boolean type)
262 if ( 'boolean' === $type ) {
263 $options['help'] = '';
264 }
265
266 if (
267 false === self::permission( $type, $name, $options, null, $pod, $id )
268 && ! pods_v_bool( 'read_only_restricted', $options )
269 ) {
270 return false;
271 }
272
273 $value = apply_filters( "pods_form_ui_field_{$type}_value", $value, $name, $options, $pod, $id );
274 $form_field_type = self::$field_type;
275
276 if ( empty( $type ) ) {
277 return;
278 }
279
280 // @todo Move into DFV field method or Pods\Whatsit later
281 if ( ( ! isset( $options['data'] ) || empty( $options['data'] ) ) && is_object( self::$loaded[ $type ] ) && method_exists( self::$loaded[ $type ], 'data' ) ) {
282 $options['data'] = self::$loaded[ $type ]->data( $name, $value, $options, $pod, $id, true );
283 $data = $options['data'];
284 }
285
286 $repeatable_field_types = self::repeatable_field_types();
287
288 // Start field render.
289 ob_start();
290
291 /**
292 * pods_form_ui_field_{$type}_override filter leaves too much to be done by developer.
293 *
294 * It will be replaced in Pods 3.0 with better documentation.
295 *
296 * @deprecated 2.7.0
297 */
298 if ( true === apply_filters( "pods_form_ui_field_{$type}_override", false, $name, $value, $options, $pod, $id ) ) {
299 /**
300 * pods_form_ui_field_{$type} action leaves too much to be done by developer.
301 *
302 * It will be replaced in Pods 3.0 with better documentation.
303 *
304 * @deprecated 2.7.0
305 */
306 do_action( "pods_form_ui_field_{$type}", $name, $value, $options, $pod, $id );
307 } elseif ( method_exists( static::class, 'field_' . $type ) ) {
308 // @todo Move these custom field methods into real/faux field classes
309 echo call_user_func( array( static::class, 'field_' . $type ), $name, $value, $options ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
310 } elseif ( is_object( self::$loaded[ $type ] ) && method_exists( self::$loaded[ $type ], 'input' ) ) {
311 // Force non-repeatable field types to be non-repeatable even if option is set to 1.
312 if ( ! empty( $options['repeatable'] ) && ! in_array( $type, $repeatable_field_types, true ) ) {
313 $options['repeatable'] = 0;
314 }
315
316 self::$loaded[ $type ]->input( $name, $value, $options, $pod, $id );
317 } else {
318 /**
319 * pods_form_ui_field_{$type} action leaves too much to be done by developer.
320 *
321 * It will be replaced in Pods 3.0 with better documentation.
322 *
323 * @deprecated 2.7.0
324 */
325 do_action( "pods_form_ui_field_{$type}", $name, $value, $options, $pod, $id );
326 }//end if
327
328 $output = ob_get_clean();
329
330 /**
331 * pods_form_ui_field_{$type} filter will remain supported.
332 *
333 * It is not intended for replacing but augmenting input markup.
334 */
335 return apply_filters( "pods_form_ui_field_{$type}", $output, $name, $value, $options, $pod, $id );
336 }
337
338 /**
339 * Output field type 'db'
340 *
341 * Used for field names and other places where only [a-z0-9_] is accepted
342 *
343 * @since 2.0.0
344 *
345 * @param $name
346 * @param null $value
347 * @param null $options
348 *
349 * @return mixed|void
350 */
351 protected static function field_db( $name, $value = null, $options = null ) {
352
353 $form_field_type = self::$field_type;
354
355 ob_start();
356
357 pods_view( PODS_DIR . 'ui/fields/_db.php', compact( array_keys( get_defined_vars() ) ) );
358
359 $output = ob_get_clean();
360
361 return apply_filters( 'pods_form_ui_field_db', $output, $name, $value, $options );
362 }
363
364 /**
365 * Output a hidden field
366 *
367 * @param $name
368 * @param null $value
369 * @param null $options
370 *
371 * @return mixed|void
372 */
373 protected static function field_hidden( $name, $value = null, $options = null ) {
374
375 $form_field_type = self::$field_type;
376
377 ob_start();
378
379 pods_view( PODS_DIR . 'ui/fields/_hidden.php', compact( array_keys( get_defined_vars() ) ) );
380
381 $output = ob_get_clean();
382
383 return apply_filters( 'pods_form_ui_field_hidden', $output, $name, $value, $options );
384 }
385
386 /**
387 * Output a submit button.
388 *
389 * @since 3.3.5
390 *
391 * @param string $text The text of the button (defaults to 'Save Changes')
392 * @param string $type The type of button. One of: primary, secondary, delete
393 * @param string $name The HTML name of the submit button. Defaults to "submit". If no id
394 * attribute is given in $other_attributes below, $name will be used as the
395 * button's id.
396 * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
397 * false otherwise. Defaults to true
398 * @param array|string $other_attributes Other attributes that should be output with the button,
399 * mapping attributes to their values, such as array( 'tabindex' => '1' ).
400 * These attributes will be output as attribute="value", such as
401 * tabindex="1".
402 * Defaults to no other attributes. Other attributes can also be provided as
403 * a
404 * string such as 'tabindex="1"', though the array format is typically
405 * cleaner.
406 */
407 public static function output_submit_button( $text = null, $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = null ) {
408 echo self::submit_button( $text, $type, $name, $wrap, $other_attributes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
409 }
410
411 /**
412 * Returns a submit button, with provided text and appropriate class, copied from WP Core for use on the frontend
413 *
414 * @see get_submit_button
415 *
416 * @param string $text The text of the button (defaults to 'Save Changes')
417 * @param string $type The type of button. One of: primary, secondary, delete
418 * @param string $name The HTML name of the submit button. Defaults to "submit". If no id
419 * attribute is given in $other_attributes below, $name will be used as the
420 * button's id.
421 * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
422 * false otherwise. Defaults to true
423 * @param array|string $other_attributes Other attributes that should be output with the button,
424 * mapping attributes to their values, such as array( 'tabindex' => '1' ).
425 * These attributes will be output as attribute="value", such as
426 * tabindex="1".
427 * Defaults to no other attributes. Other attributes can also be provided as
428 * a
429 * string such as 'tabindex="1"', though the array format is typically
430 * cleaner.
431 *
432 * @since 2.7.0
433 * @return string
434 */
435 public static function submit_button( $text = null, $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = null ) {
436
437 if ( function_exists( 'get_submit_button' ) ) {
438 return get_submit_button( $text, $type, $name, $wrap, $other_attributes );
439 }
440
441 if ( ! is_array( $type ) ) {
442 $type = explode( ' ', $type );
443 }
444
445 $button_shorthand = array(
446 'primary',
447 'small',
448 'large',
449 );
450
451 $classes = array(
452 'button',
453 );
454
455 foreach ( $type as $t ) {
456 if ( 'secondary' === $t || 'button-secondary' === $t ) {
457 continue;
458 }
459
460 $classes[] = in_array( $t, $button_shorthand ) ? 'button-' . $t : $t;
461 }
462
463 $class = implode( ' ', array_unique( $classes ) );
464
465 if ( 'delete' === $type ) {
466 $class = 'button-secondary delete';
467 }
468
469 $text = $text ? $text : __( 'Save Changes', 'pods' );
470
471 // Default the id attribute to $name unless an id was specifically provided in $other_attributes
472 $id = $name;
473
474 if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
475 $id = $other_attributes['id'];
476 unset( $other_attributes['id'] );
477 }
478
479 $attributes = '';
480
481 if ( is_array( $other_attributes ) ) {
482 foreach ( $other_attributes as $attribute => $value ) {
483 $attributes .= $attribute . '="' . esc_attr( $value ) . '" ';
484 // Trailing space is important
485 }
486 } elseif ( ! empty( $other_attributes ) ) {
487 // Attributes provided as a string
488 $attributes = $other_attributes;
489 }
490
491 $button = '<input type="submit" name="' . esc_attr( $name ) . '" id="' . esc_attr( $id ) . '" class="' . esc_attr( $class );
492 $button .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
493
494 if ( $wrap ) {
495 $button = '<p class="submit">' . $button . '</p>';
496 }
497
498 return $button;
499
500 }
501
502 /**
503 * Output a row (label, field, and comment)
504 *
505 * @param string $name Field name
506 * @param mixed $value Field value
507 * @param string $type Field type
508 * @param array $options Field options
509 * @param array $pod Pod data
510 * @param int $id Item ID
511 *
512 * @return string Row HTML
513 *
514 * @since 2.0.0
515 */
516 public static function row( $name, $value, $type = 'text', $options = null, $pod = null, $id = null ) {
517
518 $options = self::options( null, $options );
519
520 ob_start();
521
522 pods_view( PODS_DIR . 'ui/fields/_row.php', compact( array_keys( get_defined_vars() ) ) );
523
524 $output = ob_get_clean();
525
526 return apply_filters( 'pods_form_ui_field_row', $output, $name, $value, $options, $pod, $id );
527 }
528
529 /**
530 * Output a field's attributes
531 *
532 * @since 2.0.0
533 *
534 * @param $attributes
535 * @param null $name
536 * @param null $type
537 * @param null $options
538 */
539 public static function attributes( $attributes, $name = null, $type = null, $options = null ) {
540
541 $attributes = (array) apply_filters( "pods_form_ui_field_{$type}_attributes", $attributes, $name, $options );
542
543 $final_attributes = [];
544
545 foreach ( $attributes as $attribute => $value ) {
546 if ( null === $value ) {
547 continue;
548 }
549
550 if ( 'class' === $attribute ) {
551 $value = pods_enforce_safe_class( $value );
552 } elseif ( 'id' === $attribute ) {
553 $value = pods_enforce_safe_id( $value );
554 }
555
556 $final_attributes[ (string) $attribute ] = (string) $value;
557 }
558
559 if (pods_render_is_in_block()) {
560 echo ' ' . get_block_wrapper_attributes( $final_attributes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
561
562 return;
563 }
564
565 foreach ( $final_attributes as $attribute => $value ) {
566 echo ' ' . esc_attr( (string) $attribute ) . '="' . esc_attr( (string) $value ) . '"';
567 }
568 }
569
570 /**
571 * Output a field's data (for use with jQuery)
572 *
573 * @since 2.0.0
574 *
575 * @param $data
576 * @param null $name
577 * @param null $type
578 * @param null $options
579 */
580 public static function data( $data, $name = null, $type = null, $options = null ) {
581
582 $data = (array) apply_filters( "pods_form_ui_field_{$type}_data", $data, $name, $options );
583
584 foreach ( $data as $key => $value ) {
585 if ( null === $value ) {
586 continue;
587 }
588
589 $key = sanitize_title( $key );
590
591 if ( is_array( $value ) ) {
592 $value = implode( ',', $value );
593 }
594
595 echo ' data-' . esc_attr( (string) $key ) . '="' . esc_attr( (string) $value ) . '"';
596 }
597 }
598
599 /**
600 * Merge attributes and handle classes
601 *
602 * @since 2.0.0
603 *
604 * @param $attributes
605 * @param null $name
606 * @param null $type
607 * @param null $options
608 * @param string $classes
609 *
610 * @return array
611 */
612 public static function merge_attributes( $attributes, $name = null, $type = null, $options = null, $classes = '' ) {
613
614 if ( $options instanceof Field ) {
615 $options = $options->get_args();
616 }
617
618 $options = (array) $options;
619
620 $prefix = pods_v( 'name_prefix', $options );
621
622 if ( ! in_array( $type, array( 'label', 'comment' ) ) ) {
623 $name_clean = self::clean( $prefix . $name );
624 $name_more_clean = self::clean( $prefix . $name, true );
625 $_attributes = array();
626 $_attributes['name'] = $prefix . $name;
627 $_attributes['data-name-clean'] = $name_more_clean;
628
629 if ( 0 < strlen( (string) pods_v( 'label', $options, '' ) ) ) {
630 $_attributes['data-label'] = wp_strip_all_tags( pods_v( 'label', $options ) );
631 }
632
633 $_attributes['id'] = 'pods-form-ui-' . $name_clean . ( self::$form_counter > 1 ? '-' . self::$form_counter : '' );
634 $_attributes['class'] = 'pods-form-ui-field pods-form-ui-field-type-' . $type . ' pods-form-ui-field-name-' . $name_more_clean;
635
636 if ( isset( $options['dependency'] ) && false !== $options['dependency'] ) {
637 $_attributes['class'] .= ' pods-dependent-toggle';
638 }
639
640 $attributes = array_merge( $_attributes, (array) $attributes );
641
642 if ( isset( $options['attributes'] ) && is_array( $options['attributes'] ) && ! empty( $options['attributes'] ) ) {
643 $attributes = array_merge( $attributes, $options['attributes'] );
644 }
645 } elseif ( isset( $options[ $type . '_attributes' ] ) && is_array( $options[ $type . '_attributes' ] ) && ! empty( $options[ $type . '_attributes' ] ) ) {
646 $attributes = array_merge( $attributes, $options[ $type . '_attributes' ] );
647 }//end if
648
649 if ( isset( $options['class'] ) && ! empty( $options['class'] ) ) {
650 if ( is_array( $options['class'] ) ) {
651 $options['class'] = implode( ' ', $options['class'] );
652 }
653
654 $options['class'] = (string) $options['class'];
655 if ( isset( $attributes['class'] ) ) {
656 $attributes['class'] = $attributes['class'] . ' ' . $options['class'];
657 } else {
658 $attributes['class'] = $options['class'];
659 }
660
661 $attributes['class'] = trim( $attributes['class'] );
662 }
663
664 if ( ! empty( $classes ) ) {
665 if ( isset( $attributes['class'] ) ) {
666 $attributes['class'] = $attributes['class'] . ' ' . $classes;
667 } else {
668 $attributes['class'] = $classes;
669 }
670 }
671
672 $placeholder = trim( (string) pods_v( 'placeholder', $options, pods_v( $type . '_placeholder', $options ) ) );
673
674 if ( ! empty( $placeholder ) ) {
675 $attributes['placeholder'] = $placeholder;
676 }
677
678 if ( 1 === (int) pods_v( 'required', $options, 0 ) ) {
679 $attributes['class'] .= ' pods-validate pods-validate-required';
680 }
681
682 $max_length = (int) pods_v( 'maxlength', $options, pods_v( $type . '_max_length', $options, 0 ) );
683
684 if ( 0 < $max_length ) {
685 $attributes['maxlength'] = $max_length;
686 }
687
688 $attributes = (array) apply_filters( "pods_form_ui_field_{$type}_merge_attributes", $attributes, $name, $options );
689
690 return $attributes;
691 }
692
693 /**
694 * Setup options for a field and store them for later use
695 *
696 * @param $type
697 * @param $options
698 *
699 * @return array
700 *
701 * @static
702 *
703 * @since 2.0.0
704 */
705 public static function options( $type, $options ) {
706 if ( is_object( $options ) ) {
707 $options_array = $options->get_args();
708 $options_array['_field_object'] = $options;
709 } else {
710 $options_array = (array) $options;
711 $options_array['_field_object'] = null;
712 }
713
714 $defaults = self::options_setup( $type );
715
716 $core_defaults = [
717 'id' => 0,
718 'label' => '',
719 'description' => '',
720 'help' => '',
721 'default' => null,
722 'attributes' => [],
723 'class' => '',
724 'grouped' => 0,
725 ];
726
727 $defaults = array_merge( $core_defaults, $defaults );
728
729 foreach ( $defaults as $option => $settings ) {
730 $default = $core_defaults['default'];
731
732 if ( ! is_array( $settings ) ) {
733 $default = $settings;
734 } elseif ( isset( $settings['default'] ) ) {
735 $default = $settings['default'];
736 }
737
738 if ( ! isset( $options_array[ $option ] ) ) {
739 $options_array[ $option ] = $default;
740 }
741 }
742
743 return $options_array;
744 }
745
746 /**
747 * Get options for a field type and setup defaults
748 *
749 * @static
750 *
751 * @param $type
752 *
753 * @param null $options
754 *
755 * @return array|null
756 * @since 2.0.0
757 */
758 public static function options_setup( $type = null, $options = null ) {
759
760 $core_defaults = array(
761 'id' => 0,
762 'name' => '',
763 'label' => '',
764 'description' => '',
765 'help' => '',
766 'default' => null,
767 'attributes' => array(),
768 'class' => '',
769 'type' => 'text',
770 'group' => 0,
771 'grouped' => 0,
772 'developer_mode' => false,
773 'dependency' => false,
774 'depends-on' => array(),
775 'depends-on-any' => array(),
776 'depends-on-multi' => array(),
777 'excludes-on' => array(),
778 'wildcard-on' => array(),
779 'options' => array(),
780 );
781
782 if ( ! empty( $options ) && is_array( $options ) ) {
783 $core_defaults = array_merge( $core_defaults, $options );
784 }
785
786 if ( null === $type ) {
787 return $core_defaults;
788 } else {
789 self::field_loader( $type );
790 }
791
792 $ui_options = apply_filters( "pods_field_{$type}_options", (array) self::$loaded[ $type ]->options(), $type );
793
794 $first_field = reset( $ui_options );
795
796 if ( ! empty( $ui_options ) && ! isset( $first_field['name'] ) && ! isset( $first_field['label'] ) ) {
797 foreach ( $ui_options as $group => $group_options ) {
798 $ui_options[ $group ] = self::fields_setup( $group_options, $core_defaults );
799 }
800
801 return $ui_options;
802 }
803
804 return self::fields_setup( $ui_options, $core_defaults );
805 }
806
807 /**
808 * Get Admin options for a field type and setup defaults
809 *
810 * @static
811 *
812 * @param $type
813 *
814 * @return array|null
815 *
816 * @since 2.0.0
817 */
818 public static function ui_options( $type ) {
819
820 $core_defaults = array(
821 'id' => 0,
822 'name' => '',
823 'label' => '',
824 'description' => '',
825 'help' => '',
826 'default' => null,
827 'attributes' => array(),
828 'class' => '',
829 'type' => 'text',
830 'group' => 0,
831 'grouped' => 0,
832 'developer_mode' => false,
833 'dependency' => false,
834 'depends-on' => array(),
835 'depends-on-any' => array(),
836 'depends-on-multi' => array(),
837 'excludes-on' => array(),
838 'wildcard-on' => array(),
839 'options' => array(),
840 );
841
842 self::field_loader( $type );
843
844 $ui_options = apply_filters( "pods_field_{$type}_ui_options", (array) self::$loaded[ $type ]->ui_options(), $type );
845
846 $first_field = reset( $ui_options );
847
848 if ( ! empty( $ui_options ) && ! isset( $first_field['name'] ) && ! isset( $first_field['label'] ) ) {
849 foreach ( $ui_options as $group => $group_options ) {
850 $ui_options[ $group ] = self::fields_setup( $group_options, $core_defaults );
851 }
852
853 return $ui_options;
854 }
855
856 return self::fields_setup( $ui_options, $core_defaults );
857 }
858
859 /**
860 * Get options for a field and setup defaults
861 *
862 * @param null $fields
863 * @param null $core_defaults
864 * @param bool $single
865 *
866 * @return array|null
867 *
868 * @static
869 * @since 2.0.0
870 */
871 public static function fields_setup( $fields = null, $core_defaults = null, $single = false ) {
872
873 if ( empty( $core_defaults ) ) {
874 $core_defaults = array(
875 'id' => 0,
876 'name' => '',
877 'label' => '',
878 'description' => '',
879 'help' => '',
880 'default' => null,
881 'attributes' => array(),
882 'class' => '',
883 'type' => 'text',
884 'group' => 0,
885 'grouped' => 0,
886 'developer_mode' => false,
887 'dependency' => false,
888 'depends-on' => array(),
889 'depends-on-any' => array(),
890 'depends-on-multi' => array(),
891 'excludes-on' => array(),
892 'wildcard-on' => array(),
893 'options' => array(),
894 );
895 }
896
897 if ( $single ) {
898 $fields = array( $fields );
899 }
900
901 foreach ( $fields as $f => $field ) {
902 if ( ! $single && empty( $field['name'] ) ) {
903 $field['name'] = $f;
904 }
905
906 $fields[ $f ] = self::field_setup( $field, $core_defaults, pods_v( 'type', $field, 'text' ) );
907 }
908
909 if ( $single ) {
910 $fields = $fields[0];
911 }
912
913 return $fields;
914 }
915
916 /**
917 * Get options for a field and setup defaults
918 *
919 * @static
920 *
921 * @param null|array|string|Field $field
922 * @param null|array $core_defaults
923 * @param null|string $type
924 *
925 * @return array|null
926 *
927 * @since 2.0.0
928 */
929 public static function field_setup( $field = null, $core_defaults = null, $type = null ) {
930
931 $ui_options = array();
932
933 if ( empty( $core_defaults ) ) {
934 $core_defaults = array(
935 'id' => 0,
936 'name' => '',
937 'label' => '',
938 'description' => '',
939 'help' => '',
940 'default' => null,
941 'attributes' => array(),
942 'class' => '',
943 'type' => 'text',
944 'group' => 0,
945 'grouped' => 0,
946 'developer_mode' => false,
947 'dependency' => false,
948 'depends-on' => array(),
949 'depends-on-any' => array(),
950 'depends-on-multi' => array(),
951 'excludes-on' => array(),
952 'wildcard-on' => array(),
953 'options' => array(),
954 );
955
956 if ( null !== $type ) {
957 self::field_loader( $type );
958
959 if ( method_exists( self::$loaded[ $type ], 'options' ) ) {
960 $ui_options = apply_filters( "pods_field_{$type}_options", (array) self::$loaded[ $type ]->options(), $type );
961 }
962 }
963 }//end if
964
965 $is_field_object = $field instanceof Field;
966
967 if ( ! is_array( $field ) && ! $is_field_object ) {
968 $field = [
969 'default' => $field,
970 ];
971 }
972
973 // @todo Revisit this.
974 if ( isset( $field['group'] ) && is_array( $field['group'] ) ) {
975 $group = $field['group'];
976
977 foreach ( $group as $g => $group_option ) {
978 $group[ $g ] = array_merge( $core_defaults, $group_option );
979
980 if ( ! isset( $group[ $g ] ) || '' === $group[ $g ]['name'] ) {
981 $group[ $g ]['name'] = $g;
982 }
983 }
984
985 $field['group'] = $group;
986 }
987
988 $field = pods_config_merge_data( $core_defaults, $field );
989
990 foreach ( $ui_options as $option => $settings ) {
991 if ( ! is_string( $option ) ) {
992 $option = $settings['name'];
993 }
994
995 $default = null;
996
997 if ( isset( $settings['default'] ) ) {
998 $default = $settings['default'];
999 }
1000
1001 if ( $is_field_object ) {
1002 $option_value = $field->get_arg( $option );
1003
1004 if ( null === $option_value ) {
1005 $field->set_arg( $option, $default );
1006 }
1007 } elseif ( ! isset( $field['options'][ $option ] ) ) {
1008 $field['options'][ $option ] = $default;
1009 }
1010 }
1011
1012 return $field;
1013 }
1014
1015 /**
1016 * Setup dependency / exclusion classes
1017 *
1018 * @param array $options array( 'depends-on' => ..., 'excludes-on' => ...)
1019 * @param string $prefix
1020 *
1021 * @return array
1022 * @static
1023 * @since 2.0.0
1024 */
1025 public static function dependencies( $options, $prefix = 'pods-form-ui-' ) {
1026 $options = (array) $options;
1027 $classes = [];
1028 $data = [];
1029
1030 $dependency_checks = [
1031 'depends-on',
1032 'depends-on-any',
1033 'depends-on-multi',
1034 'excludes-on',
1035 ];
1036
1037 foreach ( $dependency_checks as $dependency_check ) {
1038 if ( ! isset( $options[ $dependency_check ] ) ) {
1039 continue;
1040 }
1041
1042 $dependency_list = (array) $options[ $dependency_check ];
1043
1044 if ( ! empty( $dependency_list ) ) {
1045 $classes[] = 'pods-' . $dependency_check;
1046
1047 foreach ( $dependency_list as $depends => $on ) {
1048 $classes[] = 'pods-' . $dependency_check . '-' . $prefix . self::clean( $depends, true );
1049
1050 if ( ! is_bool( $on ) ) {
1051 $on = (array) $on;
1052
1053 foreach ( $on as $o ) {
1054 $classes[] = 'pods-' . $dependency_check . '-' . $prefix . self::clean( $depends, true ) . '-' . self::clean( $o, true );
1055 }
1056 }
1057 }
1058 }
1059 }
1060
1061 if ( isset( $options['wildcard-on'] ) ) {
1062 $wildcard_on = (array) $options['wildcard-on'];
1063
1064 if ( ! empty( $wildcard_on ) ) {
1065 $classes[] = 'pods-wildcard-on';
1066
1067 // Add the appropriate classes and data attribs per value dependency
1068 foreach ( $wildcard_on as $target => $wildcards ) {
1069 $target = $prefix . self::clean( $target, true );
1070 $classes[] = 'pods-wildcard-on-' . $target;
1071 $data[ 'pods-wildcard-' . $target ] = $wildcards;
1072 }
1073 }
1074 }
1075
1076 $classes = implode( ' ', $classes );
1077
1078 return array(
1079 'classes' => $classes,
1080 'data' => $data,
1081 );
1082 }
1083
1084 /**
1085 * Change the value of the field
1086 *
1087 * @param $type
1088 * @param mixed $value
1089 * @param string $name
1090 * @param array $options
1091 * @param array $pod
1092 * @param int $id
1093 * @param array $traverse
1094 *
1095 * @return array|mixed|null|object
1096 * @internal param array $fields
1097 * @since 2.3.0
1098 */
1099 public static function value( $type, $value = null, $name = null, $options = null, $pod = null, $id = null, $traverse = null ) {
1100
1101 self::field_loader( $type );
1102
1103 $is_repeatable_field = (
1104 (
1105 (
1106 $options instanceof Field
1107 || $options instanceof Value_Field
1108 )
1109 && $options->is_repeatable()
1110 )
1111 || (
1112 is_array( $options )
1113 && in_array( $type, self::repeatable_field_types(), true )
1114 && 1 === (int) pods_v( 'repeatable', $options )
1115 && (
1116 'wysiwyg' !== $type
1117 || 'tinymce' !== pods_v( 'wysiwyg_editor', $options, 'tinymce', true )
1118 )
1119 )
1120 );
1121
1122 if ( $is_repeatable_field && ! is_array( $value ) ) {
1123 if ( is_string( $value ) && 0 < strlen( $value ) ) {
1124 $simple = @json_decode( $value, true );
1125
1126 if ( is_array( $simple ) ) {
1127 $value = $simple;
1128 } else {
1129 $value = (array) $value;
1130 }
1131 } else {
1132 $value = [];
1133 }
1134 }
1135
1136 if ( is_array( $value ) && in_array( $type, self::tableless_field_types(), true ) ) {
1137 foreach ( $value as &$display_value ) {
1138 $display_value = call_user_func( array(
1139 self::$loaded[ $type ],
1140 'value',
1141 ), $display_value, $name, $options, $pod, $id, $traverse );
1142 }
1143 } else {
1144 $value = call_user_func( array(
1145 self::$loaded[ $type ],
1146 'value',
1147 ), $value, $name, $options, $pod, $id, $traverse );
1148 }//end if
1149
1150 return $value;
1151 }
1152
1153 /**
1154 * Change the way the value of the field is displayed with Pods::get
1155 *
1156 * @param $type
1157 * @param mixed $value
1158 * @param string $name
1159 * @param array $options
1160 * @param array $pod
1161 * @param int $id
1162 * @param array $traverse
1163 *
1164 * @return array|mixed|null|void
1165 * @internal param array $fields
1166 * @since 2.0.0
1167 */
1168 public static function display( $type, $value = null, $name = null, $options = null, $pod = null, $id = null, $traverse = null ) {
1169
1170 self::field_loader( $type );
1171
1172 $tableless_field_types = self::tableless_field_types();
1173
1174 if ( method_exists( self::$loaded[ $type ], 'display_list' ) ) {
1175 $value = call_user_func_array(
1176 array( self::$loaded[ $type ], 'display_list' ), array(
1177 $value,
1178 $name,
1179 $options,
1180 $pod,
1181 $id,
1182 $traverse,
1183 )
1184 );
1185 } elseif ( method_exists( self::$loaded[ $type ], 'display' ) ) {
1186 if ( is_array( $value ) && ! in_array( $type, $tableless_field_types ) ) {
1187 foreach ( $value as $k => $display_value ) {
1188 $value[ $k ] = call_user_func_array(
1189 array( self::$loaded[ $type ], 'display' ), array(
1190 $display_value,
1191 $name,
1192 $options,
1193 $pod,
1194 $id,
1195 $traverse,
1196 )
1197 );
1198 }
1199 } else {
1200 $value = call_user_func_array(
1201 array( self::$loaded[ $type ], 'display' ), array(
1202 $value,
1203 $name,
1204 $options,
1205 $pod,
1206 $id,
1207 $traverse,
1208 )
1209 );
1210 }//end if
1211 }//end if
1212
1213 $value = apply_filters( "pods_form_display_{$type}", $value, $name, $options, $pod, $id, $traverse );
1214
1215 return $value;
1216 }
1217
1218 /**
1219 * Setup regex for JS / PHP
1220 *
1221 * @static
1222 *
1223 * @param $type
1224 * @param $options
1225 *
1226 * @return mixed|void
1227 * @since 2.0.0
1228 */
1229 public static function regex( $type, $options ) {
1230
1231 self::field_loader( $type );
1232
1233 $regex = false;
1234
1235 if ( method_exists( self::$loaded[ $type ], 'regex' ) ) {
1236 $regex = self::$loaded[ $type ]->regex( $options );
1237 }
1238
1239 $regex = apply_filters( "pods_field_{$type}_regex", $regex, $options, $type );
1240
1241 return $regex;
1242 }
1243
1244 /**
1245 * Setup value preparation for sprintf
1246 *
1247 * @static
1248 *
1249 * @param $type
1250 * @param $options
1251 *
1252 * @return mixed|void
1253 * @since 2.0.0
1254 */
1255 public static function prepare( $type, $options ) {
1256
1257 self::field_loader( $type );
1258
1259 $prepare = '%s';
1260
1261 if ( method_exists( self::$loaded[ $type ], 'prepare' ) ) {
1262 $prepare = self::$loaded[ $type ]->prepare( $options );
1263 }
1264
1265 $prepare = apply_filters( "pods_field_{$type}_prepare", $prepare, $options, $type );
1266
1267 return $prepare;
1268 }
1269
1270 /**
1271 * Validate a value before it's saved
1272 *
1273 * @param string $type
1274 * @param mixed $value
1275 * @param string $name
1276 * @param array $options
1277 * @param array $fields
1278 * @param array $pod
1279 * @param int $id
1280 * @param array|object $params
1281 *
1282 * @static
1283 *
1284 * @since 2.0.0
1285 * @return bool|mixed|void
1286 */
1287 public static function validate( $type, $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
1288
1289 self::field_loader( $type );
1290
1291 $validate = true;
1292
1293 if ( 1 == pods_v( 'pre_save', $options, 1 ) && method_exists( self::$loaded[ $type ], 'validate' ) ) {
1294 $validate = self::$loaded[ $type ]->validate( $value, $name, $options, $fields, $pod, $id, $params );
1295 }
1296
1297 $validate = apply_filters( "pods_field_{$type}_validate", $validate, $value, $name, $options, $fields, $pod, $id, $type, $params );
1298
1299 return $validate;
1300 }
1301
1302 /**
1303 * Change the value or perform actions after validation but before saving to the DB
1304 *
1305 * @param string $type
1306 * @param mixed $value
1307 * @param int $id
1308 * @param string $name
1309 * @param array $options
1310 * @param array $fields
1311 * @param array $pod
1312 * @param object $params
1313 *
1314 * @static
1315 *
1316 * @since 2.0.0
1317 * @return mixed
1318 */
1319 public static function pre_save( $type, $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
1320
1321 self::field_loader( $type );
1322
1323 if ( 1 == pods_v( 'field_pre_save', $options, 1 ) && method_exists( self::$loaded[ $type ], 'pre_save' ) ) {
1324 $value = self::$loaded[ $type ]->pre_save( $value, $id, $name, $options, $fields, $pod, $params );
1325 }
1326
1327 return $value;
1328 }
1329
1330 /**
1331 * Save the value to the DB
1332 *
1333 * @param string $type
1334 * @param mixed $value
1335 * @param int $id
1336 * @param string $name
1337 * @param array $options
1338 * @param array $fields
1339 * @param array $pod
1340 * @param object $params
1341 *
1342 * @static
1343 *
1344 * @since 2.3.0
1345 * @return null
1346 */
1347 public static function save( $type, $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
1348
1349 self::field_loader( $type );
1350
1351 $saved = null;
1352
1353 if ( 1 == pods_v( 'field_save', $options, 1 ) && method_exists( self::$loaded[ $type ], 'save' ) ) {
1354 $saved = self::$loaded[ $type ]->save( $value, $id, $name, $options, $fields, $pod, $params );
1355 }
1356
1357 return $saved;
1358 }
1359
1360 /**
1361 * Delete the value from the DB
1362 *
1363 * @param string $type
1364 * @param int $id
1365 * @param string $name
1366 * @param array $options
1367 * @param array $pod
1368 *
1369 * @static
1370 *
1371 * @since 2.3.0
1372 * @return null
1373 */
1374 public static function delete( $type, $id = null, $name = null, $options = null, $pod = null ) {
1375
1376 self::field_loader( $type );
1377
1378 $deleted = null;
1379
1380 if ( 1 == pods_v( 'field_delete', $options, 1 ) && method_exists( self::$loaded[ $type ], 'delete' ) ) {
1381 $deleted = self::$loaded[ $type ]->delete( $id, $name, $options, $pod );
1382 }
1383
1384 return $deleted;
1385 }
1386
1387 /**
1388 * Check if a user has permission to be editing a field
1389 *
1390 * @param $type
1391 * @param null $name
1392 * @param null $options
1393 * @param null $fields
1394 * @param null $pod
1395 * @param null $id
1396 * @param null $params
1397 *
1398 * @static
1399 *
1400 * @since 2.0.0
1401 * @return bool
1402 */
1403 public static function permission( $type, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
1404 $permission = pods_permission( $options );
1405
1406 /**
1407 * @since 2.0.0
1408 * @deprecated 2.8.0
1409 */
1410 return (boolean) apply_filters( 'pods_form_field_permission', $permission, $type, $name, $options, $fields, $pod, $id, $params );
1411 }
1412
1413 /**
1414 * Parse the default the value
1415 *
1416 * @since 2.0.0
1417 *
1418 * @param $value
1419 * @param string $type
1420 * @param null $name
1421 * @param null $options
1422 * @param null $pod
1423 * @param null $id
1424 *
1425 * @return mixed|void
1426 */
1427 public static function default_value( $value, $type = 'text', $name = null, $options = null, $pod = null, $id = null ) {
1428
1429 $default_value = pods_v( 'default_value', $options );
1430
1431 if ( '' === $default_value || null === $default_value ) {
1432 $default_value = $value;
1433 }
1434
1435 $default = pods_v( 'default', $options, $default_value, true );
1436
1437 if ( is_string( $default ) ) {
1438 $default_value = str_replace( array( '{@', '}' ), '', $default );
1439
1440 if ( $default !== $default_value && 1 === (int) pods_v( 'default_evaluate_tags', $options, 1 ) ) {
1441 $default = pods_evaluate_tags( $default );
1442 }
1443 }
1444
1445 $default_value_parameter = pods_v( 'default_value_parameter', $options );
1446
1447 if ( $default_value_parameter ) {
1448 $default_value = pods_v( $default_value_parameter, 'request', $default );
1449
1450 if ( '' !== $default_value ) {
1451 $default = $default_value;
1452 }
1453 }
1454
1455 if ( $default != $value ) {
1456 $value = $default;
1457 }
1458
1459 if ( is_array( $value ) && 'multi' !== pods_v( $type . '_format_type' ) ) {
1460 $value = pods_serial_comma( $value, $name, [ $name => $options ] );
1461 }
1462
1463 return apply_filters( 'pods_form_field_default_value', $value, $default, $type, $options, $pod, $id );
1464 }
1465
1466 /**
1467 * Clean a value for use in class / id
1468 *
1469 * @since 2.0.0
1470 *
1471 * @param $input
1472 * @param bool $noarray
1473 * @param bool $db_field
1474 *
1475 * @return mixed|string
1476 */
1477 public static function clean( $input, $noarray = false, $db_field = false ) {
1478
1479 $output = trim( (string) $input );
1480
1481 $output = str_replace( '--1', 'podsfixtemp1', $output );
1482 $output = str_replace( '__1', 'podsfixtemp2', $output );
1483
1484 if ( false !== $noarray ) {
1485 $output = preg_replace( '/\[podsfixtemp\d+\]/', '-', $output );
1486 $output = preg_replace( '/\[\d*\]/', '-', $output );
1487 }
1488
1489 $output = str_replace( array( '[', ']' ), '-', $output );
1490
1491 $output = pods_clean_name( $output );
1492
1493 $output = preg_replace( '/([^a-z0-9\-_])/', '', $output );
1494 $output = preg_replace( '/(_){2,}/', '_', $output );
1495 $output = preg_replace( '/(-){2,}/', '-', $output );
1496
1497 if ( true !== $db_field ) {
1498 $output = str_replace( '_', '-', $output );
1499 }
1500
1501 $output = rtrim( $output, '-' );
1502
1503 $output = str_replace( 'podsfixtemp1', '--1', $output );
1504 $output = str_replace( 'podsfixtemp2', '__1', $output );
1505
1506 return $output;
1507 }
1508
1509 /**
1510 * Run admin_init methods for each field type
1511 *
1512 * @since 2.3.0
1513 */
1514 public function admin_init() {
1515
1516 $admin_field_types = pods_transient_get( 'pods_form_admin_init_field_types' );
1517
1518 if ( empty( $admin_field_types ) ) {
1519 $admin_field_types = array();
1520
1521 $field_types = self::field_types();
1522
1523 foreach ( $field_types as $field_type => $field_type_data ) {
1524 $has_admin_init = self::field_method( $field_type_data['type'], 'admin_init' );
1525
1526 if ( false !== $has_admin_init ) {
1527 $admin_field_types[] = $field_type;
1528 }
1529 }
1530
1531 pods_transient_set( 'pods_form_admin_init_field_types', $admin_field_types, WEEK_IN_SECONDS );
1532 } else {
1533 foreach ( $admin_field_types as $field_type ) {
1534 self::field_method( $field_type, 'admin_init' );
1535 }
1536 }
1537 }
1538
1539 /**
1540 * Autoload a Field Type's class
1541 *
1542 * @param string $field_type Field Type identifier
1543 * @param string $file The Field Type class file location
1544 *
1545 * @return string
1546 * @access public
1547 * @static
1548 * @since 2.0.0
1549 */
1550 public static function field_loader( $field_type, $file = '' ) {
1551
1552 if ( isset( self::$loaded[ $field_type ] ) ) {
1553 $class_vars = get_class_vars( get_class( self::$loaded[ $field_type ] ) );
1554 // PHP 5.2.x workaround
1555 self::$field_group = ( isset( $class_vars['group'] ) ? $class_vars['group'] : '' );
1556 self::$field_type = $class_vars['type'];
1557
1558 if ( 'Unknown' !== $class_vars['label'] ) {
1559 return self::$loaded[ $field_type ];
1560 }
1561 }
1562
1563 $field_type = self::clean( $field_type, true, true );
1564
1565 $class_name = ucfirst( $field_type );
1566 $class_name = "PodsField_{$class_name}";
1567
1568 if ( ! class_exists( $class_name ) ) {
1569 if ( isset( self::$field_types[ $field_type ] ) && ! empty( self::$field_types[ $field_type ]['file'] ) ) {
1570 $file = realpath( self::$field_types[ $field_type ]['file'] );
1571 }
1572
1573 /**
1574 * The field type include path.
1575 *
1576 * @since unknown
1577 *
1578 * @param string $file The file path to include for the field type.
1579 * @param string $field_type The field type.
1580 */
1581 $file = apply_filters( 'pods_form_field_include', $file, $field_type );
1582
1583 $file = trim( $file );
1584
1585 if ( '' !== $file ) {
1586 $located = pods_validate_safe_path( $file, 'all' );
1587
1588 if ( $located ) {
1589 include_once $located;
1590 }
1591 }
1592 }
1593
1594 if ( class_exists( $class_name ) ) {
1595 $class = new $class_name();
1596 } else {
1597 $class = new PodsField();
1598 $class_name = 'PodsField';
1599 }
1600
1601 $class_vars = get_class_vars( $class_name );
1602
1603 // PHP 5.2.x workaround
1604 self::$field_group = ( isset( $class_vars['group'] ) ? $class_vars['group'] : '' );
1605 self::$field_type = $class_vars['type'];
1606
1607 self::$loaded[ $field_type ] =& $class;
1608
1609 return self::$loaded[ $field_type ];
1610 }
1611
1612 /**
1613 * Run a method from a Field Type's class
1614 *
1615 * @return mixed
1616 * @internal param string $field_type Field Type identifier
1617 * @internal param string $method Method name
1618 * @internal param mixed $arg More arguments
1619 *
1620 * @access public
1621 * @static
1622 * @since 2.0.0
1623 */
1624 public static function field_method() {
1625
1626 $args = func_get_args();
1627
1628 if ( empty( $args ) && count( $args ) < 2 ) {
1629 return false;
1630 }
1631
1632 $field_type = array_shift( $args );
1633 $method = array_shift( $args );
1634
1635 $class = self::field_loader( $field_type );
1636
1637 if ( method_exists( $class, $method ) ) {
1638 return call_user_func_array( array( $class, $method ), $args );
1639 }
1640
1641 return false;
1642 }
1643
1644 /**
1645 * Add a new Pod field type
1646 *
1647 * @param string $type The new field type identifier
1648 * @param string $file The new field type class file location
1649 *
1650 * @return array Field Type data
1651 *
1652 * @since 2.3.0
1653 */
1654 public static function register_field_type( $type, $file = null ) {
1655
1656 $field_type = pods_transient_get( 'pods_field_type_' . $type );
1657
1658 if ( empty( $field_type ) || $field_type['type'] != $type || $field_type['file'] != $file ) {
1659 self::field_loader( $type, $file );
1660
1661 $class_vars = get_class_vars( get_class( self::$loaded[ $type ] ) );
1662 // PHP 5.2.x workaround
1663 self::$field_types[ $type ] = $class_vars;
1664 self::$field_types[ $type ]['file'] = $file;
1665
1666 pods_transient_set( 'pods_field_type_' . $type, self::$field_types[ $type ], WEEK_IN_SECONDS );
1667 } else {
1668 self::$field_types[ $type ] = $field_type;
1669 }
1670
1671 return self::$field_types[ $type ];
1672 }
1673
1674 /**
1675 * Get a list of all available Pod types (no labels).
1676 *
1677 * @return string[] List of Pod types.
1678 *
1679 * @since 2.8.0
1680 * @deprecated 2.9.17 Use pods_api()->get_pod_types() instead.
1681 */
1682 public static function pod_types_list() {
1683 return array_keys( pods_api()->get_pod_types() );
1684 }
1685
1686 /**
1687 * Get a list of all available Field types.
1688 *
1689 * @return string[] List of Field types.
1690 *
1691 * @since 2.8.0
1692 */
1693 public static function field_types_list() {
1694 $field_types = [
1695 'text',
1696 'website',
1697 // 'link',
1698 'phone',
1699 'email',
1700 'password',
1701 'paragraph',
1702 'wysiwyg',
1703 'code',
1704 'datetime',
1705 'date',
1706 'time',
1707 'number',
1708 'currency',
1709 'file',
1710 'avatar',
1711 'oembed',
1712 'pick',
1713 'boolean',
1714 'color',
1715 'slug',
1716 'heading',
1717 'html',
1718 ];
1719
1720 $field_types = array_merge( $field_types, array_keys( self::$field_types ) );
1721
1722 $field_types = array_filter( array_unique( $field_types ) );
1723
1724 return apply_filters( 'pods_api_field_types', $field_types );
1725 }
1726
1727 /**
1728 * Get a list of all available field types and include
1729 *
1730 * @return array Registered Field Types data
1731 *
1732 * @since 2.3.0
1733 */
1734 public static function field_types() {
1735
1736 $types = self::field_types_list();
1737
1738 $field_types = pods_transient_get( 'pods_field_types' );
1739
1740 if ( empty( $field_types ) || count( $types ) != count( $field_types ) ) {
1741 $field_types = array();
1742
1743 foreach ( $types as $field_type ) {
1744 $file = null;
1745
1746 if ( isset( self::$field_types[ $field_type ] ) ) {
1747 $file = self::$field_types[ $field_type ]['file'];
1748 }
1749
1750 self::field_loader( $field_type, $file );
1751
1752 if ( ! isset( self::$loaded[ $field_type ] ) || ! is_object( self::$loaded[ $field_type ] ) ) {
1753 continue;
1754 }
1755
1756 $class_vars = get_class_vars( get_class( self::$loaded[ $field_type ] ) );
1757 // PHP 5.2.x workaround
1758 $field_types[ $field_type ] = $class_vars;
1759 $field_types[ $field_type ]['file'] = $file;
1760 }
1761
1762 self::$field_types = $field_types;
1763
1764 pods_transient_set( 'pods_field_types', self::$field_types, WEEK_IN_SECONDS );
1765 } else {
1766 self::$field_types = array_merge( $field_types, self::$field_types );
1767 }//end if
1768
1769 return self::$field_types;
1770 }
1771
1772 /**
1773 * Get the list of available tableless field types.
1774 *
1775 * @since 2.3.0
1776 *
1777 * @return array The list of available tableless field types.
1778 */
1779 public static function tableless_field_types() {
1780 static $field_types = null;
1781
1782 if ( null === $field_types ) {
1783 $field_types = [
1784 'pick',
1785 'file',
1786 'avatar',
1787 'taxonomy',
1788 'comment',
1789 'author',
1790 ];
1791
1792 $field_types = apply_filters( 'pods_tableless_field_types', $field_types );
1793 }
1794
1795 return $field_types;
1796 }
1797
1798 /**
1799 * Get the list of available file field types.
1800 *
1801 * @since 2.3.0
1802 *
1803 * @return array The list of available file field types.
1804 */
1805 public static function file_field_types() {
1806 static $field_types = null;
1807
1808 if ( null === $field_types ) {
1809 $field_types = [
1810 'file',
1811 'avatar',
1812 ];
1813
1814 $field_types = apply_filters( 'pods_file_field_types', $field_types );
1815 }
1816
1817 return $field_types;
1818 }
1819
1820 /**
1821 * Get the list of available repeatable field types.
1822 *
1823 * @since 2.3.0
1824 *
1825 * @return array The list of available repeatable field types.
1826 */
1827 public static function repeatable_field_types() {
1828 static $field_types = null;
1829
1830 if ( null === $field_types ) {
1831 $field_types = [
1832 'color',
1833 'currency',
1834 'date',
1835 'datetime',
1836 'email',
1837 'number',
1838 'oembed',
1839 'paragraph',
1840 'password',
1841 'phone',
1842 'text',
1843 'time',
1844 'website',
1845 'wysiwyg',
1846 ];
1847
1848 $field_types = (array) apply_filters( 'pods_repeatable_field_types', $field_types );
1849 }
1850
1851 return $field_types;
1852 }
1853
1854 /**
1855 * Get the list of available number field types.
1856 *
1857 * @since 2.3.0
1858 *
1859 * @return array The list of available number field types.
1860 */
1861 public static function number_field_types() {
1862 static $field_types = null;
1863
1864 if ( null === $field_types ) {
1865 $field_types = [
1866 'currency',
1867 'number',
1868 ];
1869
1870 $field_types = apply_filters( 'pods_tableless_field_types', $field_types );
1871 }
1872
1873 return $field_types;
1874 }
1875
1876 /**
1877 * Get the list of available date field types.
1878 *
1879 * @since 2.3.0
1880 *
1881 * @return array The list of available date field types.
1882 */
1883 public static function date_field_types() {
1884 static $field_types = null;
1885
1886 if ( null === $field_types ) {
1887 $field_types = [
1888 'date',
1889 'datetime',
1890 'time',
1891 ];
1892
1893 $field_types = apply_filters( 'pods_tableless_field_types', $field_types );
1894 }
1895
1896 return $field_types;
1897 }
1898
1899 /**
1900 * Get the list of available text field types.
1901 *
1902 * @since 2.3.0
1903 *
1904 * @return array The list of available text field types.
1905 */
1906 public static function text_field_types() {
1907 static $field_types = null;
1908
1909 if ( null === $field_types ) {
1910 $field_types = [
1911 'code',
1912 'paragraph',
1913 'slug',
1914 'password',
1915 'text',
1916 'wysiwyg',
1917 ];
1918
1919 $field_types = apply_filters( 'pods_text_field_types', $field_types );
1920 }
1921
1922 return $field_types;
1923 }
1924
1925 /**
1926 * Get the list of available Layout field types (backwards compatible version).
1927 *
1928 * @since 2.3.0
1929 *
1930 * @deprecated since 2.3.0
1931 * @see PodsForm::layout_field_types()
1932 *
1933 * @return array The list of available Layout field types.
1934 */
1935 public static function block_field_types() {
1936 _doing_it_wrong( 'PodsForm::layout_field_types', 'This function is deprecated, use PodsForm::layout_field_types instead.', '2.8.0' );
1937
1938 return self::layout_field_types();
1939 }
1940
1941 /**
1942 * Get the list of available Layout field types.
1943 *
1944 * @since 2.8.0
1945 *
1946 * @return array The list of available Layout field types.
1947 */
1948 public static function layout_field_types() {
1949 static $field_types = null;
1950
1951 if ( null === $field_types ) {
1952 $field_types = [
1953 'heading',
1954 'html',
1955 ];
1956
1957 /**
1958 * Allow filtering of the list of Layout field types.
1959 *
1960 * @since 2.8.0
1961 *
1962 * @param array $field_types The list of Layout field types.
1963 */
1964 $field_types = apply_filters( 'pods_layout_field_types', $field_types );
1965 }
1966
1967 return $field_types;
1968 }
1969
1970 /**
1971 * Get the list of available Non-Input field types.
1972 *
1973 * @since 2.8.0
1974 *
1975 * @return array The list of available Non-Input field types.
1976 */
1977 public static function non_input_field_types() {
1978 static $field_types = null;
1979
1980 if ( null === $field_types ) {
1981 $field_types = [
1982 'internal',
1983 ];
1984
1985 /**
1986 * Allow filtering of the list of Non-Input field types.
1987 *
1988 * @since 2.8.0
1989 *
1990 * @param array $field_types The list of Non-Input field types.
1991 */
1992 $field_types = apply_filters( 'pods_non_input_field_types', $field_types );
1993 }
1994
1995 return $field_types;
1996 }
1997
1998 /**
1999 * Get the list of field types that do not use serial comma separators.
2000 *
2001 * @since 2.9.4
2002 *
2003 * @return array The list of field types that do not use serial comma separators.
2004 */
2005 public static function separator_excluded_field_types() {
2006 static $field_types = null;
2007
2008 if ( null === $field_types ) {
2009 $field_types = [
2010 'avatar',
2011 'code',
2012 'link',
2013 'oembed',
2014 'paragraph',
2015 'website',
2016 'wysiwyg',
2017 ];
2018
2019 /**
2020 * Allow filtering of the list of field types that do not use serial comma separators.
2021 *
2022 * @since 2.8.0
2023 *
2024 * @param array $field_types The list of field types that do not use serial comma separators.
2025 */
2026 $field_types = apply_filters( 'pods_separator_excluded_field_types', $field_types );
2027 }
2028
2029 return $field_types;
2030 }
2031
2032 /**
2033 * Get the list of revisionable field types.
2034 *
2035 * @since 3.2.0
2036 *
2037 * @return array The list of revisionable field types.
2038 */
2039 public static function revisionable_field_types(): array {
2040 $revisionable_field_types = pods_static_cache_get( __FUNCTION__, __CLASS__ );
2041
2042 if ( ! is_array( $revisionable_field_types ) ) {
2043 $revisionable_field_types = [];
2044 }
2045
2046 if ( $revisionable_field_types ) {
2047 return $revisionable_field_types;
2048 }
2049
2050 $field_types = static::field_types_list();
2051 $tableless_field_types = static::tableless_field_types();
2052 $layout_field_types = static::layout_field_types();
2053
2054 foreach ( $field_types as $field_type ) {
2055 if (
2056 in_array( $field_type, $tableless_field_types, true )
2057 || in_array( $field_type, $layout_field_types, true )
2058 ) {
2059 continue;
2060 }
2061
2062 $revisionable_field_types[] = $field_type;
2063 }
2064
2065 /**
2066 * Allow filtering of the list of field types that can be revisioned.
2067 *
2068 * @since 3.2.0
2069 *
2070 * @param array $revisionable_field_types The listof field types that can be revisioned.
2071 */
2072 $revisionable_field_types = apply_filters( 'pods_form_revisionable_field_types', $revisionable_field_types );
2073
2074 pods_static_cache_set( __FUNCTION__, $revisionable_field_types, __CLASS__ );
2075
2076 return $revisionable_field_types;
2077 }
2078
2079 /**
2080 * Get the list of simple tableless objects.
2081 *
2082 * @since 2.3.0
2083 *
2084 * @return array The list of simple tableless objects.
2085 */
2086 public static function simple_tableless_objects() {
2087
2088 static $object_types = null;
2089
2090 if ( null === $object_types ) {
2091 $object_types = self::field_method( 'pick', 'simple_objects' );
2092 }
2093
2094 return $object_types;
2095 }
2096
2097 /**
2098 * Render the postbox header in a compatible way.
2099 *
2100 * @since 2.7.22
2101 *
2102 * @param string $title Header title.
2103 */
2104 public static function render_postbox_header( $title ) {
2105 pods_view( PODS_DIR . 'ui/admin/postbox-header.php', compact( array_keys( get_defined_vars() ) ) );
2106 }
2107 }
2108