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