Completed
Pull Request — 2.x (#3260)
by Phil
05:44
created

PodsForm::__clone()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
/**
3
 * @package Pods
4
 */
5
class PodsForm {
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
6
7
    /**
8
     * @var PodsForm
9
     */
10
    protected static $instance = null;
11
12
    /**
13
     * @var string
14
     */
15
    static $field = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $field.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
16
17
    /**
18
     * @var string
19
     */
20
    static $field_group = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $field_group.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
21
22
    /**
23
     * @var string
24
     */
25
    static $field_type = null;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $field_type.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
26
27
    /**
28
     * @var array
29
     */
30
    static $field_types = array();
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $field_types.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
31
32
    /**
33
     * @var array
34
     */
35
    static $loaded = array();
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $loaded.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
36
37
    /**
38
     * @var int
39
     */
40
    static $form_counter = 0;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $form_counter.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
41
42
    /**
43
     * Singleton handling for a basic pods_form() request
44
     *
45
     * @return \PodsForm
46
     *
47
     * @since 2.3.5
48
     */
49
    public static function init () {
50
        if ( !is_object( self::$instance ) )
51
            self::$instance = new PodsForm();
52
53
        return self::$instance;
54
    }
55
56
    /**
57
     * Master handler for all field / form methods
58
     *
59
     * @return \PodsForm
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

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

Please refer to the PHP core documentation on constructors.

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

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

Loading history...
219
        elseif ( method_exists( get_class(), 'field_' . $type ) )
220
            echo call_user_func( array( get_class(), 'field_' . $type ), $name, $value, $options );
221
        elseif ( is_object( self::$loaded[ $type ] ) && method_exists( self::$loaded[ $type ], 'input' ) )
222
            self::$loaded[ $type ]->input( $name, $value, $options, $pod, $id );
223
        else
224
            do_action( 'pods_form_ui_field_' . $type, $name, $value, $options, $pod, $id );
225
226
        $output = ob_get_clean();
227
228
        return apply_filters( 'pods_form_ui_field_' . $type, $output, $name, $value, $options, $pod, $id );
229
    }
230
231
    /**
232
     * Output a flexible relationship button
233
     *
234
     * @todo  : support other content types
235
     * @todo  : replace thickbox
236
     *
237
     * @param array $field Field options array
238
     *
239
     * @param int   $item_id
240
     *
241
     * @return string Button HTML
242
     *
243
     * @since 2.7
244
     */
245
    public static function flex_relationship( $field, $item_id ) {
246
247
        $output = '';
248
249
        // Early exit if any of:
250
        //  * Not admin
251
        //  * this isn't a flexible relationship enabled field
252
        //  * we're already in a modal
253
        if ( ! is_admin() || 'pick' != $field[ 'type' ] || empty( $field[ 'pick_flexible' ] ) || pods_is_modal_window() ) {
254
            return $output;
255
        }
256
257
        // Set the file name and args based on the content type of the relationship
258
        switch ( $field[ 'pick_object' ] ) {
259
            case 'post_type':
260
                $file_name = 'post-new.php';
261
                $query_args = array(
262
                    'post_type' => $field[ 'pick_val' ],
263
                );
264
                break;
265
266
            case 'taxonomy':
267
                $file_name = 'edit-tags.php';
268
                $query_args = array(
269
                    'taxonomy' => $field[ 'pick_val' ],
270
                );
271
                break;
272
273
            case 'user':
274
                $file_name = 'user-new.php';
275
                $query_args = array();
276
                break;
277
278
            case 'pod':
279
                $file_name = 'admin.php';
280
                $query_args = array(
281
                    'page'   => 'pods-manage-' . $field[ 'pick_val' ],
282
                    'action' => 'add'
283
                );
284
                break;
285
286
            // Something unsupported
287
            default:
288
                return $output;
289
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
290
        }
291
292
        // Add args we always need
293
        $query_args = array_merge(
294
            $query_args,
295
            array(
296
                'pods_modal' => '1', // @todo: Replace string literal with defined constant
297
                'TB_iframe'  => 'true',
298
                'width'      => '1000',
299
                'height'     => '798',
300
            )
301
        );
302
303
        // Assemble the URL
304
        $url = add_query_arg( $query_args, admin_url( $file_name ) );
305
306
        ob_start();
307
308
        ?>
309
        <div class="podsform-flex-relationship-container">
310
	        <a href="<?php echo esc_url( $url ); ?>"
311
	            id="pods-related-edit-<?php echo esc_attr( $field[ 'name' ] ); ?>"
312
	            class="button pods-related-edit"
313
	            data-pod-id="<?php echo esc_attr( $field[ 'pod_id' ] ); ?>"
314
	            data-field-id="<?php echo esc_attr( $field[ 'id' ] ); ?>"
315
	            data-item-id="<?php echo esc_attr( $item_id ); ?>">
316
		        Add New
317
	        </a>
318
	    </div>
319
        <?php
320
321
        $output = ob_get_clean();
322
323
        // @todo: add a filter
324
        return $output;
325
    }
326
327
    /**
328
     * Output field type 'db'
329
     *
330
     * Used for field names and other places where only [a-z0-9_] is accepted
331
     *
332
     * @since 2.0
333
     */
334 View Code Duplication
    protected static function field_db( $name, $value = null, $options = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
335
        $form_field_type = self::$field_type;
336
337
        ob_start();
338
339
        pods_view( PODS_DIR . 'ui/fields/_db.php', compact( array_keys( get_defined_vars() ) ) );
340
341
        $output = ob_get_clean();
342
343
        return apply_filters( 'pods_form_ui_field_db', $output, $name, $value, $options );
344
    }
345
346
    /**
347
     * Output a hidden field
348
     */
349 View Code Duplication
    protected static function field_hidden( $name, $value = null, $options = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
350
        $form_field_type = self::$field_type;
351
352
        ob_start();
353
354
        pods_view( PODS_DIR . 'ui/fields/_hidden.php', compact( array_keys( get_defined_vars() ) ) );
355
356
        $output = ob_get_clean();
357
358
        return apply_filters( 'pods_form_ui_field_hidden', $output, $name, $value, $options );
359
    }
360
361
	/**
362
	 * Returns a submit button, with provided text and appropriate class, copied from WP Core for use on the frontend
363
	 *
364
	 * @see get_submit_button
365
	 *
366
	 * @param string $text The text of the button (defaults to 'Save Changes')
367
	 * @param string $type The type of button. One of: primary, secondary, delete
368
	 * @param string $name The HTML name of the submit button. Defaults to "submit". If no id attribute
369
	 *               is given in $other_attributes below, $name will be used as the button's id.
370
	 * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
371
	 * 			   false otherwise. Defaults to true
372
	 * @param array|string $other_attributes Other attributes that should be output with the button,
373
	 *                     mapping attributes to their values, such as array( 'tabindex' => '1' ).
374
	 *                     These attributes will be output as attribute="value", such as tabindex="1".
375
	 *                     Defaults to no other attributes. Other attributes can also be provided as a
376
	 *                     string such as 'tabindex="1"', though the array format is typically cleaner.
377
	 *
378
	 * @since 3.0
379
	 */
380
	public static function submit_button( $text = null, $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = null ) {
381
382
		if ( function_exists( 'get_submit_button' ) ) {
383
			return get_submit_button( $text, $type, $name, $wrap, $other_attributes );
384
		}
385
386
		if ( !is_array( $type ) ) {
387
			$type = explode( ' ', $type );
388
		}
389
390
		$button_shorthand = array(
391
			'primary',
392
			'small',
393
			'large'
394
		);
395
396
		$classes = array(
397
			'button'
398
		);
399
400
		foreach ( $type as $t ) {
401
			if ( 'secondary' === $t || 'button-secondary' === $t ) {
402
				continue;
403
			}
404
405
			$classes[] = in_array( $t, $button_shorthand ) ? 'button-' . $t : $t;
406
		}
407
408
		$class = implode( ' ', array_unique( $classes ) );
409
410
		if ( 'delete' === $type ) {
411
			$class = 'button-secondary delete';
412
		}
413
414
		$text = $text ? $text : __( 'Save Changes' );
415
416
		// Default the id attribute to $name unless an id was specifically provided in $other_attributes
417
		$id = $name;
418
419
		if ( is_array( $other_attributes ) && isset( $other_attributes[ 'id' ] ) ) {
420
			$id = $other_attributes[ 'id' ];
421
			unset( $other_attributes[ 'id' ] );
422
		}
423
424
		$attributes = '';
425
426
		if ( is_array( $other_attributes ) ) {
427
			foreach ( $other_attributes as $attribute => $value ) {
428
				$attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important
429
			}
430
		}
431
		elseif ( !empty( $other_attributes ) ) { // Attributes provided as a string
432
			$attributes = $other_attributes;
433
		}
434
435
		$button = '<input type="submit" name="' . esc_attr( $name ) . '" id="' . esc_attr( $id ) . '" class="' . esc_attr( $class );
436
		$button .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
437
438
		if ( $wrap ) {
439
			$button = '<p class="submit">' . $button . '</p>';
440
		}
441
442
		return $button;
443
444
	}
445
446
    /**
447
     * Output a row (label, field, and comment)
448
     *
449
     * @param string $name Field name
450
     * @param mixed $value Field value
451
     * @param string $type Field type
452
     * @param array $options Field options
453
     * @param array $pod Pod data
454
     * @param int $id Item ID
455
     *
456
     * @return string Row HTML
457
     *
458
     * @since 2.0
459
     */
460
    public static function row( $name, $value, $type = 'text', $options = null, $pod = null, $id = null ) {
461
        $options = self::options( null, $options );
462
463
        ob_start();
464
465
        pods_view( PODS_DIR . 'ui/fields/_row.php', compact( array_keys( get_defined_vars() ) ) );
466
467
        $output = ob_get_clean();
468
469
        return apply_filters( 'pods_form_ui_field_row', $output, $name, $value, $options, $pod, $id );
470
    }
471
472
    /**
473
     * Output a field's attributes
474
     *
475
     * @since 2.0
476
     */
477
    public static function attributes( $attributes, $name = null, $type = null, $options = null ) {
478
        $attributes = (array) apply_filters( 'pods_form_ui_field_' . $type . '_attributes', $attributes, $name, $options );
479
480
        foreach ( $attributes as $attribute => $value ) {
481
            if ( null === $value )
482
                continue;
483
484
            echo ' ' . esc_attr( (string) $attribute ) . '="' . esc_attr( (string) $value ) . '"';
485
        }
486
    }
487
488
    /**
489
     * Output a field's data (for use with jQuery)
490
     *
491
     * @since 2.0
492
     */
493
    public static function data( $data, $name = null, $type = null, $options = null ) {
494
        $data = (array) apply_filters( 'pods_form_ui_field_' . $type . '_data', $data, $name, $options );
495
496
        foreach ( $data as $key => $value ) {
497
            if ( null === $value )
498
                continue;
499
500
            $key = sanitize_title( $key );
501
502
            if ( is_array( $value ) )
503
                $value = implode( ',', $value );
504
505
            echo ' data-' . esc_attr( (string) $key ) . '="' . esc_attr( (string) $value ) . '"';
506
        }
507
    }
508
509
    /**
510
     * Merge attributes and handle classes
511
     *
512
     * @since 2.0
513
     */
514
    public static function merge_attributes( $attributes, $name = null, $type = null, $options = null, $classes = '' ) {
515
        $options = (array) $options;
516
517
        if ( !in_array( $type, array( 'label', 'comment' ) ) ) {
518
            $name_clean = self::clean( $name );
519
            $name_more_clean = self::clean( $name, true );
520
            $_attributes = array();
521
            $_attributes[ 'name' ] = $name;
522
            $_attributes[ 'data-name-clean' ] = $name_more_clean;
523
524
            if ( 0 < strlen( pods_v( 'label', $options, '' ) ) )
525
                $_attributes[ 'data-label' ] = strip_tags( pods_v( 'label', $options ) );
526
527
            $_attributes[ 'id' ] = 'pods-form-ui-' . $name_clean;
528
            $_attributes[ 'class' ] = 'pods-form-ui-field-type-' . $type . ' pods-form-ui-field-name-' . $name_more_clean;
529
530
            if ( isset( $options[ 'dependency' ] ) && false !== $options[ 'dependency' ] )
531
                $_attributes[ 'class' ] .= ' pods-dependent-toggle';
532
533
            $attributes = array_merge( $_attributes, (array) $attributes );
534
535 View Code Duplication
            if ( isset( $options[ 'attributes' ] ) && is_array( $options[ 'attributes' ] ) && !empty( $options[ 'attributes' ] ) )
536
                $attributes = array_merge( $attributes, $options[ 'attributes' ] );
537
        }
538
        elseif ( isset( $options[ $type . '_attributes' ] ) && is_array( $options[ $type . '_attributes' ] ) && !empty( $options[ $type . '_attributes' ] ) )
539
            $attributes = array_merge( $attributes, $options[ $type . '_attributes' ] );
540
541
        if ( isset( $options[ 'class' ] ) && !empty( $options[ 'class' ] ) ) {
542
            if ( is_array( $options[ 'class' ] ) )
543
                $options[ 'class' ] = implode( ' ', $options[ 'class' ] );
544
545
            $options[ 'class' ] = (string) $options[ 'class' ];
546 View Code Duplication
            if ( isset( $attributes[ 'class' ] ) )
547
                $attributes[ 'class' ] = $attributes[ 'class' ] . ' ' . $options[ 'class' ];
548
            else
549
                $attributes[ 'class' ] = $options[ 'class' ];
550
551
            $attributes[ 'class' ] = trim( $attributes[ 'class' ] );
552
        }
553
554
        if ( !empty( $classes ) ) {
555 View Code Duplication
            if ( isset( $attributes[ 'class' ] ) )
556
                $attributes[ 'class' ] = $attributes[ 'class' ] . ' ' . $classes;
557
            else
558
                $attributes[ 'class' ] = $classes;
559
        }
560
561
        if ( isset( $options[ 'placeholder' ] ) && !empty( $options[ 'placeholder' ] ) ) {
562
            if ( is_array( $options[ 'placeholder' ] ) )
563
                $options[ 'placeholder' ] = implode( ' ', $options[ 'placeholder' ] );
564
565
            $options[ 'placeholder' ] = (string) $options[ 'placeholder' ];
566
			$attributes[ 'placeholder' ] = trim( $options[ 'placeholder' ] );
567
        }
568
569
        if ( 1 == pods_v( 'required', $options, 0 ) )
570
            $attributes[ 'class' ] .= ' pods-validate pods-validate-required';
571
572
        $max_length = (int) pods_var( 'maxlength', $options, pods_v( $type . '_max_length', $options, 0 ), null, true );
573
574
        if ( 0 < $max_length )
575
            $attributes[ 'maxlength' ] = $max_length;
576
577
        $attributes = (array) apply_filters( 'pods_form_ui_field_' . $type . '_merge_attributes', $attributes, $name, $options );
578
        return $attributes;
579
    }
580
581
    /**
582
     * Setup options for a field and store them for later use
583
     *
584
     * @param $type
585
     * @param $options
586
     *
587
     * @return array
588
     *
589
     * @static
590
     *
591
     * @since 2.0
592
     */
593
    public static function options( $type, $options ) {
594
        $options = (array) $options;
595
596
        if ( !is_object( $options ) && isset( $options[ 'options' ] ) ) {
597
            $options_temp = $options[ 'options' ];
598
599
            unset( $options[ 'options' ] );
600
601
            $options = array_merge( $options_temp, $options );
602
603
            $override = array(
604
                'class'
605
            );
606
607
            foreach ( $override as $check ) {
608
                if ( isset( $options_temp[ $check ] ) )
609
                    $options[ $check ] = $options_temp[ $check ];
610
            }
611
        }
612
613
        $defaults = self::options_setup( $type, $options );
614
615
        $core_defaults = array(
616
            'id' => 0,
617
            'label' => '',
618
            'description' => '',
619
            'help' => '',
620
            'default' => null,
621
            'attributes' => array(),
622
            'class' => '',
623
            'grouped' => 0,
624
        );
625
626
        $defaults = array_merge( $core_defaults, $defaults );
627
628
        foreach ( $defaults as $option => $settings ) {
629
            $default = $settings;
630
631
            if ( is_array( $settings ) && isset( $settings[ 'default' ] ) )
632
                $default = $settings[ 'default' ];
633
634
            if ( !isset( $options[ $option ] ) )
635
                $options[ $option ] = $default;
636
        }
637
638
        return $options;
639
    }
640
641
    /**
642
     * Get options for a field type and setup defaults
643
     *
644
     * @static
645
     *
646
     * @param $type
647
     *
648
     * @return array|null
649
     *
650
     * @since 2.0
651
     */
652
    public static function options_setup( $type = null, $options = null ) {
653
        $core_defaults = array(
654
            'id' => 0,
655
            'name' => '',
656
            'label' => '',
657
            'description' => '',
658
            'help' => '',
659
            'default' => null,
660
            'attributes' => array(),
661
            'class' => '',
662
            'type' => 'text',
663
            'group' => 0,
664
            'grouped' => 0,
665
            'developer_mode' => false,
666
            'dependency' => false,
667
            'depends-on' => array(),
668
            'excludes-on' => array(),
669
            'options' => array()
670
        );
671
672
        if ( !empty( $options ) && is_array( $options ) )
673
            $core_defaults = array_merge( $core_defaults, $options );
674
675
        if ( null === $type )
676
            return $core_defaults;
677
        else
678
            self::field_loader( $type );
679
680
        $options = apply_filters( 'pods_field_' . $type . '_options', (array) self::$loaded[ $type ]->options(), $type );
681
682
        $first_field = current( $options );
683
684
        if ( !empty( $options ) && !isset( $first_field[ 'name' ] ) && !isset( $first_field[ 'label' ] ) ) {
685
            $all_options = array();
686
687
            foreach ( $options as $group => $group_options ) {
688
                $all_options = array_merge( $all_options, self::fields_setup( $group_options, $core_defaults ) );
689
            }
690
691
            $options = $all_options;
692
        }
693
        else
694
            $options = self::fields_setup( $options, $core_defaults );
695
696
        return $options;
697
    }
698
699
    /**
700
     * Get Admin options for a field type and setup defaults
701
     *
702
     * @static
703
     *
704
     * @param $type
705
     *
706
     * @return array|null
707
     *
708
     * @since 2.0
709
     */
710
    public static function ui_options( $type ) {
711
        $core_defaults = array(
712
            'id' => 0,
713
            'name' => '',
714
            'label' => '',
715
            'description' => '',
716
            'help' => '',
717
            'default' => null,
718
            'attributes' => array(),
719
            'class' => '',
720
            'type' => 'text',
721
            'group' => 0,
722
            'grouped' => 0,
723
            'developer_mode' => false,
724
            'dependency' => false,
725
            'depends-on' => array(),
726
            'excludes-on' => array(),
727
            'options' => array()
728
        );
729
730
        self::field_loader( $type );
731
732
        $options = apply_filters( 'pods_field_' . $type . '_ui_options', (array) self::$loaded[ $type ]->ui_options(), $type );
733
734
        $first_field = current( $options );
735
736
        if ( !empty( $options ) && !isset( $first_field[ 'name' ] ) && !isset( $first_field[ 'label' ] ) ) {
737
            foreach ( $options as $group => $group_options ) {
738
                $options[ $group ] = self::fields_setup( $group_options, $core_defaults );
739
            }
740
        }
741
        else
742
            $options = self::fields_setup( $options, $core_defaults );
743
744
        return $options;
745
    }
746
747
    /**
748
     * Get options for a field and setup defaults
749
     *
750
     *
751
     * @param null $fields
752
     * @param null $core_defaults
753
     * @param bool $single
754
     *
755
     * @return array|null
756
     *
757
     * @static
758
     * @since 2.0
759
     */
760
    public static function fields_setup( $fields = null, $core_defaults = null, $single = false ) {
761
        if ( empty( $core_defaults ) ) {
762
            $core_defaults = array(
763
                'id' => 0,
764
                'name' => '',
765
                'label' => '',
766
                'description' => '',
767
                'help' => '',
768
                'default' => null,
769
                'attributes' => array(),
770
                'class' => '',
771
                'type' => 'text',
772
                'group' => 0,
773
                'grouped' => 0,
774
                'developer_mode' => false,
775
                'dependency' => false,
776
                'depends-on' => array(),
777
                'excludes-on' => array(),
778
                'options' => array()
779
            );
780
        }
781
782
        if ( $single )
783
            $fields = array( $fields );
784
785
        foreach ( $fields as $f => $field ) {
0 ignored issues
show
Bug introduced by
The expression $fields of type array<integer,null,{"0":"null"}>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

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

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

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

Loading history...
786
            $fields[ $f ] = self::field_setup( $field, $core_defaults, pods_v( 'type', $field, 'text' ) );
787
788
            if ( !$single && strlen( $fields[ $f ][ 'name' ] ) < 1 )
789
                $fields[ $f ][ 'name' ] = $f;
790
        }
791
792
        if ( $single )
793
            $fields = $fields[ 0 ];
794
795
        return $fields;
796
    }
797
798
    /**
799
     * Get options for a field and setup defaults
800
     *
801
     * @static
802
     *
803
     * @param null $field
804
     * @param null $core_defaults
805
     * @param null $type
806
     *
807
     * @return array|null
808
     *
809
     * @since 2.0
810
     */
811
    public static function field_setup( $field = null, $core_defaults = null, $type = null ) {
812
        $options = array();
813
814
        if ( empty( $core_defaults ) ) {
815
            $core_defaults = array(
816
                'id' => 0,
817
                'name' => '',
818
                'label' => '',
819
                'description' => '',
820
                'help' => '',
821
                'default' => null,
822
                'attributes' => array(),
823
                'class' => '',
824
                'type' => 'text',
825
                'group' => 0,
826
                'grouped' => 0,
827
                'developer_mode' => false,
828
                'dependency' => false,
829
                'depends-on' => array(),
830
                'excludes-on' => array(),
831
                'options' => array()
832
            );
833
834
            if ( null !== $type ) {
835
                self::field_loader( $type );
836
837
                if ( method_exists( self::$loaded[ $type ], 'options' ) )
838
                    $options = apply_filters( 'pods_field_' . $type . '_options', (array) self::$loaded[ $type ]->options(), $type );
839
            }
840
        }
841
842
        if ( !is_array( $field ) )
843
            $field = array( 'default' => $field );
844
845
        if ( isset( $field[ 'group' ] ) && is_array( $field[ 'group' ] ) ) {
846
            foreach ( $field[ 'group' ] as $g => $group_option ) {
847
                $field[ 'group' ][ $g ] = array_merge( $core_defaults, $group_option );
848
849
                if ( strlen( $field[ 'group' ][ $g ][ 'name' ] ) < 1 )
850
                    $field[ 'group' ][ $g ][ 'name' ] = $g;
851
            }
852
        }
853
854
        $field = array_merge( $core_defaults, $field );
855
856
        foreach ( $options as $option => $settings ) {
857
            $v = null;
858
859
            if ( isset( $settings[ 'default' ] ) )
860
                $v = $settings[ 'default' ];
861
862
            if ( !isset( $field[ 'options' ][ $option ] ) )
863
                $field[ 'options' ][ $option ] = $v;
864
        }
865
866
        return $field;
867
    }
868
869
    /**
870
     * Setup dependency / exclusion classes
871
     *
872
     * @param array $options array( 'depends-on' => ..., 'excludes-on' => ...)
873
     * @param string $prefix
874
     *
875
     * @return string
876
     * @static
877
     * @since 2.0
878
     */
879
    public static function dependencies( $options, $prefix = '' ) {
880
        $options = (array) $options;
881
882
        $depends_on = $excludes_on = array();
883
        if ( isset( $options[ 'depends-on' ] ) )
884
            $depends_on = (array) $options[ 'depends-on' ];
885
886
        if ( isset( $options[ 'excludes-on' ] ) )
887
            $excludes_on = (array) $options[ 'excludes-on' ];
888
889
        $classes = array();
890
891 View Code Duplication
        if ( !empty( $depends_on ) ) {
892
            $classes[] = 'pods-depends-on';
893
894
            foreach ( $depends_on as $depends => $on ) {
895
                $classes[] = 'pods-depends-on-' . $prefix . self::clean( $depends, true );
896
897
                if ( !is_bool( $on ) ) {
898
                    $on = (array) $on;
899
900
                    foreach ( $on as $o ) {
901
                        $classes[] = 'pods-depends-on-' . $prefix . self::clean( $depends, true ) . '-' . self::clean( $o, true );
902
                    }
903
                }
904
            }
905
        }
906
907 View Code Duplication
        if ( !empty( $excludes_on ) ) {
908
            $classes[] = 'pods-excludes-on';
909
            foreach ( $excludes_on as $excludes => $on ) {
910
                $classes[] = 'pods-excludes-on-' . $prefix . self::clean( $excludes, true );
911
912
                $on = (array) $on;
913
914
                foreach ( $on as $o ) {
915
                    $classes[] = 'pods-excludes-on-' . $prefix . self::clean( $excludes, true ) . '-' . self::clean( $o, true );
916
                }
917
            }
918
        }
919
920
        $classes = implode( ' ', $classes );
921
922
        return $classes;
923
    }
924
925
    /**
926
     * Change the value of the field
927
     *
928
     * @param mixed $value
929
     * @param string $name
930
     * @param array $options
931
     * @param array $fields
0 ignored issues
show
Bug introduced by
There is no parameter named $fields. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
932
     * @param array $pod
933
     * @param int $id
934
     * @param array $traverse
935
     *
936
     * @since 2.3
937
     */
938
    public static function value( $type, $value = null, $name = null, $options = null, $pod = null, $id = null, $traverse = null ) {
939
        self::field_loader( $type );
940
941
        if ( in_array( $type, self::repeatable_field_types() ) && 1 == pods_v( $type . '_repeatable', $options, 0 ) && !is_array( $value ) ) {
942
            if ( 0 < strlen( $value ) ) {
943
                $simple = @json_decode( $value, true );
1 ignored issue
show
Unused Code introduced by
The call to json_decode() has too many arguments starting with true.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
944
945
                if ( is_array( $simple ) )
946
                    $value = $simple;
947
                else
948
                    $value = (array) $value;
949
            }
950
            else
951
                $value = array();
952
        }
953
954
        if ( method_exists( self::$loaded[ $type ], 'value' ) ) {
955
            if ( is_array( $value ) && in_array( $type, self::tableless_field_types() ) ) {
956 View Code Duplication
                foreach ( $value as &$display_value ) {
957
                    $display_value = call_user_func_array( array( self::$loaded[ $type ], 'value' ), array( $display_value, $name, $options, $pod, $id, $traverse ) );
958
                }
959
            }
960 View Code Duplication
            else
961
                $value = call_user_func_array( array( self::$loaded[ $type ], 'value' ), array( $value, $name, $options, $pod, $id, $traverse ) );
962
        }
963
964
        return $value;
965
    }
966
967
    /**
968
     * Change the way the value of the field is displayed with Pods::get
969
     *
970
     * @param mixed $value
971
     * @param string $name
972
     * @param array $options
973
     * @param array $fields
0 ignored issues
show
Bug introduced by
There is no parameter named $fields. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
974
     * @param array $pod
975
     * @param int $id
976
     * @param array $traverse
977
     *
978
     * @since 2.0
979
     */
980
    public static function display( $type, $value = null, $name = null, $options = null, $pod = null, $id = null, $traverse = null ) {
981
        self::field_loader( $type );
982
983
        $tableless_field_types = self::tableless_field_types();
984
985
        if ( method_exists( self::$loaded[ $type ], 'display' ) ) {
986
            if ( is_array( $value ) && !in_array( $type, $tableless_field_types ) ) {
987 View Code Duplication
                foreach ( $value as $k => $display_value ) {
988
                    $value[ $k ] = call_user_func_array( array( self::$loaded[ $type ], 'display' ), array( $display_value, $name, $options, $pod, $id, $traverse ) );
989
                }
990
            }
991 View Code Duplication
            else
992
                $value = call_user_func_array( array( self::$loaded[ $type ], 'display' ), array( $value, $name, $options, $pod, $id, $traverse ) );
993
        }
994
995
        $value = apply_filters( 'pods_form_display_' . $type, $value, $name, $options, $pod, $id, $traverse );
996
997
        return $value;
998
    }
999
1000
    /**
1001
     * Setup regex for JS / PHP
1002
     *
1003
     * @static
1004
     *
1005
     * @param $type
1006
     * @param $options
1007
     *
1008
     * @return mixed|void
1009
     * @since 2.0
1010
     */
1011 View Code Duplication
    public static function regex( $type, $options ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1012
        self::field_loader( $type );
1013
1014
        $regex = false;
1015
1016
        if ( method_exists( self::$loaded[ $type ], 'regex' ) )
1017
            $regex = self::$loaded[ $type ]->regex( $options );
1018
1019
        $regex = apply_filters( 'pods_field_' . $type . '_regex', $regex, $options, $type );
1020
1021
        return $regex;
1022
    }
1023
1024
    /**
1025
     * Setup value preparation for sprintf
1026
     *
1027
     * @static
1028
     *
1029
     * @param $type
1030
     * @param $options
1031
     *
1032
     * @return mixed|void
1033
     * @since 2.0
1034
     */
1035 View Code Duplication
    public static function prepare( $type, $options ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1036
        self::field_loader( $type );
1037
1038
        $prepare = '%s';
1039
1040
        if ( method_exists( self::$loaded[ $type ], 'prepare' ) )
1041
            $prepare = self::$loaded[ $type ]->prepare( $options );
1042
1043
        $prepare = apply_filters( 'pods_field_' . $type . '_prepare', $prepare, $options, $type );
1044
1045
        return $prepare;
1046
    }
1047
1048
    /**
1049
     * Validate a value before it's saved
1050
     *
1051
     * @param string $type
1052
     * @param mixed $value
1053
     * @param string $name
1054
     * @param array $options
1055
     * @param array $fields
1056
     * @param array $pod
1057
     * @param int $id
1058
     * @param array|object $params
1059
     *
1060
     * @static
1061
     *
1062
     * @since 2.0
1063
     */
1064
    public static function validate( $type, $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
1065
        self::field_loader( $type );
1066
1067
        $validate = true;
1068
1069
        if ( 1 == pods_v( 'pre_save', $options, 1 ) && method_exists( self::$loaded[ $type ], 'validate' ) )
1070
            $validate = self::$loaded[ $type ]->validate( $value, $name, $options, $fields, $pod, $id, $params );
1071
1072
        $validate = apply_filters( 'pods_field_' . $type . '_validate', $validate, $value, $name, $options, $fields, $pod, $id, $type, $params );
1073
1074
        return $validate;
1075
    }
1076
1077
    /**
1078
     * Change the value or perform actions after validation but before saving to the DB
1079
     *
1080
     * @param string $type
1081
     * @param mixed $value
1082
     * @param int $id
1083
     * @param string $name
1084
     * @param array $options
1085
     * @param array $fields
1086
     * @param array $pod
1087
     * @param object $params
1088
     *
1089
     * @static
1090
     *
1091
     * @since 2.0
1092
     */
1093 View Code Duplication
    public static function pre_save( $type, $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1094
        self::field_loader( $type );
1095
1096
        if ( 1 == pods_v( 'field_pre_save', $options, 1 ) && method_exists( self::$loaded[ $type ], 'pre_save' ) )
1097
            $value = self::$loaded[ $type ]->pre_save( $value, $id, $name, $options, $fields, $pod, $params );
1098
1099
        return $value;
1100
    }
1101
1102
    /**
1103
     * Save the value to the DB
1104
     *
1105
     * @param string $type
1106
     * @param mixed $value
1107
     * @param int $id
1108
     * @param string $name
1109
     * @param array $options
1110
     * @param array $fields
1111
     * @param array $pod
1112
     * @param object $params
1113
     *
1114
     * @static
1115
     *
1116
     * @since 2.3
1117
     */
1118 View Code Duplication
    public static function save( $type, $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1119
        self::field_loader( $type );
1120
1121
        $saved = null;
1122
1123
        if ( 1 == pods_v( 'field_save', $options, 1 ) && method_exists( self::$loaded[ $type ], 'save' ) )
1124
            $saved = self::$loaded[ $type ]->save( $value, $id, $name, $options, $fields, $pod, $params );
1125
1126
        return $saved;
1127
    }
1128
1129
    /**
1130
     * Delete the value from the DB
1131
     *
1132
     * @param string $type
1133
     * @param int $id
1134
     * @param string $name
1135
     * @param array $options
1136
     * @param array $pod
1137
     *
1138
     * @static
1139
     *
1140
     * @since 2.3
1141
     */
1142 View Code Duplication
    public static function delete( $type, $id = null, $name = null, $options = null, $pod = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1143
        self::field_loader( $type );
1144
1145
        $deleted = null;
1146
1147
        if ( 1 == pods_v( 'field_delete', $options, 1 ) && method_exists( self::$loaded[ $type ], 'delete' ) )
1148
            $deleted = self::$loaded[ $type ]->delete( $id, $name, $options, $pod );
1149
1150
        return $deleted;
1151
    }
1152
1153
    /**
1154
     * Check if a user has permission to be editing a field
1155
     *
1156
     * @param $type
1157
     * @param null $name
1158
     * @param null $options
1159
     * @param null $fields
1160
     * @param null $pod
1161
     * @param null $id
1162
     * @param null $params
1163
     *
1164
     * @static
1165
     *
1166
     * @since 2.0
1167
     */
1168
    public static function permission( $type, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
1169
        $permission = pods_permission( $options );
1170
1171
        $permission = (boolean) apply_filters( 'pods_form_field_permission', $permission, $type, $name, $options, $fields, $pod, $id, $params );
1172
1173
        return $permission;
1174
    }
1175
1176
    /**
1177
     * Parse the default the value
1178
     *
1179
     * @since 2.0
1180
     */
1181
    public static function default_value( $value, $type = 'text', $name = null, $options = null, $pod = null, $id = null ) {
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1182
        $default_value = pods_v( 'default_value', $options );
1183
1184
		if ( '' === $default_value || null === $default_value ) {
1185
			$default_value = $value;
1186
		}
1187
1188
        $default = pods_v( 'default', $options, $default_value, true );
1189
1190
	    if ( is_string( $default ) ) {
1191
		    $default_value = str_replace( array( '{@', '}' ), '', trim( $default ) );
1192
	    }
1193
1194
        if ( $default != $default_value && 1 == (int) pods_v( 'default_evaluate_tags', $options, 1 ) )
1195
            $default = pods_evaluate_tags( $default );
1196
1197
        $default = pods_var_raw( pods_v( 'default_value_parameter', $options ), 'request', $default, null, true );
1198
1199
        if ( $default != $value )
1200
            $value = $default;
1201
1202
        if ( is_array( $value ) )
1203
            $value = pods_serial_comma( $value );
1204
1205
        return apply_filters( 'pods_form_field_default_value', $value, $default, $type, $options, $pod, $id );
1206
    }
1207
1208
    /**
1209
     * Clean a value for use in class / id
1210
     *
1211
     * @since 2.0
1212
     */
1213
    public static function clean( $input, $noarray = false, $db_field = false ) {
1214
        $input = str_replace( array( '--1', '__1' ), '00000', (string) $input );
1215
        if ( false !== $noarray )
1216
            $input = preg_replace( '/\[\d*\]/', '-', $input );
1217
        $output = str_replace( array( '[', ']' ), '-', strtolower( $input ) );
1218
        $output = preg_replace( '/([^a-z0-9\-_])/', '', $output );
1219
        $output = trim( str_replace( array( '__', '_', '--' ), '-', $output ), '-' );
1220
        $output = str_replace( '00000', '--1', $output );
1221
        if ( false !== $db_field )
1222
            $output = str_replace( '-', '_', $output );
1223
        return $output;
1224
    }
1225
1226
    /**
1227
     * Run admin_init methods for each field type
1228
     *
1229
     * @since 2.3
1230
     */
1231
    public function admin_init() {
1232
        $admin_field_types = pods_transient_get( 'pods_form_admin_init_field_types' );
1233
1234
        if ( empty( $admin_field_types ) ) {
1235
            $admin_field_types = array();
1236
1237
            $field_types = self::field_types();
1238
1239
            foreach ( $field_types as $field_type => $field_type_data ) {
1240
                $has_ajax = self::field_method( $field_type_data[ 'type' ], 'admin_init' );
1241
1242
                if ( false !== $has_ajax )
1243
                    $admin_field_types[] = $field_type;
1244
            }
1245
1246
            pods_transient_set( 'pods_form_admin_init_field_types', $admin_field_types );
1247
        }
1248
        else {
1249
            foreach ( $admin_field_types as $field_type ) {
1250
                self::field_method( $field_type, 'admin_init' );
1251
            }
1252
        }
1253
    }
1254
1255
    /**
1256
     * Autoload a Field Type's class
1257
     *
1258
     * @param string $field_type Field Type indentifier
1259
     * @param string $file The Field Type class file location
1260
     *
1261
     * @return string
1262
     * @access public
1263
     * @static
1264
     * @since 2.0
1265
     */
1266
    public static function field_loader( $field_type, $file = '' ) {
1267
        if ( isset( self::$loaded[ $field_type ] ) ) {
1268
            $class_vars = get_class_vars( get_class( self::$loaded[ $field_type ] ) ); // PHP 5.2.x workaround
1269
1270
            self::$field_group = ( isset( $class_vars[ 'group' ] ) ? $class_vars[ 'group' ] : '' );
1271
            self::$field_type = $class_vars[ 'type' ];
1272
1273
            if ( 'Unknown' != $class_vars[ 'label' ] )
1274
                return self::$loaded[ $field_type ];
1275
        }
1276
1277
        include_once PODS_DIR . 'classes/PodsField.php';
1278
1279
        $field_type = self::clean( $field_type, true, true );
1280
1281
        $class_name = ucfirst( $field_type );
1282
        $class_name = "PodsField_{$class_name}";
1283
1284
        $content_dir = realpath( WP_CONTENT_DIR );
1285
        $plugins_dir = realpath( WP_PLUGIN_DIR );
1286
        $muplugins_dir = realpath( WPMU_PLUGIN_DIR );
1287
        $abspath_dir = realpath( ABSPATH );
1288
1289
        if ( !class_exists( $class_name ) ) {
1290
            if ( isset( self::$field_types[ $field_type ] ) && !empty( self::$field_types[ $field_type ][ 'file' ] ) )
1291
                $file = realpath( self::$field_types[ $field_type ][ 'file' ] );
1292
1293
            if ( !empty( $file ) && 0 === strpos( $file, $abspath_dir ) && file_exists( $file ) )
1294
                include_once $file;
1295
            else {
1296
                $file = str_replace( '../', '', apply_filters( 'pods_form_field_include', PODS_DIR . 'classes/fields/' . basename( $field_type ) . '.php', $field_type ) );
1297
                $file = realpath( $file );
1298
1299
                if ( file_exists( $file ) && ( 0 === strpos( $file, $content_dir ) || 0 === strpos( $file, $plugins_dir ) || 0 === strpos( $file, $muplugins_dir ) || 0 === strpos( $file, $abspath_dir ) ) )
1300
                    include_once $file;
1301
            }
1302
        }
1303
1304
        if ( class_exists( $class_name ) )
1305
            $class = new $class_name();
1306
        else {
1307
            $class = new PodsField();
1308
            $class_name = 'PodsField';
1309
        }
1310
1311
        $class_vars = get_class_vars( $class_name ); // PHP 5.2.x workaround
1312
1313
        self::$field_group = ( isset( $class_vars[ 'group' ] ) ? $class_vars[ 'group' ] : '' );
1314
        self::$field_type = $class_vars[ 'type' ];
1315
1316
        self::$loaded[ $field_type ] =& $class;
1317
1318
        return self::$loaded[ $field_type ];
1319
    }
1320
1321
    /**
1322
     * Run a method from a Field Type's class
1323
     *
1324
     * @param string $field_type Field Type indentifier
0 ignored issues
show
Bug introduced by
There is no parameter named $field_type. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1325
     * @param string $method Method name
0 ignored issues
show
Bug introduced by
There is no parameter named $method. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1326
     * @param mixed $arg More arguments
0 ignored issues
show
Bug introduced by
There is no parameter named $arg. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1327
     *
1328
     * @return mixed
1329
     * @access public
1330
     * @static
1331
     * @since 2.0
1332
     */
1333
    public static function field_method() {
1334
        $args = func_get_args();
1335
1336
        if ( empty( $args ) && count( $args ) < 2 )
1337
            return false;
1338
1339
        $field_type = array_shift( $args );
1340
        $method = array_shift( $args );
1341
1342
        $class = self::field_loader( $field_type );
1343
1344
        if ( method_exists( $class, $method ) )
1345
            return call_user_func_array( array( $class, $method ), $args );
1346
1347
        return false;
1348
    }
1349
1350
    /**
1351
     * Add a new Pod field type
1352
     *
1353
     * @param string $type The new field type identifier
1354
     * @param string $file The new field type class file location
1355
     *
1356
     * @return array Field Type data
1357
     *
1358
     * @since 2.3
1359
     */
1360
    public static function register_field_type( $type, $file = null ) {
1361
        $field_type = pods_transient_get( 'pods_field_type_' . $type );
1362
1363
        if ( empty( $field_type ) || $field_type[ 'type' ] != $type || $field_type[ 'file' ] != $file ) {
1364
            self::field_loader( $type, $file );
1365
1366
            $class_vars = get_class_vars( get_class( self::$loaded[ $type ] ) ); // PHP 5.2.x workaround
1367
1368
            self::$field_types[ $type ] = $class_vars;
1369
            self::$field_types[ $type ][ 'file' ] = $file;
1370
1371
            pods_transient_set( 'pods_field_type_' . $type, self::$field_types[ $type ] );
1372
        }
1373
        else
1374
            self::$field_types[ $type ] = $field_type;
1375
1376
        return self::$field_types[ $type ];
1377
    }
1378
1379
    /**
1380
     * Get a list of all available field types and include
1381
     *
1382
     * @return array Registered Field Types data
1383
     *
1384
     * @since 2.3
1385
     */
1386
    public static function field_types() {
1387
        $field_types = array(
1388
            'text',
1389
            'website',
1390
            'phone',
1391
            'email',
1392
            'password',
1393
            'paragraph',
1394
            'wysiwyg',
1395
            'code',
1396
            'datetime',
1397
            'date',
1398
            'time',
1399
            'number',
1400
            'currency',
1401
            'file',
1402
            'avatar',
1403
            'pick',
1404
            'boolean',
1405
            'color',
1406
            'slug'
1407
        );
1408
1409
        $field_types = array_merge( $field_types, array_keys( self::$field_types ) );
1410
1411
        $field_types = array_filter( array_unique( $field_types ) );
1412
1413
        $types = apply_filters( 'pods_api_field_types', $field_types );
1414
1415
        $field_types = pods_transient_get( 'pods_field_types' );
1416
1417
        if ( empty( $field_types ) || count( $types ) != count( $field_types ) ) {
1418
            $field_types = array();
1419
1420
            foreach ( $types as $field_type ) {
1421
                $file = null;
1422
1423
                if ( isset( self::$field_types[ $field_type ] ) )
1424
                    $file = self::$field_types[ $field_type ][ 'file' ];
1425
1426
                self::field_loader( $field_type, $file );
1427
1428
                if ( !isset( self::$loaded[ $field_type ] ) || !is_object( self::$loaded[ $field_type ] ) )
1429
                    continue;
1430
1431
                $class_vars = get_class_vars( get_class( self::$loaded[ $field_type ] ) ); // PHP 5.2.x workaround
1432
1433
                $field_types[ $field_type ] = $class_vars;
1434
                $field_types[ $field_type ][ 'file' ] = $file;
1435
            }
1436
1437
            self::$field_types = $field_types;
1438
1439
            pods_transient_set( 'pods_field_types', self::$field_types );
1440
        }
1441
        else
1442
            self::$field_types = array_merge( $field_types, self::$field_types );
1443
1444
        return self::$field_types;
1445
    }
1446
1447
    /**
1448
     * Get list of available tableless field types
1449
     *
1450
     * @return array Tableless field types
1451
     *
1452
     * @since 2.3
1453
     */
1454 View Code Duplication
    public static function tableless_field_types() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1455
	    static $field_types = null;
1456
1457
	    if ( null === $field_types ) {
1458
		    $field_types = array( 'pick', 'file', 'avatar', 'taxonomy' );
1459
1460
		    $field_types = apply_filters( 'pods_tableless_field_types', $field_types );
1461
	    }
1462
	    return $field_types;
1463
    }
1464
1465
    /**
1466
     * Get list of available file field types
1467
     *
1468
     * @return array File field types
1469
     *
1470
     * @since 2.3
1471
     */
1472 View Code Duplication
    public static function file_field_types() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1473
	    static $field_types = null;
1474
1475
	    if ( null === $field_types ) {
1476
		    $field_types = array( 'file', 'avatar' );
1477
1478
		    $field_types = apply_filters( 'pods_file_field_types', $field_types );
1479
	    }
1480
	    return $field_types;
1481
    }
1482
1483
    /**
1484
     * Get list of available repeatable field types
1485
     *
1486
     * @return array Repeatable field types
1487
     *
1488
     * @since 2.3
1489
     */
1490
    public static function repeatable_field_types() {
1491
	    static $field_types = null;
1492
1493
	    if ( null === $field_types ) {
1494
		    $field_types = array(
1495
			    'code',
1496
			    'color',
1497
			    'currency',
1498
			    'date',
1499
			    'datetime',
1500
			    'email',
1501
			    'number',
1502
			    'paragraph',
1503
			    'phone',
1504
			    'text',
1505
			    'time',
1506
			    'website',
1507
			    'wysiwyg'
1508
		    );
1509
1510
		    $field_types = apply_filters( 'pods_repeatable_field_types', $field_types );
1511
	    }
1512
	    return $field_types;
1513
    }
1514
1515
    /**
1516
     * Get list of available number field types
1517
     *
1518
     * @return array Number field types
1519
     *
1520
     * @since 2.3
1521
     */
1522 View Code Duplication
    public static function number_field_types() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1523
	    static $field_types = null;
1524
1525
	    if ( null === $field_types ) {
1526
		    $field_types = array( 'currency', 'number' );
1527
1528
		    $field_types = apply_filters( 'pods_tableless_field_types', $field_types );
1529
	    }
1530
	    return $field_types;
1531
    }
1532
1533
    /**
1534
     * Get list of available date field types
1535
     *
1536
     * @return array Date field types
1537
     *
1538
     * @since 2.3
1539
     */
1540 View Code Duplication
    public static function date_field_types() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1541
	    static $field_types = null;
1542
1543
	    if ( null === $field_types ) {
1544
		    $field_types = array( 'date', 'datetime', 'time' );
1545
1546
		    $field_types = apply_filters( 'pods_tableless_field_types', $field_types );
1547
	    }
1548
	    return $field_types;
1549
    }
1550
1551
    /**
1552
     * Get list of available text field types
1553
     *
1554
     * @return array Text field types
1555
     *
1556
     * @since 2.3
1557
     */
1558
    public static function text_field_types() {
1559
	    static $field_types = null;
1560
1561
	    if ( null === $field_types ) {
1562
		    $field_types = array( 'code', 'paragraph', 'slug', 'password', 'text', 'wysiwyg' );
1563
1564
		    $field_types = apply_filters( 'pods_text_field_types', $field_types );
1565
	    }
1566
	    return $field_types;
1567
    }
1568
1569
    /**
1570
     * Get list of available text field types
1571
     *
1572
     * @return array Text field types
1573
     *
1574
     * @since 2.3
1575
     */
1576
    public static function block_field_types() {
1577
	    static $field_types = null;
1578
1579
	    if ( null === $field_types ) {
1580
		    $field_types = array( 'heading', 'html' );
1581
1582
		    /**
1583
		     * Returns the available text field types
1584
		     *
1585
		     * @since unknown
1586
		     *
1587
		     * @param object $field_types Outputs the field types
1588
		     */
1589
1590
		    $field_types = apply_filters( 'pods_block_field_types', $field_types );
1591
	    }
1592
	    return $field_types;
1593
    }
1594
1595
	/**
1596
	 * Get list of available text field types
1597
	 *
1598
	 * @return array Text field types
1599
	 *
1600
	 * @since 2.3
1601
	 */
1602
	public static function simple_tableless_objects() {
1603
		static $object_types = null;
1604
1605
		if ( null === $object_types ) {
1606
			$object_types = PodsForm::field_method( 'pick', 'simple_objects' );
1607
		}
1608
		return $object_types;
1609
	}
1610
1611
	}
1612