CMB2_Field   F
last analyzed

Complexity

Total Complexity 172

Size/Duplication

Total Lines 1531
Duplicated Lines 0 %

Test Coverage

Coverage 88.7%

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 172
eloc 442
c 7
b 0
f 0
dl 0
loc 1531
ccs 369
cts 416
cp 0.887
rs 2

50 Methods

Rating   Name   Duplication   Size   Complexity  
A value() 0 2 1
A id() 0 3 2
A args() 0 13 4
A __call() 0 7 3
B __construct() 0 20 7
B get_data() 0 62 9
A _data() 0 6 3
A js_data() 0 12 2
A get_default() 0 12 3
A has_args_method() 0 27 3
A group_id() 0 2 2
A get_rest_value() 0 43 2
A get_field_clone() 0 2 1
A options() 0 10 4
A data_args() 0 9 1
A set_field_defaults_all_or_nothing_types() 0 10 5
C save_field() 0 69 13
A register_js_data() 0 6 2
A render_field() 0 7 1
A get_timestamp_from_value() 0 2 1
A get_default_field_args() 0 36 5
A add_js_dependencies() 0 6 2
B get_string() 0 23 7
A hash_id() 0 6 2
A label() 0 8 3
A get_default_args() 0 10 2
A set_field_defaults_wysiwyg() 0 5 1
A set_options() 0 12 4
A field_timezone_offset() 0 2 1
A field_timezone() 0 13 3
A render_column() 0 7 1
A save_field_from_data() 0 8 2
A get_cmb() 0 6 2
A get_timestamp_format() 0 11 4
A format_timestamp() 0 2 1
B row_classes() 0 50 9
A set_field_defaults_group() 0 7 1
A val_or_default() 0 2 2
A replace_hash() 0 3 1
A set_group_sub_field_defaults() 0 5 1
A sanitization_cb() 0 43 6
A remove_data() 0 57 4
A escaping_exception() 0 6 1
B escaped_value() 0 54 10
A display_value_callback() 0 43 3
B update_data() 0 65 8
A repeatable_exception() 0 33 1
B render_field_callback() 0 43 6
A _set_field_defaults() 0 39 5
A convert_deprecated_params() 0 40 5

How to fix   Complexity   

Complex Class

Complex classes like CMB2_Field often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CMB2_Field, and based on these observations, apply Extract Interface, too.

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
		$this->peform_param_callback( 'before_row' );
887
888 14
		printf( "<div class=\"cmb-row %s\" data-fieldtype=\"%s\">\n", $this->row_classes(), $this->type() );
889
890
		if ( ! $this->args( 'show_names' ) ) {
891
			echo "\n\t<div class=\"cmb-td\">\n";
892
893
			$this->peform_param_callback( 'label_cb' );
894
895 14
		} else {
896 14
897
			if ( $this->get_param_callback_result( 'label_cb' ) ) {
898
				echo '<div class="cmb-th">', $this->peform_param_callback( 'label_cb' ), '</div>';
899 14
			}
900
901
			echo "\n\t<div class=\"cmb-td\">\n";
902 14
		}
903
904 14
		$this->peform_param_callback( 'before' );
905 14
906
		$types = new CMB2_Types( $this );
907 14
		$types->render();
908
909 14
		$this->peform_param_callback( 'after' );
910
911 14
		echo "\n\t</div>\n</div>";
912
913
		$this->peform_param_callback( 'after_row' );
914 14
915
		// For chaining.
916
		return $this;
917
	}
918
919
	/**
920
	 * The default label_cb callback (if not a title field)
921
	 *
922
	 * @since  2.1.1
923 14
	 * @return string Label html markup.
924 14
	 */
925
	public function label() {
926
		if ( ! $this->args( 'name' ) ) {
927
			return '';
928 14
		}
929
930 14
		$style = ! $this->args( 'show_names' ) ? ' style="display:none;"' : '';
931
932
		return sprintf( "\n" . '<label%1$s for="%2$s">%3$s</label>' . "\n", $style, $this->id(), $this->args( 'name' ) );
933
	}
934
935
	/**
936
	 * Defines the classes for the current CMB2 field row
937
	 *
938
	 * @since  2.0.0
939 50
	 * @return string Space concatenated list of classes
940
	 */
941 50
	public function row_classes() {
942
943
		$classes = array();
944
945
		/**
946
		 * By default, 'text_url' and 'text' fields get table-like styling
947
		 *
948
		 * @since 2.0.0
949
		 *
950 50
		 * @param array $field_types The types of fields which should get the 'table-layout' class
951 50
		 */
952
		$repeat_table_rows_types = apply_filters( 'cmb2_repeat_table_row_types', array(
953
			'text_url',
954
			'text',
955
		) );
956 50
957 50
		$conditional_classes = array(
958 50
			'cmb-type-' . str_replace( '_', '-', sanitize_html_class( $this->type() ) ) => true,
959 50
			'cmb2-id-' . str_replace( '_', '-', sanitize_html_class( $this->id() ) )    => true,
960 50
			'cmb-repeat'             => $this->args( 'repeatable' ),
961 50
			'cmb-repeat-group-field' => $this->group,
962
			'cmb-inline'             => $this->args( 'inline' ),
963
			'table-layout'           => 'edit' === $this->render_context && in_array( $this->type(), $repeat_table_rows_types ),
964 50
		);
965 50
966 50
		foreach ( $conditional_classes as $class => $condition ) {
967
			if ( $condition ) {
968
				$classes[] = $class;
969
			}
970 50
		}
971 1
972 49
		if ( $added_classes = $this->args( 'classes' ) ) {
973 2
			$added_classes = is_array( $added_classes ) ? implode( ' ', $added_classes ) : (string) $added_classes;
974
		} elseif ( $added_classes = $this->get_param_callback_result( 'classes_cb' ) ) {
975
			$added_classes = is_array( $added_classes ) ? implode( ' ', $added_classes ) : (string) $added_classes;
976 50
		}
977 3
978
		if ( $added_classes ) {
979
			$classes[] = esc_attr( $added_classes );
980
		}
981
982
		/**
983
		 * Globally filter row classes
984
		 *
985
		 * @since 2.0.0
986
		 *
987
		 * @param string            $classes Space-separated list of row classes
988 50
		 * @param CMB2_Field object $field   This field object
989
		 */
990
		return apply_filters( 'cmb2_row_classes', implode( ' ', $classes ), $this );
991
	}
992
993
	/**
994
	 * Get field display callback and render the display value in the column.
995
	 *
996 33
	 * @since 2.2.2
997 33
	 */
998
	public function render_column() {
999 33
		$this->render_context = 'display';
1000
1001
		$this->peform_param_callback( 'display_cb' );
1002 33
1003
		// For chaining.
1004
		return $this;
1005
	}
1006
1007
	/**
1008
	 * The method to fetch the value for this field for the REST API.
1009
	 *
1010 3
	 * @since 2.5.0
1011 3
	 */
1012 3
	public function get_rest_value() {
1013
		$field_type = $this->type();
1014 3
		$field_id   = $this->id( true );
1015
1016
		if ( $cb = $this->maybe_callback( 'rest_value_cb' ) ) {
1017
			apply_filters( "cmb2_get_rest_value_for_{$field_id}", $cb, 99 );
1018 3
		}
1019
1020
		$value = $this->get_data();
1021
1022
		/**
1023
		 * Filter the value before it is sent to the REST request.
1024
		 *
1025
		 * @since 2.5.0
1026
		 *
1027
		 * @param mixed      $value The value from CMB2_Field::get_data()
1028 3
		 * @param CMB2_Field $field This field object.
1029
		 */
1030
		$value = apply_filters( 'cmb2_get_rest_value', $value, $this );
1031
1032
		/**
1033
		 * Filter the value before it is sent to the REST request.
1034
		 *
1035
		 * The dynamic portion of the hook name, $field_type, refers to the field type.
1036
		 *
1037
		 * @since 2.5.0
1038
		 *
1039
		 * @param mixed      $value The value from CMB2_Field::get_data()
1040 3
		 * @param CMB2_Field $field This field object.
1041
		 */
1042
		$value = apply_filters( "cmb2_get_rest_value_{$field_type}", $value, $this );
1043
1044
		/**
1045
		 * Filter the value before it is sent to the REST request.
1046
		 *
1047
		 * The dynamic portion of the hook name, $field_id, refers to the field id.
1048
		 *
1049
		 * @since 2.5.0
1050
		 *
1051
		 * @param mixed      $value The value from CMB2_Field::get_data()
1052 3
		 * @param CMB2_Field $field This field object.
1053
		 */
1054
		return apply_filters( "cmb2_get_rest_value_for_{$field_id}", $value, $this );
1055
	}
1056
1057
	/**
1058
	 * Default callback to outputs field value in a display format.
1059
	 *
1060 33
	 * @since 2.2.2
1061
	 */
1062 33
	public function display_value_callback() {
1063
		// If field is requesting to be conditionally shown.
1064
		if ( ! $this->should_show() ) {
1065
			return;
1066 33
		}
1067 33
1068
		$display = new CMB2_Field_Display( $this );
1069
		$field_type = $this->type();
1070
1071
		/**
1072
		 * A filter to bypass the default display.
1073
		 *
1074
		 * The dynamic portion of the hook name, $field_type, refers to the field type.
1075
		 *
1076
		 * Passing a non-null value to the filter will short-circuit the default display.
1077
		 *
1078
		 * @param bool|mixed         $pre_output Default null value.
1079
		 * @param CMB2_Field         $field      This field object.
1080 33
		 * @param CMB2_Field_Display $display    The `CMB2_Field_Display` object.
1081
		 */
1082 33
		$pre_output = apply_filters( "cmb2_pre_field_display_{$field_type}", null, $this, $display );
1083
1084
		if ( null !== $pre_output ) {
1085
			echo $pre_output;
1086
			return;
1087 33
		}
1088
1089 33
		$this->peform_param_callback( 'before_display_wrap' );
1090
1091 33
		printf( "<div class=\"cmb-column %s\" data-fieldtype=\"%s\">\n", $this->row_classes(), $field_type );
1092
1093 33
		$this->peform_param_callback( 'before_display' );
1094
1095 33
		CMB2_Field_Display::get( $this )->display();
1096
1097 33
		$this->peform_param_callback( 'after_display' );
1098
1099 33
		echo "\n</div>";
1100
1101
		$this->peform_param_callback( 'after_display_wrap' );
1102 33
1103
		// For chaining.
1104
		return $this;
1105
	}
1106
1107
	/**
1108
	 * Replaces a hash key - {#} - with the repeatable index
1109
	 *
1110
	 * @since  1.2.0
1111
	 * @param  string $value Value to update.
1112 2
	 * @return string        Updated value
1113
	 */
1114 2
	public function replace_hash( $value ) {
1115
		// Replace hash with 1 based count.
1116
		return str_replace( '{#}', ( $this->index + 1 ), $value );
1117
	}
1118
1119
	/**
1120
	 * Retrieve text parameter from field's text array (if it has one), or use fallback text
1121
	 * For back-compatibility, falls back to checking the options array.
1122
	 *
1123
	 * @since  2.2.2
1124
	 * @param  string $text_key Key in field's text array.
1125
	 * @param  string $fallback Fallback text.
1126 10
	 * @return string            Text
1127
	 */
1128 10
	public function get_string( $text_key, $fallback ) {
1129 10
		// If null, populate with our field strings values.
1130
		if ( null === $this->strings ) {
1131 10
			$this->strings = (array) $this->args['text'];
1132
1133
			if ( is_callable( $this->args['text_cb'] ) ) {
1134
				$strings = call_user_func( $this->args['text_cb'], $this );
1135
1136
				if ( $strings && is_array( $strings ) ) {
1137
					$this->strings += $strings;
1138
				}
1139
			}
1140
		}
1141 10
1142 1
		// If we have that string value, send it back.
1143
		if ( isset( $this->strings[ $text_key ] ) ) {
1144
			return $this->strings[ $text_key ];
1145
		}
1146 10
1147
		// Check options for back-compat.
1148 10
		$string = $this->options( $text_key );
1149
1150
		return $string ? $string : $fallback;
1151
	}
1152
1153
	/**
1154
	 * Retrieve options args.
1155
	 *
1156
	 * @since  2.0.0
1157
	 * @param  string $key Specific option to retrieve.
1158 47
	 * @return array|mixed Array of options or specific option.
1159 47
	 */
1160 47
	public function options( $key = '' ) {
1161
		if ( empty( $this->field_options ) ) {
1162
			$this->set_options();
1163 47
		}
1164 16
1165
		if ( $key ) {
1166
			return array_key_exists( $key, $this->field_options ) ? $this->field_options[ $key ] : false;
1167 36
		}
1168
1169
		return $this->field_options;
1170
	}
1171
1172
	/**
1173
	 * Generates/sets options args. Calls options_cb if it exists.
1174
	 *
1175
	 * @since  2.2.5
1176
	 *
1177 47
	 * @return array Array of options
1178 47
	 */
1179
	public function set_options() {
1180 47
		$this->field_options = (array) $this->args['options'];
1181 1
1182
		if ( is_callable( $this->args['options_cb'] ) ) {
1183 1
			$options = call_user_func( $this->args['options_cb'], $this );
1184 1
1185
			if ( $options && is_array( $options ) ) {
1186
				$this->field_options = $options + $this->field_options;
1187
			}
1188 47
		}
1189
1190
		return $this->field_options;
1191
	}
1192
1193
	/**
1194
	 * Store JS dependencies as part of the field args.
1195
	 *
1196
	 * @since 2.2.0
1197 14
	 * @param array $dependencies Dependies to register for this field.
1198 14
	 */
1199 14
	public function add_js_dependencies( $dependencies = array() ) {
1200
		foreach ( (array) $dependencies as $dependency ) {
1201
			$this->args['js_dependencies'][ $dependency ] = $dependency;
1202 14
		}
1203 14
1204
		CMB2_JS::add_dependencies( $dependencies );
1205
	}
1206
1207
	/**
1208
	 * Send field data to JS.
1209
	 *
1210 57
	 * @since 2.2.0
1211 57
	 */
1212 2
	public function register_js_data() {
1213
		if ( $this->group ) {
1214
			CMB2_JS::add_field_data( $this->group );
1215 57
		}
1216
1217
		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...
1218
	}
1219
1220
	/**
1221
	 * Get an array of some of the field data to be used in the Javascript.
1222
	 *
1223
	 * @since  2.2.4
1224
	 *
1225 15
	 * @return array
1226
	 */
1227 15
	public function js_data() {
1228 15
		return array(
1229 15
			'label'     => $this->args( 'name' ),
1230 15
			'id'        => $this->id( true ),
1231 15
			'type'      => $this->type(),
1232 15
			'hash'      => $this->hash_id(),
1233 15
			'box'       => $this->cmb_id,
1234 15
			'id_attr'   => $this->id(),
1235 15
			'name_attr' => $this->args( '_name' ),
1236 15
			'default'   => $this->get_default(),
1237
			'group'     => $this->group_id(),
1238
			'index'     => $this->group ? $this->group->index : null,
1239
		);
1240
	}
1241
1242
	/**
1243
	 * Returns a unique hash representing this field.
1244
	 *
1245
	 * @since  2.2.4
1246
	 *
1247 57
	 * @return string
1248 57
	 */
1249 57
	public function hash_id() {
1250
		if ( '' === $this->hash_id ) {
1251
			$this->hash_id = CMB2_Utils::generate_hash( $this->cmb_id . '||' . $this->id() );
1252 57
		}
1253
1254
		return $this->hash_id;
1255
	}
1256
1257
	/**
1258
	 * Gets the id of the group field if this field is part of a group.
1259
	 *
1260
	 * @since  2.2.4
1261
	 *
1262 15
	 * @return string
1263 15
	 */
1264
	public function group_id() {
1265
		return $this->group ? $this->group->id( true ) : '';
1266
	}
1267
1268
	/**
1269
	 * Get CMB2_Field default value, either from default param or default_cb param.
1270
	 *
1271
	 * @since  0.2.2
1272
	 *
1273 46
	 * @return mixed  Default field value
1274 46
	 */
1275
	public function get_default() {
1276 46
		$default = $this->args['default'];
1277 17
1278
		if ( null !== $default ) {
1279
			return apply_filters( 'cmb2_default_filter', $default, $this );
1280 45
		}
1281 45
1282
		$param = is_callable( $this->args['default_cb'] ) ? 'default_cb' : 'default';
1283
		$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...
1284 45
1285
		// Allow a filter override of the default value.
1286
		return apply_filters( 'cmb2_default_filter', $this->args['default'], $this );
1287
	}
1288
1289
	/**
1290
	 * Fills in empty field parameters with defaults
1291
	 *
1292
	 * @since 1.1.0
1293
	 *
1294
	 * @param  array $args Field config array.
1295 142
	 * @return array        Modified field config array.
1296
	 */
1297
	public function _set_field_defaults( $args ) {
1298 142
1299
		// Set up blank or default values for empty ones.
1300
		$args = wp_parse_args( $args, $this->get_default_field_args( $args ) );
1301
1302
		/*
1303
		 * Deprecated usage:
1304
		 *
1305
		 * 'std' -- use 'default' (no longer works)
1306
		 * 'row_classes' -- use 'class', or 'class_cb'
1307 142
		 * 'default' -- as callback (use default_cb)
1308
		 */
1309 142
		$args = $this->convert_deprecated_params( $args );
1310 142
1311 142
		$args['repeatable'] = $args['repeatable'] && ! $this->repeatable_exception( $args['type'] );
1312 142
		$args['inline']     = $args['inline'] || false !== stripos( $args['type'], '_inline' );
1313
		$args['_id']        = $args['id'];
1314 142
		$args['_name']      = $args['id'];
1315 26
1316
		if ( $method = $this->has_args_method( $args['type'] ) ) {
1317
			$args = $this->{$method}( $args );
1318 142
		}
1319 4
1320
		if ( $this->group ) {
1321
			$args = $this->set_group_sub_field_defaults( $args );
1322 142
		}
1323 142
1324
		$args['has_supporting_data'] = in_array(
1325
			$args['type'],
1326 142
			array(
1327
				// CMB2_Sanitize::_save_file_id_value()/CMB2_Sanitize::_get_group_file_value_array().
1328
				'file',
1329
				// See CMB2_Sanitize::_save_utc_value().
1330 142
				'text_datetime_timestamp_timezone',
1331
			),
1332
			true
1333 142
		);
1334
1335
		return $args;
1336
	}
1337
1338
	/**
1339
	 * Sets default arguments for the group field types.
1340
	 *
1341
	 * @since 2.2.6
1342
	 *
1343
	 * @param  array $args Field config array.
1344 5
	 * @return array        Modified field config array.
1345 5
	 */
1346 5
	protected function set_field_defaults_group( $args ) {
1347 5
		$args['options'] = wp_parse_args( $args['options'], array(
1348
			'add_button'    => esc_html__( 'Add Group', 'cmb2' ),
1349
			'remove_button' => esc_html__( 'Remove Group', 'cmb2' ),
1350 5
		) );
1351
1352
		return $args;
1353
	}
1354
1355
	/**
1356
	 * Sets default arguments for the wysiwyg field types.
1357
	 *
1358
	 * @since 2.2.6
1359
	 *
1360
	 * @param  array $args Field config array.
1361 1
	 * @return array        Modified field config array.
1362 1
	 */
1363 1
	protected function set_field_defaults_wysiwyg( $args ) {
1364
		$args['id'] = strtolower( str_ireplace( '-', '_', $args['id'] ) );
1365 1
		$args['options']['textarea_name'] = $args['_name'];
1366
1367
		return $args;
1368
	}
1369
1370
	/**
1371
	 * Sets default arguments for the all-or-nothing field types.
1372
	 *
1373
	 * @since 2.2.6
1374
	 *
1375
	 * @param  array $args Field config array.
1376 20
	 * @return array        Modified field config array.
1377 20
	 */
1378 20
	protected function set_field_defaults_all_or_nothing_types( $args ) {
1379
		$args['show_option_none'] = isset( $args['show_option_none'] ) ? $args['show_option_none'] : null;
1380 20
		$args['show_option_none'] = true === $args['show_option_none'] ? esc_html__( 'None', 'cmb2' ) : $args['show_option_none'];
1381 19
1382 19
		if ( null === $args['show_option_none'] ) {
1383
			$off_by_default = in_array( $args['type'], array( 'select', 'radio', 'radio_inline' ), true );
1384
			$args['show_option_none'] = $off_by_default ? false : esc_html__( 'None', 'cmb2' );
1385 20
		}
1386
1387
		return $args;
1388
	}
1389
1390
	/**
1391
	 * Sets default arguments for group sub-fields.
1392
	 *
1393
	 * @since 2.2.6
1394
	 *
1395
	 * @param  array $args Field config array.
1396 4
	 * @return array        Modified field config array.
1397 4
	 */
1398 4
	protected function set_group_sub_field_defaults( $args ) {
1399
		$args['id']    = $this->group->args( 'id' ) . '_' . $this->group->index . '_' . $args['id'];
1400 4
		$args['_name'] = $this->group->args( 'id' ) . '[' . $this->group->index . '][' . $args['_name'] . ']';
1401
1402
		return $args;
1403
	}
1404
1405
	/**
1406
	 * Gets the default arguments for all fields.
1407
	 *
1408
	 * @since 2.2.6
1409
	 *
1410
	 * @param  array $args Field config array.
1411 142
	 * @return array        Field defaults.
1412 142
	 */
1413
	protected function get_default_field_args( $args ) {
1414
		$type = isset( $args['type'] ) ? $args['type'] : '';
1415 142
1416 142
		return array(
1417 142
			'type'              => $type,
1418 142
			'name'              => '',
1419 142
			'desc'              => '',
1420
			'before'            => '',
1421 142
			'after'             => '',
1422
			'options'           => array(),
1423 142
			'options_cb'        => '',
1424
			'text'              => array(),
1425
			'text_cb'           => '',
1426
			'attributes'        => array(),
1427 142
			'protocols'         => null,
1428
			'default'           => null,
1429 142
			'default_cb'        => '',
1430
			'classes'           => null,
1431
			'classes_cb'        => '',
1432 142
			'select_all_button' => true,
1433
			'multiple'          => false,
1434
			'repeatable'        => 'group' === $type,
1435
			'inline'            => false,
1436
			'on_front'          => true,
1437 142
			'show_names'        => true,
1438 142
			'save_field'        => true, // Will not save if false.
1439 142
			'date_format'       => 'm\/d\/Y',
1440 142
			'time_format'       => 'h:i A',
1441 142
			'description'       => isset( $args['desc'] ) ? $args['desc'] : '',
1442 142
			'preview_size'      => 'file' === $type ? array( 350, 350 ) : array( 50, 50 ),
1443 142
			'render_row_cb'     => array( $this, 'render_field_callback' ),
1444
			'display_cb'        => array( $this, 'display_value_callback' ),
1445
			'label_cb'          => 'title' !== $type ? array( $this, 'label' ) : '',
1446
			'column'            => false,
1447
			'js_dependencies'   => array(),
1448
			'show_in_rest'      => null,
1449
		);
1450
	}
1451
1452
	/**
1453
	 * Get default field arguments specific to this CMB2 object.
1454
	 *
1455
	 * @since  2.2.0
1456
	 * @param  array      $field_args  Metabox field config array.
1457
	 * @param  CMB2_Field $field_group (optional) CMB2_Field object (group parent).
1458 8
	 * @return array                   Array of field arguments.
1459 8
	 */
1460
	protected function get_default_args( $field_args, $field_group = null ) {
1461 8
		$args = parent::get_default_args( array(), $this->group );
1462
1463
		if ( isset( $field_args['field_args'] ) ) {
1464 8
			$args = wp_parse_args( $field_args, $args );
1465
		} else {
1466
			$args['field_args'] = wp_parse_args( $field_args, $this->args );
1467 8
		}
1468
1469
		return $args;
1470
	}
1471
1472
	/**
1473
	 * Returns a cloned version of this field object, but with
1474
	 * modified/overridden field arguments.
1475
	 *
1476
	 * @since  2.2.2
1477
	 * @param  array $field_args Array of field arguments, or entire array of
1478
	 *                           arguments for CMB2_Field.
1479
	 *
1480 8
	 * @return CMB2_Field         The new CMB2_Field instance.
1481 8
	 */
1482
	public function get_field_clone( $field_args ) {
1483
		return $this->get_new_field( $field_args );
1484
	}
1485
1486
	/**
1487
	 * Returns the CMB2 instance this field is registered to.
1488
	 *
1489
	 * @since  2.2.2
1490
	 *
1491 2
	 * @return CMB2|WP_Error If new CMB2_Field is called without cmb_id arg, returns error.
1492 2
	 */
1493
	public function get_cmb() {
1494
		if ( ! $this->cmb_id ) {
1495
			return new WP_Error( 'no_cmb_id', esc_html__( 'Sorry, this field does not have a cmb_id specified.', 'cmb2' ) );
1496 2
		}
1497
1498
		return cmb2_get_metabox( $this->cmb_id, $this->object_id, $this->object_type );
1499
	}
1500
1501
	/**
1502
	 * Converts deprecated field parameters to the current/proper parameter, and throws a deprecation notice.
1503
	 *
1504
	 * @since  2.2.3
1505
	 * @param  array $args Metabox field config array.
1506 142
	 * @return array       Modified field config array.
1507
	 */
1508 142
	protected function convert_deprecated_params( $args ) {
1509
1510
		if ( isset( $args['row_classes'] ) ) {
1511
1512
			// We'll let this one be.
1513 2
			// $this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_PARAM, 'row_classes', 'classes' );
1514
			// row_classes param could be a callback. This is definitely deprecated.
1515 1
			if ( is_callable( $args['row_classes'] ) ) {
1516
1517 1
				$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'row_classes', 'classes_cb' );
1518 1
1519
				$args['classes_cb'] = $args['row_classes'];
1520
				$args['classes'] = null;
1521 1
			} else {
1522
1523
				$args['classes'] = $args['row_classes'];
1524 2
			}
1525
1526
			unset( $args['row_classes'] );
1527
		}
1528 142
1529
		// default param can be passed a callback as well.
1530
		if ( is_callable( $args['default'] ) ) {
1531
1532
			$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'default', 'default_cb' );
1533
1534
			$args['default_cb'] = $args['default'];
1535
			$args['default'] = null;
1536
		}
1537 142
1538
		// options param can be passed a callback as well.
1539
		if ( is_callable( $args['options'] ) ) {
1540
1541
			$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'options', 'options_cb' );
1542
1543
			$args['options_cb'] = $args['options'];
1544
			$args['options'] = array();
1545 142
		}
1546
1547
		return $args;
1548
	}
1549
1550
}
1551