Passed
Pull Request — trunk (#1007)
by
unknown
11:05
created

CMB2_Field::_set_field_defaults()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 72
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 22
c 1
b 0
f 0
dl 0
loc 72
ccs 21
cts 21
cp 1
rs 8.9457
cc 6
nc 32
nop 1
crap 6

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * CMB2 field objects
4
 *
5
 * @since  1.1.0
6
 *
7
 * @category  WordPress_Plugin
8
 * @package   CMB2
9
 * @author    CMB2 team
10
 * @license   GPL-2.0+
11
 * @link      https://cmb2.io
12
 *
13
 * @method string _id()
14
 * @method string type()
15
 * @method mixed fields()
16
 */
17
class CMB2_Field extends CMB2_Base {
18
19
	/**
20
	 * The object properties name.
21
	 *
22
	 * @var   string
23
	 * @since 2.2.3
24
	 */
25
	protected $properties_name = 'args';
26
27
	/**
28
	 * Field arguments
29
	 *
30
	 * @var   mixed
31
	 * @since 1.1.0
32
	 */
33
	public $args = array();
34
35
	/**
36
	 * Field group object or false (if no group)
37
	 *
38
	 * @var   mixed
39
	 * @since 1.1.0
40
	 */
41
	public $group = false;
42
43
	/**
44
	 * Field meta value
45
	 *
46
	 * @var   mixed
47
	 * @since 1.1.0
48
	 */
49
	public $value = null;
50
51
	/**
52
	 * Field meta value
53
	 *
54
	 * @var   mixed
55
	 * @since 1.1.0
56
	 */
57
	public $escaped_value = null;
58
59
	/**
60
	 * Grouped Field's current numeric index during the save process
61
	 *
62
	 * @var   mixed
63
	 * @since 2.0.0
64
	 */
65
	public $index = 0;
66
67
	/**
68
	 * Array of field options
69
	 *
70
	 * @var   array
71
	 * @since 2.0.0
72
	 */
73
	protected $field_options = array();
74
75
	/**
76
	 * Array of provided field text strings
77
	 *
78
	 * @var   array
79
	 * @since 2.0.0
80
	 */
81
	protected $strings;
82
83
	/**
84
	 * The field's render context. In most cases, 'edit', but can be 'display'.
85
	 *
86
	 * @var   string
87
	 * @since 2.2.2
88
	 */
89
	public $render_context = 'edit';
90
91
	/**
92
	 * All CMB2_Field callable field arguments.
93
	 * Can be used to determine if a field argument is callable.
94
	 *
95
	 * @var array
96
	 */
97
	public static $callable_fields = array(
98
		'default_cb',
99
		'classes_cb',
100
		'options_cb',
101
		'text_cb',
102
		'label_cb',
103
		'render_row_cb',
104
		'display_cb',
105
		'before_group',
106
		'before_group_row',
107
		'before_row',
108
		'before',
109
		'before_field',
110
		'after_field',
111
		'after',
112
		'after_row',
113
		'after_group_row',
114
		'after_group',
115
	);
116
117
	/**
118
	 * Represents a unique hash representing this field.
119
	 *
120
	 * @since  2.2.4
121
	 *
122
	 * @var string
123
	 */
124
	protected $hash_id = '';
125
126
	/**
127
	 * Constructs our field object
128
	 *
129
	 * @since 1.1.0
130
	 * @param array $args Field arguments.
131
	 */
132 142
	public function __construct( $args ) {
133
134 142
		if ( ! empty( $args['group_field'] ) ) {
135 4
			$this->group       = $args['group_field'];
136 4
			$this->object_id   = $this->group->object_id;
137 4
			$this->object_type = $this->group->object_type;
138 4
			$this->cmb_id      = $this->group->cmb_id;
139
		} else {
140 142
			$this->object_id   = isset( $args['object_id'] ) && '_' !== $args['object_id'] ? $args['object_id'] : 0;
141 142
			$this->object_type = isset( $args['object_type'] ) ? $args['object_type'] : 'post';
142
143 142
			if ( isset( $args['cmb_id'] ) ) {
144 69
				$this->cmb_id = $args['cmb_id'];
145
			}
146
		}
147
148 142
		$this->args = $this->_set_field_defaults( $args['field_args'] );
149
150 142
		if ( $this->object_id ) {
151 127
			$this->value = $this->get_data();
152
		}
153 142
	}
154
155
	/**
156
	 * Non-existent methods fallback to checking for field arguments of the same name
157
	 *
158
	 * @since  1.1.0
159
	 * @param  string $name     Method name.
160
	 * @param  array  $arguments Array of passed-in arguments.
161
	 * @return mixed             Value of field argument
162
	 */
163 119
	public function __call( $name, $arguments ) {
164 119
		if ( 'string' === $name ) {
165
			return call_user_func_array( array( $this, 'get_string' ), $arguments );
166
		}
167
168 119
		$key = isset( $arguments[0] ) ? $arguments[0] : '';
169 119
		return $this->args( $name, $key );
170
	}
171
172
	/**
173
	 * Retrieves the field id
174
	 *
175
	 * @since  1.1.0
176
	 * @param  boolean $raw Whether to retrieve pre-modidifed id.
177
	 * @return string       Field id
178
	 */
179 135
	public function id( $raw = false ) {
180 135
		$id = $raw ? '_id' : 'id';
181 135
		return $this->args( $id );
182
	}
183
184
	/**
185
	 * Get a field argument
186
	 *
187
	 * @since  1.1.0
188
	 * @param  string $key  Argument to check.
189
	 * @param  string $_key Sub argument to check.
190
	 * @return mixed        Argument value or false if non-existent
191
	 */
192 138
	public function args( $key = '', $_key = '' ) {
193 138
		$arg = $this->_data( 'args', $key );
194
195 138
		if ( in_array( $key, array( 'default', 'default_cb' ), true ) ) {
196
197 1
			$arg = $this->get_default();
198
199 138
		} elseif ( $_key ) {
200
201
			$arg = isset( $arg[ $_key ] ) ? $arg[ $_key ] : false;
202
		}
203
204 138
		return $arg;
205
	}
206
207
	/**
208
	 * Retrieve a portion of a field property
209
	 *
210
	 * @since  1.1.0
211
	 * @param  string $var Field property to check.
212
	 * @param  string $key Field property array key to check.
213
	 * @return mixed        Queried property value or false
214
	 */
215 138
	public function _data( $var, $key = '' ) {
216 138
		$vars = $this->{$var};
217 138
		if ( $key ) {
218 138
			return array_key_exists( $key, $vars ) ? $vars[ $key ] : false;
219
		}
220 81
		return $vars;
221
	}
222
223
	/**
224
	 * Get Field's value
225
	 *
226
	 * @since  1.1.0
227
	 * @param  string $key If value is an array, is used to get array key->value.
228
	 * @return mixed       Field value or false if non-existent
229
	 */
230 58
	public function value( $key = '' ) {
231 58
		return $this->_data( 'value', $key );
232
	}
233
234
	/**
235
	 * Retrieves metadata/option data
236
	 *
237
	 * @since  1.0.1
238
	 * @param  string $field_id Meta key/Option array key.
239
	 * @param  array  $args     Override arguments.
240
	 * @return mixed            Meta/Option value
241
	 */
242 131
	public function get_data( $field_id = '', $args = array() ) {
243 131
		if ( $field_id ) {
244
			$args['field_id'] = $field_id;
245 131
		} elseif ( $this->group ) {
246
			$args['field_id'] = $this->group->id();
247
		}
248
249 131
		$a = $this->data_args( $args );
250
251
		/**
252
		 * Filter whether to override getting of meta value.
253
		 * Returning a non 'cmb2_field_no_override_val' value
254
		 * will effectively short-circuit the value retrieval.
255
		 *
256
		 * @since 2.0.0
257
		 *
258
		 * @param mixed $value     The value get_metadata() should
259
		 *                         return - a single metadata value,
260
		 *                         or an array of values.
261
		 *
262
		 * @param int   $object_id Object ID.
263
		 *
264
		 * @param array $args {
265
		 *     An array of arguments for retrieving data
266
		 *
267
		 *     @type string $type     The current object type
268
		 *     @type int    $id       The current object ID
269
		 *     @type string $field_id The ID of the field being requested
270
		 *     @type bool   $repeat   Whether current field is repeatable
271
		 *     @type bool   $single   Whether current field is a single database row
272
		 * }
273
		 *
274
		 * @param CMB2_Field object $field This field object
275
		 */
276 131
		$data = apply_filters( 'cmb2_override_meta_value', 'cmb2_field_no_override_val', $this->object_id, $a, $this );
277
278
		/**
279
		 * Filter and parameters are documented for 'cmb2_override_meta_value' filter (above).
280
		 *
281
		 * The dynamic portion of the hook, $field_id, refers to the current
282
		 * field id paramater. Returning a non 'cmb2_field_no_override_val' value
283
		 * will effectively short-circuit the value retrieval.
284
		 *
285
		 * @since 2.0.0
286
		 */
287 131
		$data = apply_filters( "cmb2_override_{$a['field_id']}_meta_value", $data, $this->object_id, $a, $this );
288
289
		// If no override, get value normally.
290 131
		if ( 'cmb2_field_no_override_val' === $data ) {
291 131
			$data = 'options-page' === $a['type']
292 1
				? cmb2_options( $a['id'] )->get( $a['field_id'] )
293 131
				: get_metadata( $a['type'], $a['id'], $a['field_id'], ( $a['single'] || $a['repeat'] ) );
294
		}
295
296 131
		if ( $this->group ) {
297
298
			$data = is_array( $data ) && isset( $data[ $this->group->index ][ $this->args( '_id' ) ] )
299
				? $data[ $this->group->index ][ $this->args( '_id' ) ]
300
				: false;
301
		}
302
303 131
		return $data;
304
	}
305
306
	/**
307
	 * Updates metadata/option data.
308
	 *
309
	 * @since  1.0.1
310
	 * @param  mixed $new_value Value to update data with.
311
	 * @param  bool  $single    Whether data is an array (add_metadata).
312
	 * @return mixed
313 23
	 */
314 23
	public function update_data( $new_value, $single = true ) {
315 23
		$a = $this->data_args( array(
316
			'single' => $single,
317
		) );
318 23
319
		$a['value'] = $a['repeat'] ? array_values( $new_value ) : $new_value;
320
321
		/**
322
		 * Filter whether to override saving of meta value.
323
		 * Returning a non-null value will effectively short-circuit the function.
324
		 *
325
		 * @since 2.0.0
326
		 *
327
		 * @param null|bool $check  Whether to allow updating metadata for the given type.
328
		 *
329
		 * @param array $args {
330
		 *     Array of data about current field including:
331
		 *
332
		 *     @type string $value    The value to set
333
		 *     @type string $type     The current object type
334
		 *     @type int    $id       The current object ID
335
		 *     @type string $field_id The ID of the field being updated
336
		 *     @type bool   $repeat   Whether current field is repeatable
337
		 *     @type bool   $single   Whether current field is a single database row
338
		 * }
339
		 *
340
		 * @param array $field_args All field arguments
341
		 *
342
		 * @param CMB2_Field object $field This field object
343 23
		 */
344
		$override = apply_filters( 'cmb2_override_meta_save', null, $a, $this->args(), $this );
345
346
		/**
347
		 * Filter and parameters are documented for 'cmb2_override_meta_save' filter (above).
348
		 *
349
		 * The dynamic portion of the hook, $a['field_id'], refers to the current
350
		 * field id paramater. Returning a non-null value
351
		 * will effectively short-circuit the function.
352
		 *
353
		 * @since 2.0.0
354 23
		 */
355
		$override = apply_filters( "cmb2_override_{$a['field_id']}_meta_save", $override, $a, $this->args(), $this );
356
357 23
		// If override, return that.
358 1
		if ( null !== $override ) {
359
			return $override;
360
		}
361
362 23
		// Options page handling (or temp data store).
363 6
		if ( 'options-page' === $a['type'] || empty( $a['id'] ) ) {
364
			return cmb2_options( $a['id'] )->update( $a['field_id'], $a['value'], false, $a['single'] );
365
		}
366
367 17
		// Add metadata if not single.
368 1
		if ( ! $a['single'] ) {
369
			return add_metadata( $a['type'], $a['id'], $a['field_id'], $a['value'], false );
370
		}
371
372 16
		// Delete meta if we have an empty array.
373
		if ( is_array( $a['value'] ) && empty( $a['value'] ) ) {
374
			return delete_metadata( $a['type'], $a['id'], $a['field_id'], $this->value );
375
		}
376
377 16
		// Update metadata.
378
		return update_metadata( $a['type'], $a['id'], $a['field_id'], $a['value'] );
379
	}
380
381
	/**
382
	 * Removes/updates metadata/option data.
383
	 *
384
	 * @since  1.0.1
385
	 * @param  string $old Old value.
386 5
	 * @return mixed
387 5
	 */
388 5
	public function remove_data( $old = '' ) {
389
		$a = $this->data_args( array(
390
			'old' => $old,
391
		) );
392
393
		/**
394
		 * Filter whether to override removing of meta value.
395
		 * Returning a non-null value will effectively short-circuit the function.
396
		 *
397
		 * @since 2.0.0
398
		 *
399
		 * @param null|bool $delete Whether to allow metadata deletion of the given type.
400
		 * @param array $args       Array of data about current field including:
401
		 *                              'type'     : Current object type
402
		 *                              'id'       : Current object ID
403
		 *                              'field_id' : Current Field ID
404
		 *                              'repeat'   : Whether current field is repeatable
405
		 *                              'single'   : Whether to save as a
406
		 *                                           single meta value
407
		 * @param array $field_args All field arguments
408 5
		 * @param CMB2_Field object $field This field object
409
		 */
410
		$override = apply_filters( 'cmb2_override_meta_remove', null, $a, $this->args(), $this );
411
412
		/**
413
		 * Filter whether to override removing of meta value.
414
		 *
415
		 * The dynamic portion of the hook, $a['field_id'], refers to the current
416
		 * field id paramater. Returning a non-null value
417
		 * will effectively short-circuit the function.
418
		 *
419
		 * @since 2.0.0
420
		 *
421
		 * @param null|bool $delete Whether to allow metadata deletion of the given type.
422
		 * @param array $args       Array of data about current field including:
423
		 *                              'type'     : Current object type
424
		 *                              'id'       : Current object ID
425
		 *                              'field_id' : Current Field ID
426
		 *                              'repeat'   : Whether current field is repeatable
427
		 *                              'single'   : Whether to save as a
428
		 *                                           single meta value
429
		 * @param array $field_args All field arguments
430 5
		 * @param CMB2_Field object $field This field object
431
		 */
432
		$override = apply_filters( "cmb2_override_{$a['field_id']}_meta_remove", $override, $a, $this->args(), $this );
433 5
434
		// If no override, remove as usual.
435
		if ( null !== $override ) {
436
			return $override;
437 5
		} // End if.
438 1
		// Option page handling.
439
		elseif ( 'options-page' === $a['type'] || empty( $a['id'] ) ) {
440
			return cmb2_options( $a['id'] )->remove( $a['field_id'] );
441
		}
442 4
443
		// Remove metadata.
444
		return delete_metadata( $a['type'], $a['id'], $a['field_id'], $old );
445
	}
446
447
	/**
448
	 * Data variables for get/set data methods
449
	 *
450
	 * @since  1.1.0
451
	 * @param  array $args Override arguments.
452 131
	 * @return array       Updated arguments
453 131
	 */
454 131
	public function data_args( $args = array() ) {
455 131
		$args = wp_parse_args( $args, array(
456 131
			'type'     => $this->object_type,
457 131
			'id'       => $this->object_id,
458 131
			'field_id' => $this->id( true ),
459
			'repeat'   => $this->args( 'repeatable' ),
460 131
			'single'   => ! $this->args( 'multiple' ),
461
		) );
462
		return $args;
463
	}
464
465
	/**
466
	 * Checks if field has a registered sanitization callback
467
	 *
468
	 * @since  1.0.1
469
	 * @param  mixed $meta_value Meta value.
470 25
	 * @return mixed             Possibly sanitized meta value
471
	 */
472 25
	public function sanitization_cb( $meta_value ) {
473
474 2
		if ( $this->args( 'repeatable' ) && is_array( $meta_value ) ) {
475
			// Remove empties.
476
			$meta_value = array_filter( $meta_value );
477
		}
478 25
479 25
		// Check if the field has a registered validation callback.
480
		$cb = $this->maybe_callback( 'sanitization_cb' );
481 2
		if ( false === $cb ) {
482 24
			// If requesting NO validation, return meta value.
483
			return $meta_value;
484
		} elseif ( $cb ) {
485
			// Ok, callback is good, let's run it.
486
			return call_user_func( $cb, $meta_value, $this->args(), $this );
487 24
		}
488 24
489
		$sanitizer = new CMB2_Sanitize( $this, $meta_value );
490
		$field_type = $this->type();
491
492
		/**
493
		 * Filter the value before it is saved.
494
		 *
495
		 * The dynamic portion of the hook name, $field_type, refers to the field type.
496
		 *
497
		 * Passing a non-null value to the filter will short-circuit saving
498
		 * the field value, saving the passed value instead.
499
		 *
500
		 * @param bool|mixed $override_value Sanitization/Validation override value to return.
501
		 *                                   Default: null. false to skip it.
502
		 * @param mixed      $value      The value to be saved to this field.
503
		 * @param int        $object_id  The ID of the object where the value will be saved
504
		 * @param array      $field_args The current field's arguments
505 24
		 * @param object     $sanitizer  This `CMB2_Sanitize` object
506
		 */
507 24
		$override_value = apply_filters( "cmb2_sanitize_{$field_type}", null, $sanitizer->value, $this->object_id, $this->args(), $sanitizer );
508 1
509
		if ( null !== $override_value ) {
510
			return $override_value;
511
		}
512 23
513
		// Sanitization via 'CMB2_Sanitize'.
514
		return $sanitizer->{$field_type}();
515
	}
516
517
	/**
518
	 * Process $_POST data to save this field's value
519
	 *
520
	 * @since  2.0.3
521
	 * @param  array $data_to_save $_POST data to check.
522 4
	 * @return array|int|bool                Result of save, false on failure
523 4
	 */
524
	public function save_field_from_data( array $data_to_save ) {
525 4
		$this->data_to_save = $data_to_save;
526 4
527 4
		$meta_value = isset( $this->data_to_save[ $this->id( true ) ] )
528
			? $this->data_to_save[ $this->id( true ) ]
529 4
			: null;
530
531
		return $this->save_field( $meta_value );
532
	}
533
534
	/**
535
	 * Sanitize/store a value to this field
536
	 *
537
	 * @since  2.0.0
538
	 * @param  array $meta_value Desired value to sanitize/store.
539 23
	 * @return array|int|bool              Result of save. false on failure
540
	 */
541 23
	public function save_field( $meta_value ) {
542 23
543 23
		$updated   = false;
544
		$action    = '';
545 23
		$new_value = $this->sanitization_cb( $meta_value );
546
547
		if ( ! $this->args( 'save_field' ) ) {
548 1
549
			// Nothing to see here.
550 22
			$action = 'disabled';
551
552 1
		} elseif ( $this->args( 'multiple' ) && ! $this->args( 'repeatable' ) && ! $this->group ) {
553 1
554
			$this->remove_data();
555 1
			$count = 0;
556 1
557 1
			if ( ! empty( $new_value ) ) {
558 1
				foreach ( $new_value as $add_new ) {
559
					if ( $this->update_data( $add_new, false ) ) {
560
						$count++;
561
					}
562
				}
563 1
			}
564 1
565
			$updated = $count ? $count : false;
566 21
			$action  = 'repeatable';
567 20
568 20
		} elseif ( ! CMB2_Utils::isempty( $new_value ) && $new_value !== $this->get_data() ) {
569 7
			$updated = $this->update_data( $new_value );
570 4
			$action  = 'updated';
571 4
		} elseif ( CMB2_Utils::isempty( $new_value ) ) {
572
			$updated = $this->remove_data();
573
			$action  = 'removed';
574 23
		}
575 22
576 22
		if ( $updated ) {
577
			$this->value = $this->get_data();
578
			$this->escaped_value = null;
579 23
		}
580
581
		$field_id = $this->id( true );
582
583
		/**
584
		 * Hooks after save field action.
585
		 *
586
		 * @since 2.2.0
587
		 *
588
		 * @param string            $field_id the current field id paramater.
589
		 * @param bool              $updated  Whether the metadata update action occurred.
590
		 * @param string            $action   Action performed. Could be "repeatable", "updated", or "removed".
591 23
		 * @param CMB2_Field object $field    This field object
592
		 */
593
		do_action( 'cmb2_save_field', $field_id, $updated, $action, $this );
594
595
		/**
596
		 * Hooks after save field action.
597
		 *
598
		 * The dynamic portion of the hook, $field_id, refers to the
599
		 * current field id paramater.
600
		 *
601
		 * @since 2.2.0
602
		 *
603
		 * @param bool              $updated Whether the metadata update action occurred.
604
		 * @param string            $action  Action performed. Could be "repeatable", "updated", or "removed".
605 22
		 * @param CMB2_Field object $field   This field object
606
		 */
607 21
		do_action( "cmb2_save_field_{$field_id}", $updated, $action, $this );
608
609
		return $updated;
610
	}
611
612
	/**
613
	 * Determine if current type is exempt from escaping
614
	 *
615
	 * @since  1.1.0
616 58
	 * @return bool  True if exempt
617
	 */
618 58
	public function escaping_exception() {
619 58
		// These types cannot be escaped.
620
		return in_array( $this->type(), array(
621
			'file_list',
622
			'multicheck',
623
			'text_datetime_timestamp_timezone',
624
		) );
625
	}
626
627
	/**
628
	 * Determine if current type cannot be repeatable
629
	 *
630
	 * @since  1.1.0
631
	 * @param  string $type Field type to check.
632 6
	 * @return bool         True if type cannot be repeatable
633
	 */
634
	public function repeatable_exception( $type ) {
635
		// These types cannot be repeatable.
636 6
		$internal_fields = array(
637
			// Use file_list instead.
638
			'file'                             => 1,
639
			'radio'                            => 1,
640
			'title'                            => 1,
641
			'wysiwyg'                          => 1,
642
			'checkbox'                         => 1,
643
			'radio_inline'                     => 1,
644
			'taxonomy_radio'                   => 1,
645
			'taxonomy_radio_inline'            => 1,
646
			'taxonomy_radio_hierarchical'      => 1,
647
			'taxonomy_select'                  => 1,
648
			'taxonomy_multicheck'              => 1,
649
			'taxonomy_multicheck_inline'       => 1,
650
			'taxonomy_multicheck_hierarchical' => 1,
651
652
		);
653
654
		/**
655
		 * Filter field types that are non-repeatable.
656
		 *
657
		 * Note that this does *not* allow overriding the default non-repeatable types.
658
		 *
659
		 * @since 2.1.1
660
		 *
661
		 * @param array $fields Array of fields designated as non-repeatable. Note that the field names are *keys*,
662
		 *                      and not values. The value can be anything, because it is meaningless. Example:
663 6
		 *                      array( 'my_custom_field' => 1 )
664 6
		 */
665
		$all_fields = array_merge( apply_filters( 'cmb2_non_repeatable_fields', array() ), $internal_fields );
666
		return isset( $all_fields[ $type ] );
667
	}
668
669
	/**
670
	 * Determine if current type has its own defaults field-arguments method.
671
	 *
672
	 * @since  2.2.6
673
	 * @param  string $type Field type to check.
674 142
	 * @return bool         True if has own method.
675
	 */
676
	public function has_args_method( $type ) {
677
678 142
		// These types have their own arguments parser.
679
		$type_methods = array(
680
			'group'   => 'set_field_defaults_group',
681
			'wysiwyg' => 'set_field_defaults_wysiwyg',
682 142
		);
683 6
684
		if ( isset( $type_methods[ $type ] ) ) {
685
			return $type_methods[ $type ];
686 140
		}
687 140
688
		$all_or_nothing_types = array_flip( apply_filters( 'cmb2_all_or_nothing_types', array(
689
			'select',
690
			'radio',
691
			'radio_inline',
692
			'taxonomy_select',
693
			'taxonomy_radio',
694 140
			'taxonomy_radio_inline',
695
			'taxonomy_radio_hierarchical',
696 140
		), $this ) );
697 20
698
		if ( isset( $all_or_nothing_types[ $type ] ) ) {
699
			return 'set_field_defaults_all_or_nothing_types';
700 122
		}
701
702
		return false;
703
	}
704
705
	/**
706
	 * Escape the value before output. Defaults to 'esc_attr()'
707
	 *
708
	 * @since  1.0.1
709
	 * @param  callable|string $func       Escaping function (if not esc_attr()).
710
	 * @param  mixed           $meta_value Meta value.
711 58
	 * @return mixed                Final value.
712
	 */
713 58
	public function escaped_value( $func = 'esc_attr', $meta_value = '' ) {
714 35
715
		if ( null !== $this->escaped_value ) {
716
			return $this->escaped_value;
717 58
		}
718
719
		$meta_value = $meta_value ? $meta_value : $this->value();
720 58
721
		// Check if the field has a registered escaping callback.
722
		if ( $cb = $this->maybe_callback( 'escape_cb' ) ) {
723
			// Ok, callback is good, let's run it.
724
			return call_user_func( $cb, $meta_value, $this->args(), $this );
725 58
		}
726
727
		$field_type = $this->type();
728
729
		/**
730
		 * Filter the value for escaping before it is ouput.
731
		 *
732
		 * The dynamic portion of the hook name, $field_type, refers to the field type.
733
		 *
734
		 * Passing a non-null value to the filter will short-circuit the built-in
735
		 * escaping for this field.
736
		 *
737
		 * @param bool|mixed $override_value Escaping override value to return.
738
		 *                                   Default: null. false to skip it.
739
		 * @param mixed      $meta_value The value to be output.
740
		 * @param array      $field_args The current field's arguments.
741 58
		 * @param object     $field      This `CMB2_Field` object.
742 58
		 */
743
		$esc = apply_filters( "cmb2_types_esc_{$field_type}", null, $meta_value, $this->args(), $this );
744
		if ( null !== $esc ) {
745
			return $esc;
746 58
		}
747
748 5
		if ( false === $cb || $this->escaping_exception() ) {
749
			// If requesting NO escaping, return meta value.
750
			return $this->val_or_default( $meta_value );
751
		}
752 53
753 53
		// escaping function passed in?
754
		$func       = $func ? $func : 'esc_attr';
755 53
		$meta_value = $this->val_or_default( $meta_value );
756
757
		if ( is_array( $meta_value ) ) {
758
			foreach ( $meta_value as $key => $value ) {
759
				$meta_value[ $key ] = call_user_func( $func, $value );
760 53
			}
761
		} else {
762
			$meta_value = call_user_func( $func, $meta_value );
763 53
		}
764 53
765
		$this->escaped_value = $meta_value;
766
		return $this->escaped_value;
767
	}
768
769
	/**
770
	 * Return non-empty value or field default if value IS empty
771
	 *
772
	 * @since  2.0.0
773
	 * @param  mixed $meta_value Field value.
774 58
	 * @return mixed             Field value, or default value
775 58
	 */
776
	public function val_or_default( $meta_value ) {
777
		return ! CMB2_Utils::isempty( $meta_value ) ? $meta_value : $this->get_default();
778
	}
779
780
	/**
781
	 * Offset a time value based on timezone
782
	 *
783
	 * @since  1.0.0
784
	 * @return string Offset time string
785
	 */
786
	public function field_timezone_offset() {
787
		return CMB2_Utils::timezone_offset( $this->field_timezone() );
788
	}
789
790
	/**
791
	 * Return timezone string
792
	 *
793
	 * @since  1.0.0
794
	 * @return string Timezone string
795
	 */
796
	public function field_timezone() {
797
		$value = '';
798
799
		// Is timezone arg set?
800
		if ( $this->args( 'timezone' ) ) {
801
			$value = $this->args( 'timezone' );
802
		} // End if.
803
		// Is there another meta key with a timezone stored as its value we should use?
804
		elseif ( $this->args( 'timezone_meta_key' ) ) {
805
			$value = $this->get_data( $this->args( 'timezone_meta_key' ) );
806
		}
807
808
		return $value;
809
	}
810
811
	/**
812
	 * Format the timestamp field value based on the field date/time format arg
813
	 *
814
	 * @since  2.0.0
815
	 * @param  int    $meta_value Timestamp.
816
	 * @param  string $format     Either date_format or time_format.
817 10
	 * @return string             Formatted date
818 10
	 */
819
	public function format_timestamp( $meta_value, $format = 'date_format' ) {
820
		return date( stripslashes( $this->args( $format ) ), $meta_value );
821
	}
822
823
	/**
824
	 * Return a formatted timestamp for a field
825
	 *
826
	 * @since  2.0.0
827
	 * @param  string     $format     Either date_format or time_format.
828
	 * @param  string|int $meta_value Optional meta value to check.
829 10
	 * @return string             Formatted date
830 10
	 */
831 10
	public function get_timestamp_format( $format = 'date_format', $meta_value = 0 ) {
832
		$meta_value = $meta_value ? $meta_value : $this->escaped_value();
833 10
		$meta_value = CMB2_Utils::make_valid_time_stamp( $meta_value );
834
835
		if ( empty( $meta_value ) ) {
836
			return '';
837 10
		}
838
839 10
		return is_array( $meta_value )
0 ignored issues
show
introduced by
The condition is_array($meta_value) is always false.
Loading history...
840
			? array_map( array( $this, 'format_timestamp' ), $meta_value, $format )
841
			: $this->format_timestamp( $meta_value, $format );
842
	}
843
844
	/**
845
	 * Get timestamp from text date
846
	 *
847
	 * @since  2.2.0
848
	 * @param  string $value Date value.
849
	 * @return mixed         Unix timestamp representing the date.
850
	 */
851
	public function get_timestamp_from_value( $value ) {
852
		return CMB2_Utils::get_timestamp_from_value( $value, $this->args( 'date_format' ) );
853
	}
854
855
	/**
856
	 * Get field render callback and Render the field row
857
	 *
858 10
	 * @since 1.0.0
859 10
	 */
860
	public function render_field() {
861 10
		$this->render_context = 'edit';
862
863
		$this->peform_param_callback( 'render_row_cb' );
864 10
865
		// For chaining.
866
		return $this;
867
	}
868
869
	/**
870
	 * Default field render callback
871
	 *
872 14
	 * @since 2.1.1
873
	 */
874
	public function render_field_callback() {
875 14
876
		// If field is requesting to not be shown on the front-end.
877
		if ( ! is_admin() && ! $this->args( 'on_front' ) ) {
878
			return;
879
		}
880 14
881
		// If field is requesting to be conditionally shown.
882
		if ( ! $this->should_show() ) {
883
			return;
884 14
		}
885
886 14
		$field_type = $this->type();
887
888 14
		/**
889
		 * Hook before field row begins.
890
		 *
891
		 * @param CMB2_Field $field The current field object.
892
		 */
893
		do_action( 'cmb2_before_field_row', $this );
894
895 14
		/**
896 14
		 * Hook before field row begins.
897
		 *
898
		 * The dynamic portion of the hook name, $field_type, refers to the field type.
899 14
		 *
900
		 * @param CMB2_Field $field The current field object.
901
		 */
902 14
		do_action( "cmb2_before_{$field_type}_field_row", $this );
903
904 14
		$this->peform_param_callback( 'before_row' );
905 14
906
		printf( "<div class=\"cmb-row %s\" data-fieldtype=\"%s\">\n", $this->row_classes(), $field_type );
907 14
908
		if ( ! $this->args( 'show_names' ) ) {
909 14
			echo "\n\t<div class=\"cmb-td\">\n";
910
911 14
			$this->peform_param_callback( 'label_cb' );
912
913
		} else {
914 14
915
			if ( $this->get_param_callback_result( 'label_cb' ) ) {
916
				echo '<div class="cmb-th">', $this->peform_param_callback( 'label_cb' ), '</div>';
917
			}
918
919
			echo "\n\t<div class=\"cmb-td\">\n";
920
		}
921
922
		$this->peform_param_callback( 'before' );
923 14
924 14
		$types = new CMB2_Types( $this );
925
		$types->render();
926
927
		$this->peform_param_callback( 'after' );
928 14
929
		echo "\n\t</div>\n</div>";
930 14
931
		$this->peform_param_callback( 'after_row' );
932
933
		/**
934
		 * Hook after field row ends.
935
		 *
936
		 * The dynamic portion of the hook name, $field_type, refers to the field type.
937
		 *
938
		 * @param CMB2_Field $field The current field object.
939 50
		 */
940
		do_action( "cmb2_after_{$field_type}_field_row", $this );
941 50
942
		/**
943
		 * Hook after field row ends.
944
		 *
945
		 * @param CMB2_Field $field The current field object.
946
		 */
947
		do_action( 'cmb2_after_field_row', $this );
948
949
		// For chaining.
950 50
		return $this;
951 50
	}
952
953
	/**
954
	 * The default label_cb callback (if not a title field)
955
	 *
956 50
	 * @since  2.1.1
957 50
	 * @return string Label html markup.
958 50
	 */
959 50
	public function label() {
960 50
		if ( ! $this->args( 'name' ) ) {
961 50
			return '';
962
		}
963
964 50
		$style = ! $this->args( 'show_names' ) ? ' style="display:none;"' : '';
965 50
966 50
		return sprintf( "\n" . '<label%1$s for="%2$s">%3$s</label>' . "\n", $style, $this->id(), $this->args( 'name' ) );
967
	}
968
969
	/**
970 50
	 * Defines the classes for the current CMB2 field row
971 1
	 *
972 49
	 * @since  2.0.0
973 2
	 * @return string Space concatenated list of classes
974
	 */
975
	public function row_classes() {
976 50
977 3
		$classes = array();
978
979
		/**
980
		 * By default, 'text_url' and 'text' fields get table-like styling
981
		 *
982
		 * @since 2.0.0
983
		 *
984
		 * @param array $field_types The types of fields which should get the 'table-layout' class
985
		 */
986
		$repeat_table_rows_types = apply_filters( 'cmb2_repeat_table_row_types', array(
987
			'text_url',
988 50
			'text',
989
		) );
990
991
		$conditional_classes = array(
992
			'cmb-type-' . str_replace( '_', '-', sanitize_html_class( $this->type() ) ) => true,
993
			'cmb2-id-' . str_replace( '_', '-', sanitize_html_class( $this->id() ) )    => true,
994
			'cmb-repeat'             => $this->args( 'repeatable' ),
995
			'cmb-repeat-group-field' => $this->group,
996 33
			'cmb-inline'             => $this->args( 'inline' ),
997 33
			'table-layout'           => 'edit' === $this->render_context && in_array( $this->type(), $repeat_table_rows_types ),
998
		);
999 33
1000
		foreach ( $conditional_classes as $class => $condition ) {
1001
			if ( $condition ) {
1002 33
				$classes[] = $class;
1003
			}
1004
		}
1005
1006
		if ( $added_classes = $this->args( 'classes' ) ) {
1007
			$added_classes = is_array( $added_classes ) ? implode( ' ', $added_classes ) : (string) $added_classes;
1008
		} elseif ( $added_classes = $this->get_param_callback_result( 'classes_cb' ) ) {
1009
			$added_classes = is_array( $added_classes ) ? implode( ' ', $added_classes ) : (string) $added_classes;
1010 3
		}
1011 3
1012 3
		if ( $added_classes ) {
1013
			$classes[] = esc_attr( $added_classes );
1014 3
		}
1015
1016
		/**
1017
		 * Globally filter row classes
1018 3
		 *
1019
		 * @since 2.0.0
1020
		 *
1021
		 * @param string            $classes Space-separated list of row classes
1022
		 * @param CMB2_Field object $field   This field object
1023
		 */
1024
		return apply_filters( 'cmb2_row_classes', implode( ' ', $classes ), $this );
1025
	}
1026
1027
	/**
1028 3
	 * Get field display callback and render the display value in the column.
1029
	 *
1030
	 * @since 2.2.2
1031
	 */
1032
	public function render_column() {
1033
		$this->render_context = 'display';
1034
1035
		$this->peform_param_callback( 'display_cb' );
1036
1037
		// For chaining.
1038
		return $this;
1039
	}
1040 3
1041
	/**
1042
	 * The method to fetch the value for this field for the REST API.
1043
	 *
1044
	 * @since 2.5.0
1045
	 */
1046
	public function get_rest_value() {
1047
		$field_type = $this->type();
1048
		$field_id   = $this->id( true );
1049
1050
		if ( $cb = $this->maybe_callback( 'rest_value_cb' ) ) {
1051
			add_filter( "cmb2_get_rest_value_for_{$field_id}", $cb, 99 );
1052 3
		}
1053
1054
		$value = $this->get_data();
1055
1056
		/**
1057
		 * Filter the value before it is sent to the REST request.
1058
		 *
1059
		 * @since 2.5.0
1060 33
		 *
1061
		 * @param mixed      $value The value from CMB2_Field::get_data()
1062 33
		 * @param CMB2_Field $field This field object.
1063
		 */
1064
		$value = apply_filters( 'cmb2_get_rest_value', $value, $this );
1065
1066 33
		/**
1067 33
		 * Filter the value before it is sent to the REST request.
1068
		 *
1069
		 * The dynamic portion of the hook name, $field_type, refers to the field type.
1070
		 *
1071
		 * @since 2.5.0
1072
		 *
1073
		 * @param mixed      $value The value from CMB2_Field::get_data()
1074
		 * @param CMB2_Field $field This field object.
1075
		 */
1076
		$value = apply_filters( "cmb2_get_rest_value_{$field_type}", $value, $this );
1077
1078
		/**
1079
		 * Filter the value before it is sent to the REST request.
1080 33
		 *
1081
		 * The dynamic portion of the hook name, $field_id, refers to the field id.
1082 33
		 *
1083
		 * @since 2.5.0
1084
		 *
1085
		 * @param mixed      $value The value from CMB2_Field::get_data()
1086
		 * @param CMB2_Field $field This field object.
1087 33
		 */
1088
		return apply_filters( "cmb2_get_rest_value_for_{$field_id}", $value, $this );
1089 33
	}
1090
1091 33
	/**
1092
	 * Default callback to outputs field value in a display format.
1093 33
	 *
1094
	 * @since 2.2.2
1095 33
	 */
1096
	public function display_value_callback() {
1097 33
		// If field is requesting to be conditionally shown.
1098
		if ( ! $this->should_show() ) {
1099 33
			return;
1100
		}
1101
1102 33
		$display = new CMB2_Field_Display( $this );
1103
		$field_type = $this->type();
1104
1105
		/**
1106
		 * A filter to bypass the default display.
1107
		 *
1108
		 * The dynamic portion of the hook name, $field_type, refers to the field type.
1109
		 *
1110
		 * Passing a non-null value to the filter will short-circuit the default display.
1111
		 *
1112 2
		 * @param bool|mixed         $pre_output Default null value.
1113
		 * @param CMB2_Field         $field      This field object.
1114 2
		 * @param CMB2_Field_Display $display    The `CMB2_Field_Display` object.
1115
		 */
1116
		$pre_output = apply_filters( "cmb2_pre_field_display_{$field_type}", null, $this, $display );
1117
1118
		if ( null !== $pre_output ) {
1119
			echo $pre_output;
1120
			return;
1121
		}
1122
1123
		$this->peform_param_callback( 'before_display_wrap' );
1124
1125
		printf( "<div class=\"cmb-column %s\" data-fieldtype=\"%s\">\n", $this->row_classes(), $field_type );
1126 10
1127
		$this->peform_param_callback( 'before_display' );
1128 10
1129 10
		CMB2_Field_Display::get( $this )->display();
1130
1131 10
		$this->peform_param_callback( 'after_display' );
1132
1133
		echo "\n</div>";
1134
1135
		$this->peform_param_callback( 'after_display_wrap' );
1136
1137
		// For chaining.
1138
		return $this;
1139
	}
1140
1141 10
	/**
1142 1
	 * Replaces a hash key - {#} - with the repeatable index
1143
	 *
1144
	 * @since  1.2.0
1145
	 * @param  string $value Value to update.
1146 10
	 * @return string        Updated value
1147
	 */
1148 10
	public function replace_hash( $value ) {
1149
		// Replace hash with 1 based count.
1150
		return str_replace( '{#}', ( $this->index + 1 ), $value );
1151
	}
1152
1153
	/**
1154
	 * Retrieve text parameter from field's text array (if it has one), or use fallback text
1155
	 * For back-compatibility, falls back to checking the options array.
1156
	 *
1157
	 * @since  2.2.2
1158 47
	 * @param  string $text_key Key in field's text array.
1159 47
	 * @param  string $fallback Fallback text.
1160 47
	 * @return string            Text
1161
	 */
1162
	public function get_string( $text_key, $fallback ) {
1163 47
		// If null, populate with our field strings values.
1164 16
		if ( null === $this->strings ) {
1165
			$this->strings = (array) $this->args['text'];
1166
1167 36
			if ( is_callable( $this->args['text_cb'] ) ) {
1168
				$strings = call_user_func( $this->args['text_cb'], $this );
1169
1170
				if ( $strings && is_array( $strings ) ) {
1171
					$this->strings += $strings;
1172
				}
1173
			}
1174
		}
1175
1176
		// If we have that string value, send it back.
1177 47
		if ( isset( $this->strings[ $text_key ] ) ) {
1178 47
			return $this->strings[ $text_key ];
1179
		}
1180 47
1181 1
		// Check options for back-compat.
1182
		$string = $this->options( $text_key );
1183 1
1184 1
		return $string ? $string : $fallback;
1185
	}
1186
1187
	/**
1188 47
	 * Retrieve options args.
1189
	 *
1190
	 * @since  2.0.0
1191
	 * @param  string $key Specific option to retrieve.
1192
	 * @return array|mixed Array of options or specific option.
1193
	 */
1194
	public function options( $key = '' ) {
1195
		if ( empty( $this->field_options ) ) {
1196
			$this->set_options();
1197 14
		}
1198 14
1199 14
		if ( $key ) {
1200
			return array_key_exists( $key, $this->field_options ) ? $this->field_options[ $key ] : false;
1201
		}
1202 14
1203 14
		return $this->field_options;
1204
	}
1205
1206
	/**
1207
	 * Generates/sets options args. Calls options_cb if it exists.
1208
	 *
1209
	 * @since  2.2.5
1210 57
	 *
1211 57
	 * @return array Array of options
1212 2
	 */
1213
	public function set_options() {
1214
		$this->field_options = (array) $this->args['options'];
1215 57
1216
		if ( is_callable( $this->args['options_cb'] ) ) {
1217
			$options = call_user_func( $this->args['options_cb'], $this );
1218
1219
			if ( $options && is_array( $options ) ) {
1220
				$this->field_options = $options + $this->field_options;
1221
			}
1222
		}
1223
1224
		return $this->field_options;
1225 15
	}
1226
1227 15
	/**
1228 15
	 * Store JS dependencies as part of the field args.
1229 15
	 *
1230 15
	 * @since 2.2.0
1231 15
	 * @param array $dependencies Dependies to register for this field.
1232 15
	 */
1233 15
	public function add_js_dependencies( $dependencies = array() ) {
1234 15
		foreach ( (array) $dependencies as $dependency ) {
1235 15
			$this->args['js_dependencies'][ $dependency ] = $dependency;
1236 15
		}
1237
1238
		CMB2_JS::add_dependencies( $dependencies );
1239
	}
1240
1241
	/**
1242
	 * Send field data to JS.
1243
	 *
1244
	 * @since 2.2.0
1245
	 */
1246
	public function register_js_data() {
1247 57
		if ( $this->group ) {
1248 57
			CMB2_JS::add_field_data( $this->group );
1249 57
		}
1250
1251
		return CMB2_JS::add_field_data( $this );
0 ignored issues
show
Bug introduced by
Are you sure the usage of CMB2_JS::add_field_data($this) targeting CMB2_JS::add_field_data() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1252 57
	}
1253
1254
	/**
1255
	 * Get an array of some of the field data to be used in the Javascript.
1256
	 *
1257
	 * @since  2.2.4
1258
	 *
1259
	 * @return array
1260
	 */
1261
	public function js_data() {
1262 15
		return array(
1263 15
			'label'     => $this->args( 'name' ),
1264
			'id'        => $this->id( true ),
1265
			'type'      => $this->type(),
1266
			'hash'      => $this->hash_id(),
1267
			'box'       => $this->cmb_id,
1268
			'id_attr'   => $this->id(),
1269
			'name_attr' => $this->args( '_name' ),
1270
			'default'   => $this->get_default(),
1271
			'group'     => $this->group_id(),
1272
			'index'     => $this->group ? $this->group->index : null,
1273 46
		);
1274 46
	}
1275
1276 46
	/**
1277 17
	 * Returns a unique hash representing this field.
1278
	 *
1279
	 * @since  2.2.4
1280 45
	 *
1281 45
	 * @return string
1282
	 */
1283
	public function hash_id() {
1284 45
		if ( '' === $this->hash_id ) {
1285
			$this->hash_id = CMB2_Utils::generate_hash( $this->cmb_id . '||' . $this->id() );
1286
		}
1287
1288
		return $this->hash_id;
1289
	}
1290
1291
	/**
1292
	 * Gets the id of the group field if this field is part of a group.
1293
	 *
1294
	 * @since  2.2.4
1295 142
	 *
1296
	 * @return string
1297
	 */
1298 142
	public function group_id() {
1299
		return $this->group ? $this->group->id( true ) : '';
1300
	}
1301
1302
	/**
1303
	 * Get CMB2_Field default value, either from default param or default_cb param.
1304
	 *
1305
	 * @since  0.2.2
1306
	 *
1307 142
	 * @return mixed  Default field value
1308
	 */
1309 142
	public function get_default() {
1310 142
		$default = $this->args['default'];
1311 142
1312 142
		if ( null !== $default ) {
1313
			return apply_filters( 'cmb2_default_filter', $default, $this );
1314 142
		}
1315 26
1316
		$param = is_callable( $this->args['default_cb'] ) ? 'default_cb' : 'default';
1317
		$default = $this->args['default'] = $this->get_param_callback_result( $param );
0 ignored issues
show
Unused Code introduced by
The assignment to $default is dead and can be removed.
Loading history...
1318 142
1319 4
		// Allow a filter override of the default value.
1320
		return apply_filters( 'cmb2_default_filter', $this->args['default'], $this );
1321
	}
1322 142
1323 142
	/**
1324
	 * Fills in empty field parameters with defaults
1325
	 *
1326 142
	 * @since 1.1.0
1327
	 *
1328
	 * @param  array $args Field config array.
1329
	 * @return array        Modified field config array.
1330 142
	 */
1331
	public function _set_field_defaults( $args ) {
1332
		$defaults = $this->get_default_field_args( $args );
1333 142
1334
		/**
1335
		 * Filter the CMB2 Field defaults.
1336
		 *
1337
		 * @since 2.6.0
1338
		 * @param array             $defaults Metabox field config array defaults.
1339
		 * @param string            $id       Field id for the current field to allow for selective filtering.
1340
		 * @param string            $type     Field type for the current field to allow for selective filtering.
1341
		 * @param CMB2_Field object $field    This field object.
1342
		 */
1343
		$defaults = apply_filters( 'cmb2_field_defaults', $defaults, $args['id'], $args['type'], $this );
1344 5
1345 5
		// Set up blank or default values for empty ones.
1346 5
		$args = wp_parse_args( $args, $defaults );
1347 5
1348
		/**
1349
		 * Filtering the CMB2 Field arguments once merged with the defaults, but before further processing.
1350 5
		 *
1351
		 * @since 2.6.0
1352
		 * @param array             $args  Metabox field config array defaults.
1353
		 * @param CMB2_Field object $field This field object.
1354
		 */
1355
		$args = apply_filters( 'cmb2_field_arguments_raw', $args, $this );
1356
1357
		/*
1358
		 * Deprecated usage:
1359
		 *
1360
		 * 'std' -- use 'default' (no longer works)
1361 1
		 * 'row_classes' -- use 'class', or 'class_cb'
1362 1
		 * 'default' -- as callback (use default_cb)
1363 1
		 */
1364
		$args = $this->convert_deprecated_params( $args );
1365 1
1366
		$args['repeatable'] = $args['repeatable'] && ! $this->repeatable_exception( $args['type'] );
1367
		$args['inline']     = $args['inline'] || false !== stripos( $args['type'], '_inline' );
1368
		$args['_id']        = $args['id'];
1369
		$args['_name']      = $args['id'];
1370
1371
		if ( $method = $this->has_args_method( $args['type'] ) ) {
1372
			$args = $this->{$method}( $args );
1373
		}
1374
1375
		if ( $this->group ) {
1376 20
			$args = $this->set_group_sub_field_defaults( $args );
1377 20
		}
1378 20
1379
		$args['has_supporting_data'] = in_array(
1380 20
			$args['type'],
1381 19
			array(
1382 19
				// CMB2_Sanitize::_save_file_id_value()/CMB2_Sanitize::_get_group_file_value_array().
1383
				'file',
1384
				// See CMB2_Sanitize::_save_utc_value().
1385 20
				'text_datetime_timestamp_timezone',
1386
			),
1387
			true
1388
		);
1389
1390
		// Repeatable fields require jQuery sortable library.
1391
		if ( ! empty( $args['repeatable'] ) ) {
1392
			CMB2_JS::add_dependencies( 'jquery-ui-sortable' );
1393
		}
1394
1395
		/**
1396 4
		 * Filter the CMB2 Field arguments after processing.
1397 4
		 *
1398 4
		 * @since 2.6.0
1399
		 * @param array             $args  Metabox field config array after processing.
1400 4
		 * @param CMB2_Field object $field This field object.
1401
		 */
1402
		return apply_filters( 'cmb2_field_arguments', $args, $this );
1403
	}
1404
1405
	/**
1406
	 * Sets default arguments for the group field types.
1407
	 *
1408
	 * @since 2.2.6
1409
	 *
1410
	 * @param  array $args Field config array.
1411 142
	 * @return array        Modified field config array.
1412 142
	 */
1413
	protected function set_field_defaults_group( $args ) {
1414
		$args['options'] = wp_parse_args( $args['options'], array(
1415 142
			'add_button'     => esc_html__( 'Add Group', 'cmb2' ),
1416 142
			'remove_button'  => esc_html__( 'Remove Group', 'cmb2' ),
1417 142
			'remove_confirm' => '',
1418 142
		) );
1419 142
1420
		return $args;
1421 142
	}
1422
1423 142
	/**
1424
	 * Sets default arguments for the wysiwyg field types.
1425
	 *
1426
	 * @since 2.2.6
1427 142
	 *
1428
	 * @param  array $args Field config array.
1429 142
	 * @return array        Modified field config array.
1430
	 */
1431
	protected function set_field_defaults_wysiwyg( $args ) {
1432 142
		$args['id'] = strtolower( str_ireplace( '-', '_', $args['id'] ) );
1433
		$args['options']['textarea_name'] = $args['_name'];
1434
1435
		return $args;
1436
	}
1437 142
1438 142
	/**
1439 142
	 * Sets default arguments for the all-or-nothing field types.
1440 142
	 *
1441 142
	 * @since 2.2.6
1442 142
	 *
1443 142
	 * @param  array $args Field config array.
1444
	 * @return array        Modified field config array.
1445
	 */
1446
	protected function set_field_defaults_all_or_nothing_types( $args ) {
1447
		$args['show_option_none'] = isset( $args['show_option_none'] ) ? $args['show_option_none'] : null;
1448
		$args['show_option_none'] = true === $args['show_option_none'] ? esc_html__( 'None', 'cmb2' ) : $args['show_option_none'];
1449
1450
		if ( null === $args['show_option_none'] ) {
1451
			$off_by_default = in_array( $args['type'], array( 'select', 'radio', 'radio_inline' ), true );
1452
			$args['show_option_none'] = $off_by_default ? false : esc_html__( 'None', 'cmb2' );
1453
		}
1454
1455
		return $args;
1456
	}
1457
1458 8
	/**
1459 8
	 * Sets default arguments for group sub-fields.
1460
	 *
1461 8
	 * @since 2.2.6
1462
	 *
1463
	 * @param  array $args Field config array.
1464 8
	 * @return array        Modified field config array.
1465
	 */
1466
	protected function set_group_sub_field_defaults( $args ) {
1467 8
		$args['id']    = $this->group->args( 'id' ) . '_' . $this->group->index . '_' . $args['id'];
1468
		$args['_name'] = $this->group->args( 'id' ) . '[' . $this->group->index . '][' . $args['_name'] . ']';
1469
1470
		return $args;
1471
	}
1472
1473
	/**
1474
	 * Gets the default arguments for all fields.
1475
	 *
1476
	 * @since 2.2.6
1477
	 *
1478
	 * @param  array $args Field config array.
1479
	 * @return array        Field defaults.
1480 8
	 */
1481 8
	protected function get_default_field_args( $args ) {
1482
		$type = isset( $args['type'] ) ? $args['type'] : '';
1483
1484
		return array(
1485
			'type'              => $type,
1486
			'name'              => '',
1487
			'desc'              => '',
1488
			'before'            => '',
1489
			'after'             => '',
1490
			'options'           => array(),
1491 2
			'options_cb'        => '',
1492 2
			'text'              => array(),
1493
			'text_cb'           => '',
1494
			'attributes'        => array(),
1495
			'protocols'         => null,
1496 2
			'default'           => null,
1497
			'default_cb'        => '',
1498
			'classes'           => null,
1499
			'classes_cb'        => '',
1500
			'select_all_button' => true,
1501
			'multiple'          => false,
1502
			'repeatable'        => 'group' === $type,
1503
			'inline'            => false,
1504
			'on_front'          => true,
1505
			'show_names'        => true,
1506 142
			'save_field'        => true, // Will not save if false.
1507
			'date_format'       => 'm\/d\/Y',
1508 142
			'time_format'       => 'h:i A',
1509
			'description'       => isset( $args['desc'] ) ? $args['desc'] : '',
1510
			'preview_size'      => 'file' === $type ? array( 350, 350 ) : array( 50, 50 ),
1511
			'render_row_cb'     => array( $this, 'render_field_callback' ),
1512
			'display_cb'        => array( $this, 'display_value_callback' ),
1513 2
			'label_cb'          => 'title' !== $type ? array( $this, 'label' ) : '',
1514
			'column'            => false,
1515 1
			'js_dependencies'   => array(),
1516
			'show_in_rest'      => null,
1517 1
		);
1518 1
	}
1519
1520
	/**
1521 1
	 * Get default field arguments specific to this CMB2 object.
1522
	 *
1523
	 * @since  2.2.0
1524 2
	 * @param  array      $field_args  Metabox field config array.
1525
	 * @param  CMB2_Field $field_group (optional) CMB2_Field object (group parent).
1526
	 * @return array                   Array of field arguments.
1527
	 */
1528 142
	protected function get_default_args( $field_args, $field_group = null ) {
1529
		$args = parent::get_default_args( array(), $this->group );
1530
1531
		if ( isset( $field_args['field_args'] ) ) {
1532
			$args = wp_parse_args( $field_args, $args );
1533
		} else {
1534
			$args['field_args'] = wp_parse_args( $field_args, $this->args );
1535
		}
1536
1537 142
		return $args;
1538
	}
1539
1540
	/**
1541
	 * Returns a cloned version of this field object, but with
1542
	 * modified/overridden field arguments.
1543
	 *
1544
	 * @since  2.2.2
1545 142
	 * @param  array $field_args Array of field arguments, or entire array of
1546
	 *                           arguments for CMB2_Field.
1547
	 *
1548
	 * @return CMB2_Field         The new CMB2_Field instance.
1549
	 */
1550
	public function get_field_clone( $field_args ) {
1551
		return $this->get_new_field( $field_args );
1552
	}
1553
1554
	/**
1555
	 * Returns the CMB2 instance this field is registered to.
1556
	 *
1557
	 * @since  2.2.2
1558
	 *
1559
	 * @return CMB2|WP_Error If new CMB2_Field is called without cmb_id arg, returns error.
1560
	 */
1561
	public function get_cmb() {
1562
		if ( ! $this->cmb_id ) {
1563
			return new WP_Error( 'no_cmb_id', esc_html__( 'Sorry, this field does not have a cmb_id specified.', 'cmb2' ) );
1564
		}
1565
1566
		return cmb2_get_metabox( $this->cmb_id, $this->object_id, $this->object_type );
1567
	}
1568
1569
	/**
1570
	 * Converts deprecated field parameters to the current/proper parameter, and throws a deprecation notice.
1571
	 *
1572
	 * @since  2.2.3
1573
	 * @param  array $args Metabox field config array.
1574
	 * @return array       Modified field config array.
1575
	 */
1576
	protected function convert_deprecated_params( $args ) {
1577
1578
		if ( isset( $args['row_classes'] ) ) {
1579
1580
			// We'll let this one be.
1581
			// $this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_PARAM, 'row_classes', 'classes' );
1582
			// row_classes param could be a callback. This is definitely deprecated.
1583
			if ( is_callable( $args['row_classes'] ) ) {
1584
1585
				$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'row_classes', 'classes_cb' );
1586
1587
				$args['classes_cb'] = $args['row_classes'];
1588
				$args['classes'] = null;
1589
			} else {
1590
1591
				$args['classes'] = $args['row_classes'];
1592
			}
1593
1594
			unset( $args['row_classes'] );
1595
		}
1596
1597
		// default param can be passed a callback as well.
1598
		if ( is_callable( $args['default'] ) ) {
1599
1600
			$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'default', 'default_cb' );
1601
1602
			$args['default_cb'] = $args['default'];
1603
			$args['default'] = null;
1604
		}
1605
1606
		// options param can be passed a callback as well.
1607
		if ( is_callable( $args['options'] ) ) {
1608
1609
			$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'options', 'options_cb' );
1610
1611
			$args['options_cb'] = $args['options'];
1612
			$args['options'] = array();
1613
		}
1614
1615
		return $args;
1616
	}
1617
1618
}
1619