Completed
Pull Request — trunk (#541)
by Justin
04:46
created

CMB2_Field::get_timestamp_format()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 8
c 0
b 0
f 0
nc 6
nop 2
dl 0
loc 12
ccs 10
cts 10
cp 1
crap 4
rs 9.2
1
<?php
2
/**
3
 * CMB2 field objects
4
 *
5
 * @since  1.1.0
6
 *
7
 * @category  WordPress_Plugin
8
 * @package   CMB2
9
 * @author    WebDevStudios
10
 * @license   GPL-2.0+
11
 * @link      http://webdevstudios.com
12
 *
13
 * @method string _id()
14
 * @method string type()
15
 * @method mixed fields()
16
 */
17
class CMB2_Field extends CMB2_Base {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
18
19
	/**
20
	 * The object properties name.
21
	 * @var   string
22
	 * @since 2.2.3
23
	 */
24
	protected $properties_name = 'args';
25
26
	/**
27
	 * Field arguments
28
	 * @var   mixed
29
	 * @since 1.1.0
30
	 */
31
	public $args = array();
32
33
	/**
34
	 * Field group object or false (if no group)
35
	 * @var   mixed
36
	 * @since 1.1.0
37
	 */
38
	public $group = false;
39
40
	/**
41
	 * Field meta value
42
	 * @var   mixed
43
	 * @since 1.1.0
44
	 */
45
	public $value = null;
46
47
	/**
48
	 * Field meta value
49 46
	 * @var   mixed
50
	 * @since 1.1.0
51 46
	 */
52
	public $escaped_value = null;
53
54
	/**
55
	 * Grouped Field's current numeric index during the save process
56 46
	 * @var   mixed
57 46
	 * @since 2.0.0
58 46
	 */
59
	public $index = 0;
60
61 46
	/**
62
	 * Array of field options
63
	 * @var   array
64
	 * @since 2.0.0
65
	 */
66
	protected $field_options = array();
67
68
	/**
69
	 * Array of provided field text strings
70
	 * @var   array
71
	 * @since 2.0.0
72
	 */
73
	protected $strings;
74
75
	/**
76
	 * The field's render context. In most cases, 'edit', but can be 'display'.
77
	 * @var   string
78 46
	 * @since 2.2.2
79
	 */
80
	public $render_context = 'edit';
81
82
	/**
83
	 * All CMB2_Field callable field arguments.
84
	 * Can be used to determine if a field argument is callable.
85
	 *
86
	 * @var array
87
	 */
88
	public static $callable_fields = array(
89
		'default_cb',
90
		'classes_cb',
91
		'options_cb',
92
		'text_cb',
93
		'label_cb',
94
		'render_row_cb',
95
		'display_cb',
96
		'before_group',
97 46
		'before_group_row',
98
		'before_row',
99
		'before',
100 46
		'before_field',
101 46
		'after_field',
102 46
		'after',
103 46
		'after_row',
104
		'after_group_row',
105
		'after_group',
106
	);
107
108
	/**
109
	 * Constructs our field object
110
	 * @since 1.1.0
111
	 * @param array $args Field arguments
112 38
	 */
113 38
	public function __construct( $args ) {
114 38
115
		if ( ! empty( $args['group_field'] ) ) {
116
			$this->group       = $args['group_field'];
117
			$this->object_id   = $this->group->object_id;
118
			$this->object_type = $this->group->object_type;
119
			$this->cmb_id      = $this->group->cmb_id;
120
		} else {
121
			$this->object_id   = isset( $args['object_id'] ) && '_' !== $args['object_id'] ? $args['object_id'] : 0;
122
			$this->object_type = isset( $args['object_type'] ) ? $args['object_type'] : 'post';
123 46
124 46
			if ( isset( $args['cmb_id'] ) ) {
125 46
				$this->cmb_id = $args['cmb_id'];
126
			}
127
		}
128
129
		$this->args = $this->_set_field_defaults( $args['field_args'], $args );
0 ignored issues
show
Unused Code introduced by
The call to CMB2_Field::_set_field_defaults() has too many arguments starting with $args.

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

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

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

Loading history...
130
131
		if ( $this->object_id ) {
132
			$this->value = $this->get_data();
133
		}
134
	}
135 46
136 46
	/**
137 46
	 * Non-existent methods fallback to checking for field arguments of the same name
138
	 * @since  1.1.0
139
	 * @param  string $name     Method name
140 46
	 * @param  array  $arguments Array of passed-in arguments
141
	 * @return mixed             Value of field argument
142
	 */
143
	public function __call( $name, $arguments ) {
144
		if ( 'string' === $name ) {
145
			return call_user_func_array( array( $this, 'get_string' ), $arguments );
146
		}
147
148
		$key = isset( $arguments[0] ) ? $arguments[0] : false;
149 37
		return $this->args( $name, $key );
150 37
	}
151
152
	/**
153
	 * Retrieves the field id
154
	 * @since  1.1.0
155
	 * @param  boolean $raw Whether to retrieve pre-modidifed id
156
	 * @return string       Field id
157
	 */
158
	public function id( $raw = false ) {
159
		$id = $raw ? '_id' : 'id';
160 46
		return $this->args( $id );
161 46
	}
162 46
163 46
	/**
164
	 * Get a field argument
165 46
	 * @since  1.1.0
166
	 * @param  string $key  Argument to check
167
	 * @param  string $_key Sub argument to check
168
	 * @return mixed        Argument value or false if non-existent
169
	 */
170
	public function args( $key = '', $_key = '' ) {
171
		$arg = $this->_data( 'args', $key );
172
173
		if ( in_array( $key, array( 'default', 'default_cb' ), true ) ) {
174 46
175 46
			$arg = $this->get_default();
176
177 46
		} elseif ( $_key ) {
178
179
			$arg = isset( $arg[ $_key ] ) ? $arg[ $_key ] : false;
180
		}
181 46
182
		return $arg;
183 46
	}
184 46
185 46
	/**
186
	 * Retrieve a portion of a field property
187 46
	 * @since  1.1.0
188
	 * @param  string  $var Field property to check
189
	 * @param  string  $key Field property array key to check
190
	 * @return mixed        Queried property value or false
191
	 */
192 46
	public function _data( $var, $key = '' ) {
193
		$vars = $this->{$var};
194
		if ( $key ) {
195
			return array_key_exists( $key, $vars ) ? $vars[ $key ] : false;
196
		}
197
		return $vars;
198
	}
199
200
	/**
201
	 * Get Field's value
202
	 * @since  1.1.0
203
	 * @param  string $key If value is an array, is used to get array key->value
204
	 * @return mixed       Field value or false if non-existent
205
	 */
206
	public function value( $key = '' ) {
207
		return $this->_data( 'value', $key );
208
	}
209
210
	/**
211
	 * Retrieves metadata/option data
212
	 * @since  1.0.1
213
	 * @param  string $field_id Meta key/Option array key
214
	 * @param  array  $args     Override arguments
215
	 * @return mixed            Meta/Option value
216
	 */
217
	public function get_data( $field_id = '', $args = array() ) {
218
		if ( $field_id ) {
219
			$args['field_id'] = $field_id;
220
		} else if ( $this->group ) {
221
			$args['field_id'] = $this->group->id();
222
		}
223
224
		$a = $this->data_args( $args );
225
226
		/**
227
		 * Filter whether to override getting of meta value.
228
		 * Returning a non 'cmb2_field_no_override_val' value
229
		 * will effectively short-circuit the value retrieval.
230
		 *
231
		 * @since 2.0.0
232
		 *
233
		 * @param mixed $value     The value get_metadata() should
234
		 *                         return - a single metadata value,
235
		 *                         or an array of values.
236
		 *
237
		 * @param int   $object_id Object ID.
238
		 *
239
		 * @param array $args {
240
		 *     An array of arguments for retrieving data
241
		 *
242
		 *     @type string $type     The current object type
243
		 *     @type int    $id       The current object ID
244
		 *     @type string $field_id The ID of the field being requested
245
		 *     @type bool   $repeat   Whether current field is repeatable
246
		 *     @type bool   $single   Whether current field is a single database row
247
		 * }
248
		 *
249
		 * @param CMB2_Field object $field This field object
250
		 */
251
		$data = apply_filters( 'cmb2_override_meta_value', 'cmb2_field_no_override_val', $this->object_id, $a, $this );
252
253
		/**
254
		 * Filter and parameters are documented for 'cmb2_override_meta_value' filter (above).
255
		 *
256
		 * The dynamic portion of the hook, $field_id, refers to the current
257
		 * field id paramater. Returning a non 'cmb2_field_no_override_val' value
258
		 * will effectively short-circuit the value retrieval.
259
		 *
260
		 * @since 2.0.0
261
		 */
262
		$data = apply_filters( "cmb2_override_{$a['field_id']}_meta_value", $data, $this->object_id, $a, $this );
263
264
		// If no override, get value normally
265
		if ( 'cmb2_field_no_override_val' === $data ) {
266
			$data = 'options-page' === $a['type']
267
				? cmb2_options( $a['id'] )->get( $a['field_id'] )
268
				: get_metadata( $a['type'], $a['id'], $a['field_id'], ( $a['single'] || $a['repeat'] ) );
269
		}
270
271
		if ( $this->group ) {
272
273
			$data = is_array( $data ) && isset( $data[ $this->group->index ][ $this->args( '_id' ) ] )
274
				? $data[ $this->group->index ][ $this->args( '_id' ) ]
275
				: false;
276
		}
277
278
		return $data;
279
	}
280
281
	/**
282
	 * Updates metadata/option data
283
	 * @since  1.0.1
284
	 * @param  mixed $new_value Value to update data with
285
	 * @param  bool  $single    Whether data is an array (add_metadata)
286
	 */
287
	public function update_data( $new_value, $single = true ) {
288
		$a = $this->data_args( array( 'single' => $single ) );
289
290
		$a['value'] = $a['repeat'] ? array_values( $new_value ) : $new_value;
291
292
		/**
293
		 * Filter whether to override saving of meta value.
294
		 * Returning a non-null value will effectively short-circuit the function.
295
		 *
296
		 * @since 2.0.0
297
		 *
298
		 * @param null|bool $check  Whether to allow updating metadata for the given type.
299
		 *
300
		 * @param array $args {
301
		 *     Array of data about current field including:
302
		 *
303
		 *     @type string $value    The value to set
304
		 *     @type string $type     The current object type
305
		 *     @type int    $id       The current object ID
306
		 *     @type string $field_id The ID of the field being updated
307
		 *     @type bool   $repeat   Whether current field is repeatable
308
		 *     @type bool   $single   Whether current field is a single database row
309
		 * }
310
		 *
311
		 * @param array $field_args All field arguments
312
		 *
313
		 * @param CMB2_Field object $field This field object
314
		 */
315
		$override = apply_filters( 'cmb2_override_meta_save', null, $a, $this->args(), $this );
316
317
		/**
318
		 * Filter and parameters are documented for 'cmb2_override_meta_save' filter (above).
319
		 *
320
		 * The dynamic portion of the hook, $a['field_id'], refers to the current
321
		 * field id paramater. Returning a non-null value
322
		 * will effectively short-circuit the function.
323
		 *
324
		 * @since 2.0.0
325
		 */
326
		$override = apply_filters( "cmb2_override_{$a['field_id']}_meta_save", $override, $a, $this->args(), $this );
327
328
		// If override, return that
329
		if ( null !== $override ) {
330
			return $override;
331
		}
332
333
		// Options page handling (or temp data store)
334
		if ( 'options-page' === $a['type'] || empty( $a['id'] ) ) {
335
			return cmb2_options( $a['id'] )->update( $a['field_id'], $a['value'], false, $a['single'] );
336
		}
337
338
		// Add metadata if not single
339
		if ( ! $a['single'] ) {
340
			return add_metadata( $a['type'], $a['id'], $a['field_id'], $a['value'], false );
341
		}
342
343
		// Delete meta if we have an empty array
344
		if ( is_array( $a['value'] ) && empty( $a['value'] ) ) {
345
			return delete_metadata( $a['type'], $a['id'], $a['field_id'], $this->value );
346
		}
347
348
		// Update metadata
349
		return update_metadata( $a['type'], $a['id'], $a['field_id'], $a['value'] );
350 46
	}
351 46
352 46
	/**
353 46
	 * Removes/updates metadata/option data
354 46
	 * @since  1.0.1
355 46
	 * @param  string $old Old value
356 46
	 */
357 46
	public function remove_data( $old = '' ) {
358 46
		$a = $this->data_args( array( 'old' => $old ) );
359
360
		/**
361
		 * Filter whether to override removing of meta value.
362
		 * Returning a non-null value will effectively short-circuit the function.
363
		 *
364
		 * @since 2.0.0
365
		 *
366
		 * @param null|bool $delete Whether to allow metadata deletion of the given type.
367
		 * @param array $args       Array of data about current field including:
368
		 *                              'type'     : Current object type
369
		 *                              'id'       : Current object ID
370
		 *                              'field_id' : Current Field ID
371
		 *                              'repeat'   : Whether current field is repeatable
372
		 *                              'single'   : Whether to save as a
373
		 *                              					single meta value
374
		 * @param array $field_args All field arguments
375
		 * @param CMB2_Field object $field This field object
376
		 */
377
		$override = apply_filters( 'cmb2_override_meta_remove', null, $a, $this->args(), $this );
378
379
		/**
380
		 * Filter whether to override removing of meta value.
381
		 *
382
		 * The dynamic portion of the hook, $a['field_id'], refers to the current
383
		 * field id paramater. Returning a non-null value
384
		 * will effectively short-circuit the function.
385
		 *
386
		 * @since 2.0.0
387
		 *
388
		 * @param null|bool $delete Whether to allow metadata deletion of the given type.
389
		 * @param array $args       Array of data about current field including:
390
		 *                              'type'     : Current object type
391
		 *                              'id'       : Current object ID
392
		 *                              'field_id' : Current Field ID
393
		 *                              'repeat'   : Whether current field is repeatable
394
		 *                              'single'   : Whether to save as a
395
		 *                              					single meta value
396
		 * @param array $field_args All field arguments
397
		 * @param CMB2_Field object $field This field object
398
		 */
399
		$override = apply_filters( "cmb2_override_{$a['field_id']}_meta_remove", $override, $a, $this->args(), $this );
400
401
		// If no override, remove as usual
402
		if ( null !== $override ) {
403
			return $override;
404
		}
405
		// Option page handling
406
		elseif ( 'options-page' === $a['type'] || empty( $a['id'] ) ) {
407
			return cmb2_options( $a['id'] )->remove( $a['field_id'] );
408
		}
409
410
		// Remove metadata
411
		return delete_metadata( $a['type'], $a['id'], $a['field_id'], $old );
412
	}
413
414
	/**
415
	 * Data variables for get/set data methods
416
	 * @since  1.1.0
417
	 * @param  array $args Override arguments
418
	 * @return array       Updated arguments
419
	 */
420
	public function data_args( $args = array() ) {
421
		$args = wp_parse_args( $args, array(
422
			'type'     => $this->object_type,
423
			'id'       => $this->object_id,
424
			'field_id' => $this->id( true ),
425
			'repeat'   => $this->args( 'repeatable' ),
426
			'single'   => ! $this->args( 'multiple' ),
427
		) );
428
		return $args;
429 39
	}
430 39
431 39
	/**
432 38
	 * Checks if field has a registered sanitization callback
433
	 * @since  1.0.1
434
	 * @param  mixed $meta_value Meta value
435
	 * @return mixed             Possibly sanitized meta value
436 7
	 */
437
	public function sanitization_cb( $meta_value ) {
438
439 7
		if ( $this->args( 'repeatable' ) && is_array( $meta_value ) ) {
440 4
			// Remove empties
441
			$meta_value = array_filter( $meta_value );
442
		}
443 3
444 2
		// Check if the field has a registered validation callback
445
		$cb = $this->maybe_callback( 'sanitization_cb' );
446 3
		if ( false === $cb ) {
447
			// If requesting NO validation, return meta value
448
			return $meta_value;
449
		} elseif ( $cb ) {
450
			// Ok, callback is good, let's run it.
451
			return call_user_func( $cb, $meta_value, $this->args(), $this );
452
		}
453 37
454
		$sanitizer = new CMB2_Sanitize( $this, $meta_value );
455 37
456 37
		/**
457 37
		 * Filter the value before it is saved.
458 37
		 *
459 37
		 * The dynamic portion of the hook name, $this->type(), refers to the field type.
460
		 *
461
		 * Passing a non-null value to the filter will short-circuit saving
462
		 * the field value, saving the passed value instead.
463
		 *
464
		 * @param bool|mixed $override_value Sanitization/Validation override value to return.
465
		 *                                   Default false to skip it.
466
		 * @param mixed      $value      The value to be saved to this field.
467
		 * @param int        $object_id  The ID of the object where the value will be saved
468 1
		 * @param array      $field_args The current field's arguments
469
		 * @param object     $sanitizer  This `CMB2_Sanitize` object
470 1
		 */
471 1
		$override_value = apply_filters( "cmb2_sanitize_{$this->type()}", null, $sanitizer->value, $this->object_id, $this->args(), $sanitizer );
472 1
473 1
		if ( null !== $override_value ) {
474 1
			return $override_value;
475
		}
476 1
477 1
		// Sanitization via 'CMB2_Sanitize'
478 1
		return $sanitizer->{$this->type()}();
479 1
	}
480 1
481 1
	/**
482 1
	 * Process $_POST data to save this field's value
483
	 * @since  2.0.3
484
	 * @param  array $data_to_save $_POST data to check
485
	 * @return array|int|bool                Result of save, false on failure
486
	 */
487
	public function save_field_from_data( array $data_to_save ) {
488
		$this->data_to_save = $data_to_save;
489
490
		$meta_value = isset( $this->data_to_save[ $this->id( true ) ] )
491
			? $this->data_to_save[ $this->id( true ) ]
492 37
			: null;
493
494 37
		return $this->save_field( $meta_value );
495 16
	}
496
497
	/**
498 37
	 * Sanitize/store a value to this field
499
	 * @since  2.0.0
500
	 * @param  array $meta_value Desired value to sanitize/store
501 37
	 * @return array|int|bool              Result of save. false on failure
502
	 */
503
	public function save_field( $meta_value ) {
504
505
		$updated   = false;
506
		$action    = '';
507 37
		$new_value = $this->sanitization_cb( $meta_value );
508 37
509
		if ( ! $this->args( 'save_field' ) ) {
510
511
			// Nothing to see here.
512 37
			$action = 'disabled';
513
514 4
		} elseif ( $this->args( 'multiple' ) && ! $this->args( 'repeatable' ) && ! $this->group ) {
515
516
			$this->remove_data();
517
			$count = 0;
518 33
519 33
			if ( ! empty( $new_value ) ) {
520
				foreach ( $new_value as $add_new ) {
521 33
					if ( $this->update_data( $add_new, false ) ) {
522
						$count++;
523
					}
524
				}
525
			}
526 33
527
			$updated = $count ? $count : false;
528
			$action  = 'repeatable';
529 33
530 33
		} elseif ( ! CMB2_Utils::isempty( $new_value ) && $new_value !== $this->get_data() ) {
531
			$updated = $this->update_data( $new_value );
532
			$action  = 'updated';
533
		} elseif ( CMB2_Utils::isempty( $new_value ) ) {
534
			$updated = $this->remove_data();
535
			$action  = 'removed';
536
		}
537
538 1
		if ( $updated ) {
539 1
			$this->value = $this->get_data();
540
			$this->escaped_value = null;
541
		}
542
543
		$field_id = $this->id( true );
544
545
		/**
546
		 * Hooks after save field action.
547 1
		 *
548
		 * @since 2.2.0
549
		 *
550 1
		 * @param string            $field_id the current field id paramater.
551
		 * @param bool              $updated  Whether the metadata update action occurred.
552
		 * @param string            $action   Action performed. Could be "repeatable", "updated", or "removed".
553
		 * @param CMB2_Field object $field    This field object
554 1
		 */
555
		do_action( 'cmb2_save_field', $field_id, $updated, $action, $this );
556
557
		/**
558 1
		 * Hooks after save field action.
559
		 *
560
		 * The dynamic portion of the hook, $field_id, refers to the
561
		 * current field id paramater.
562
		 *
563
		 * @since 2.2.0
564
		 *
565
		 * @param bool              $updated Whether the metadata update action occurred.
566
		 * @param string            $action  Action performed. Could be "repeatable", "updated", or "removed".
567
		 * @param CMB2_Field object $field   This field object
568 5
		 */
569 5
		do_action( "cmb2_save_field_{$field_id}", $updated, $action, $this );
570
571
		return $updated;
572
	}
573
574
	/**
575
	 * Determine if current type is exempt from escaping
576
	 * @since  1.1.0
577
	 * @return bool  True if exempt
578 5
	 */
579 5
	public function escaping_exception() {
580 5
		// These types cannot be escaped
581
		return in_array( $this->type(), array(
582 5
			'file_list',
583
			'multicheck',
584
			'text_datetime_timestamp_timezone',
585
		) );
586 5
	}
587 5
588 5
	/**
589
	 * Determine if current type cannot be repeatable
590
	 * @since  1.1.0
591
	 * @param  string $type Field type to check
592
	 * @return bool         True if type cannot be repeatable
593
	 */
594
	public function repeatable_exception( $type ) {
595 5
		// These types cannot be repeatable.
596
		$internal_fields = array(
597
			// Use file_list instead
598 5
			'file'                => 1,
599
			'radio'               => 1,
600
			'title'               => 1,
601
			// @todo Ajax load wp_editor: http://wordpress.stackexchange.com/questions/51776/how-to-load-wp-editor-through-ajax-jquery
602
			'wysiwyg'             => 1,
603 5
			'checkbox'            => 1,
604
			'radio_inline'        => 1,
605
			'taxonomy_radio'      => 1,
606
			'taxonomy_select'     => 1,
607 5
			'taxonomy_multicheck' => 1,
608
		);
609 5
610
		/**
611 5
		 * Filter field types that are non-repeatable.
612
		 *
613
		 * Note that this does *not* allow overriding the default non-repeatable types.
614
		 *
615
		 * @since 2.1.1
616
		 *
617
		 * @param array $fields Array of fields designated as non-repeatable. Note that the field names are *keys*,
618
		 *                      and not values. The value can be anything, because it is meaningless. Example:
619
		 *                      array( 'my_custom_field' => 1 )
620 5
		 */
621 5
		$all_fields = array_merge( apply_filters( 'cmb2_non_repeatable_fields', array() ), $internal_fields );
622 5
		return isset( $all_fields[ $type ] );
623
	}
624 5
625
	/**
626
	 * Escape the value before output. Defaults to 'esc_attr()'
627 5
	 * @since  1.0.1
628
	 * @param  callable $func       Escaping function (if not esc_attr())
629 5
	 * @param  mixed    $meta_value Meta value
630 5
	 * @return mixed                Final value
631
	 */
632 5
	public function escaped_value( $func = 'esc_attr', $meta_value = '' ) {
633
634 5
		if ( null !== $this->escaped_value ) {
635
			return $this->escaped_value;
636 5
		}
637 5
638
		$meta_value = $meta_value ? $meta_value : $this->value();
639
640
		// Check if the field has a registered escaping callback
641
		if ( $cb = $this->maybe_callback( 'escape_cb' ) ) {
642
			// Ok, callback is good, let's run it.
643
			return call_user_func( $cb, $meta_value, $this->args(), $this );
644
		}
645 5
646 5
		// Or custom escaping filter can be used
647 5
		$esc = apply_filters( "cmb2_types_esc_{$this->type()}", null, $meta_value, $this->args(), $this );
648 5
		if ( null !== $esc ) {
649 5
			return $esc;
650
		}
651 5
652
		if ( false === $cb || $this->escaping_exception() ) {
653 5
			// If requesting NO escaping, return meta value
654 5
			return $this->val_or_default( $meta_value );
655 5
		}
656
657 5
		// escaping function passed in?
658 3
		$func       = $func ? $func : 'esc_attr';
659 3
		$meta_value = $this->val_or_default( $meta_value );
660
661 5
		if ( is_array( $meta_value ) ) {
662
			foreach ( $meta_value as $key => $value ) {
663
				$meta_value[ $key ] = call_user_func( $func, $value );
664
			}
665
		} else {
666
			$meta_value = call_user_func( $func, $meta_value );
667
		}
668
669
		$this->escaped_value = $meta_value;
670
		return $this->escaped_value;
671 38
	}
672 38
673
	/**
674 2
	 * Return non-empty value or field default if value IS empty
675 2
	 * @since  2.0.0
676
	 * @param  mixed $meta_value Field value
677
	 * @return mixed             Field value, or default value
678
	 */
679 38
	public function val_or_default( $meta_value ) {
680 38
		return ! CMB2_Utils::isempty( $meta_value ) ? $meta_value : $this->get_default();
681
	}
682
683
	/**
684
	 * Offset a time value based on timezone
685
	 * @since  1.0.0
686
	 * @return string Offset time string
687
	 */
688
	public function field_timezone_offset() {
689
		return CMB2_Utils::timezone_offset( $this->field_timezone() );
690
	}
691
692
	/**
693
	 * Return timezone string
694
	 * @since  1.0.0
695
	 * @return string Timezone string
696
	 */
697
	public function field_timezone() {
698
		$value = '';
699 14
700 14
		// Is timezone arg set?
701 5
		if ( $this->args( 'timezone' ) ) {
702 4
			$value = $this->args( 'timezone' );
703
		}
704
		// Is there another meta key with a timezone stored as its value we should use?
705 1
		else if ( $this->args( 'timezone_meta_key' ) ) {
706
			$value = $this->get_data( $this->args( 'timezone_meta_key' ) );
707
		}
708 14
709
		return $value;
710 14
	}
711 1
712
	/**
713 1
	 * Format the timestamp field value based on the field date/time format arg
714 1
	 * @since  2.0.0
715 1
	 * @param  int    $meta_value Timestamp
716 1
	 * @param  string $format     Either date_format or time_format
717
	 * @return string             Formatted date
718 14
	 */
719 4
	public function format_timestamp( $meta_value, $format = 'date_format' ) {
720
		return date( stripslashes( $this->args( $format ) ), $meta_value );
721
	}
722 11
723
	/**
724
	 * Return a formatted timestamp for a field
725
	 * @since  2.0.0
726
	 * @param  string $format     Either date_format or time_format
727
	 * @param  string $meta_value Optional meta value to check
728
	 * @return string             Formatted date
729
	 */
730 46
	public function get_timestamp_format( $format = 'date_format', $meta_value = 0 ) {
731
		$meta_value = $meta_value ? $meta_value : $this->escaped_value();
732
		$meta_value = CMB2_Utils::make_valid_time_stamp( $meta_value );
733 46
734 46
		if ( empty( $meta_value ) ) {
735 46
			return '';
736 46
		}
737 46
738 46
		return is_array( $meta_value )
739 46
			? array_map( array( $this, 'format_timestamp' ), $meta_value, $format )
740 46
			: $this->format_timestamp( $meta_value, $format );
741 46
	}
742 46
743 46
	/**
744 46
	 * Get timestamp from text date
745 46
	 * @since  2.2.0
746 46
	 * @param  string $value Date value
747 46
	 * @return mixed         Unix timestamp representing the date.
748 46
	 */
749 46
	public function get_timestamp_from_value( $value ) {
750 46
		return CMB2_Utils::get_timestamp_from_value( $value, $this->args( 'date_format' ) );
751 46
	}
752 46
753 46
	/**
754 46
	 * Get field render callback and Render the field row
755
	 * @since 1.0.0
756
	 */
757
	public function render_field() {
758 46
		$this->render_context = 'edit';
759
760 46
		$this->peform_param_callback( 'render_row_cb' );
761 46
762
		// For chaining
763
		return $this;
764 46
	}
765
766
	/**
767
	 * Default field render callback
768
	 * @since 2.1.1
769 46
	 */
770
	public function render_field_callback() {
771
772 46
		// If field is requesting to not be shown on the front-end
773
		if ( ! is_admin() && ! $this->args( 'on_front' ) ) {
774 46
			return;
775 46
		}
776
777 46
		// If field is requesting to be conditionally shown
778
		if ( ! $this->should_show() ) {
779
			return;
780
		}
781
782
		$this->peform_param_callback( 'before_row' );
783 46
784 1
		printf( "<div class=\"cmb-row %s\" data-fieldtype=\"%s\">\n", $this->row_classes(), $this->type() );
785 1
786 1
		if ( ! $this->args( 'show_names' ) ) {
787
			echo "\n\t<div class=\"cmb-td\">\n";
788 46
789
			$this->peform_param_callback( 'label_cb' );
790 46
791
		} else {
792 2
793 2
			if ( $this->get_param_callback_result( 'label_cb' ) ) {
794
				echo '<div class="cmb-th">', $this->peform_param_callback( 'label_cb' ), '</div>';
795 2
			}
796
797 46
			echo "\n\t<div class=\"cmb-td\">\n";
798
		}
799
800
		$this->peform_param_callback( 'before' );
801
802
		$field_type = new CMB2_Types( $this );
803
		$field_type->render();
804
805 36
		$this->peform_param_callback( 'after' );
806 36
807
		echo "\n\t</div>\n</div>";
808
809
		$this->peform_param_callback( 'after_row' );
810 1
811
		// For chaining
812
		return $this;
813
	}
814
815
	/**
816
	 * The default label_cb callback (if not a title field)
817
	 *
818
	 * @since  2.1.1
819
	 * @return string Label html markup
820
	 */
821
	public function label() {
822
		if ( ! $this->args( 'name' ) ) {
823
			return '';
824
		}
825
826
		$style = ! $this->args( 'show_names' ) ? ' style="display:none;"' : '';
827
828
		return sprintf( "\n" . '<label%1$s for="%2$s">%3$s</label>' . "\n", $style, $this->id(), $this->args( 'name' ) );
829
	}
830
831
	/**
832
	 * Defines the classes for the current CMB2 field row
833
	 *
834
	 * @since  2.0.0
835
	 * @return string Space concatenated list of classes
836
	 */
837
	public function row_classes() {
838
839
		$classes = array();
840
841
		/**
842
		 * By default, 'text_url' and 'text' fields get table-like styling
843
		 *
844
		 * @since 2.0.0
845
		 *
846
		 * @param array $field_types The types of fields which should get the 'table-layout' class
847
		 */
848
		$repeat_table_rows_types = apply_filters( 'cmb2_repeat_table_row_types', array(
849
			'text_url', 'text',
850
		) );
851
852
		$conditional_classes = array(
853
			'cmb-type-' . str_replace( '_', '-', sanitize_html_class( $this->type() ) ) => true,
854
			'cmb2-id-' . str_replace( '_', '-', sanitize_html_class( $this->id() ) )    => true,
855
			'cmb-repeat'             => $this->args( 'repeatable' ),
856
			'cmb-repeat-group-field' => $this->group,
857
			'cmb-inline'             => $this->args( 'inline' ),
858
			'table-layout'           => 'edit' === $this->render_context && in_array( $this->type(), $repeat_table_rows_types ),
859
		);
860
861
		foreach ( $conditional_classes as $class => $condition ) {
862
			if ( $condition ) {
863
				$classes[] = $class;
864
			}
865
		}
866
867
		if ( $added_classes = $this->args( 'classes' ) ) {
868
			$added_classes = is_array( $added_classes ) ? implode( ' ', $added_classes ) : (string) $added_classes;
869
		} elseif ( $added_classes = $this->get_param_callback_result( 'classes_cb' ) ) {
870
			$added_classes = is_array( $added_classes ) ? implode( ' ', $added_classes ) : (string) $added_classes;
871
		}
872
873
		if ( $added_classes ) {
874
			$classes[] = esc_attr( $added_classes );
875
		}
876
877
		/**
878
		 * Globally filter row classes
879
		 *
880
		 * @since 2.0.0
881
		 *
882
		 * @param string            $classes Space-separated list of row classes
883
		 * @param CMB2_Field object $field   This field object
884
		 */
885
		return apply_filters( 'cmb2_row_classes', implode( ' ', $classes ), $this );
886
	}
887
888
889
890
	/**
891
	 * Get field display callback and render the display value in the column.
892
	 * @since 2.2.2
893
	 */
894
	public function render_column() {
895
		$this->render_context = 'display';
896
897
		$this->peform_param_callback( 'display_cb' );
898
899
		// For chaining
900
		return $this;
901
	}
902
903
	/**
904
	 * Default callback to outputs field value in a display format.
905
	 * @since 2.2.2
906
	 */
907
	public function display_value_callback() {
908
		// If field is requesting to be conditionally shown
909
		if ( ! $this->should_show() ) {
910
			return;
911
		}
912
913
		$display = new CMB2_Field_Display( $this );
914
915
		/**
916
		 * A filter to bypass the default display.
917
		 *
918
		 * The dynamic portion of the hook name, $this->type(), refers to the field type.
919
		 *
920
		 * Passing a non-null value to the filter will short-circuit the default display.
921
		 *
922
		 * @param bool|mixed         $pre_output Default null value.
923
		 * @param CMB2_Field         $field      This field object.
924
		 * @param CMB2_Field_Display $display    The `CMB2_Field_Display` object.
925
		 */
926
		$pre_output = apply_filters( "cmb2_pre_field_display_{$this->type()}", null, $this, $display );
927
928
		if ( null !== $pre_output ) {
929
			echo $pre_output;
930
			return;
931
		}
932
933
		$this->peform_param_callback( 'before_display_wrap' );
934
935
		printf( "<div class=\"cmb-column %s\" data-fieldtype=\"%s\">\n", $this->row_classes( 'display' ), $this->type() );
0 ignored issues
show
Unused Code introduced by
The call to CMB2_Field::row_classes() has too many arguments starting with 'display'.

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

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

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

Loading history...
936
937
		$this->peform_param_callback( 'before_display' );
938
939
		CMB2_Field_Display::get( $this )->display();
940
941
		$this->peform_param_callback( 'after_display' );
942
943
		echo "\n</div>";
944
945
		$this->peform_param_callback( 'after_display_wrap' );
946
947
		// For chaining
948
		return $this;
949
	}
950
951
	/**
952
	 * Replaces a hash key - {#} - with the repeatable index
953
	 * @since  1.2.0
954
	 * @param  string $value Value to update
955
	 * @return string        Updated value
956
	 */
957
	public function replace_hash( $value ) {
958
		// Replace hash with 1 based count
959
		return str_replace( '{#}', ( $this->index + 1 ), $value );
960
	}
961
962
	/**
963
	 * Retrieve text parameter from field's text array (if it has one), or use fallback text
964
	 * For back-compatibility, falls back to checking the options array.
965
	 *
966
	 * @since  2.2.2
967
	 * @param  string  $text_key Key in field's text array
968
	 * @param  string  $fallback Fallback text
969
	 * @return string            Text
970
	 */
971
	public function get_string( $text_key, $fallback ) {
972
		// If null, populate with our field strings values.
973
		if ( null === $this->strings ) {
974
			$this->strings = (array) $this->args['text'];
975
976 View Code Duplication
			if ( is_callable( $this->args['text_cb'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
977
				$strings = call_user_func( $this->args['text_cb'], $this );
978
979
				if ( $strings && is_array( $strings ) ) {
980
					$this->strings += $strings;
981
				}
982
			}
983
		}
984
985
		// If we have that string value, send it back.
986
		if ( isset( $this->strings[ $text_key ] ) ) {
987
			return $this->strings[ $text_key ];
988
		}
989
990
		// Check options for back-compat.
991
		$string = $this->options( $text_key );
992
993
		return $string ? $string : $fallback;
0 ignored issues
show
Bug Compatibility introduced by
The expression $string ? $string : $fallback; of type array|string adds the type array to the return on line 993 which is incompatible with the return type documented by CMB2_Field::get_string of type string.
Loading history...
994
	}
995
996
	/**
997
	 * Retrieve options args. Calls options_cb if it exists.
998
	 * @since  2.0.0
999
	 * @param  string  $key Specific option to retrieve
1000
	 * @return array        Array of options
1001
	 */
1002
	public function options( $key = '' ) {
1003
		if ( ! empty( $this->field_options ) ) {
1004
			if ( $key ) {
1005
				return array_key_exists( $key, $this->field_options ) ? $this->field_options[ $key ] : false;
1006
			}
1007
1008
			return $this->field_options;
1009
		}
1010
1011
		$this->field_options = (array) $this->args['options'];
1012
1013 View Code Duplication
		if ( is_callable( $this->args['options_cb'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1014
			$options = call_user_func( $this->args['options_cb'], $this );
1015
1016
			if ( $options && is_array( $options ) ) {
1017
				$this->field_options = $options + $this->field_options;
1018
			}
1019
		}
1020
1021
		if ( $key ) {
1022
			return array_key_exists( $key, $this->field_options ) ? $this->field_options[ $key ] : false;
1023
		}
1024
1025
		return $this->field_options;
1026
	}
1027
1028
	/**
1029
	 * Store JS dependencies as part of the field args.
1030
	 * @since 2.2.0
1031
	 * @param array $dependencies Dependies to register for this field.
1032
	 */
1033
	public function add_js_dependencies( $dependencies = array() ) {
1034
		foreach ( (array) $dependencies as $dependency ) {
1035
			$this->args['js_dependencies'][ $dependency ] = $dependency;
1036
		}
1037
1038
		CMB2_JS::add_dependencies( $dependencies );
1039
	}
1040
1041
	/**
1042
	 * Get CMB2_Field default value, either from default param or default_cb param.
1043
	 *
1044
	 * @since  0.2.2
1045
	 *
1046
	 * @return mixed  Default field value
1047
	 */
1048
	public function get_default() {
1049
		if ( null !== $this->args['default'] ) {
1050
			return $this->args['default'];
1051
		}
1052
1053
		$param = is_callable( $this->args['default_cb'] ) ? 'default_cb' : 'default';
1054
		$default = $this->get_param_callback_result( $param );
1055
1056
		// Allow a filter override of the default value
1057
		$this->args['default'] = apply_filters( 'cmb2_default_filter', $default, $this );
1058
1059
		return $this->args['default'];
1060
	}
1061
1062
	/**
1063
	 * Fills in empty field parameters with defaults
1064
	 * @since 1.1.0
1065
	 * @param array $args Metabox field config array
1066
	 * @param array       Modified field config array.
1067
	 */
1068
	public function _set_field_defaults( $args ) {
1069
1070
		// Set up blank or default values for empty ones
1071
		$args = wp_parse_args( $args, array(
1072
			'type'              => '',
1073
			'name'              => '',
1074
			'desc'              => '',
1075
			'before'            => '',
1076
			'after'             => '',
1077
			'options'           => array(),
1078
			'options_cb'        => '',
1079
			'text'              => array(),
1080
			'text_cb'           => '',
1081
			'attributes'        => array(),
1082
			'protocols'         => null,
1083
			'default'           => null,
1084
			'default_cb'        => '',
1085
			'classes'           => null,
1086
			'classes_cb'        => '',
1087
			'select_all_button' => true,
1088
			'multiple'          => false,
1089
			'repeatable'        => isset( $args['type'] ) && 'group' == $args['type'],
1090
			'inline'            => false,
1091
			'on_front'          => true,
1092
			'show_names'        => true,
1093
			'save_field'        => true, // Will not save if false
1094
			'date_format'       => 'm\/d\/Y',
1095
			'time_format'       => 'h:i A',
1096
			'description'       => isset( $args['desc'] ) ? $args['desc'] : '',
1097
			'preview_size'      => 'file' == $args['type'] ? array( 350, 350 ) : array( 50, 50 ),
1098
			'render_row_cb'     => array( $this, 'render_field_callback' ),
1099
			'display_cb'        => array( $this, 'display_value_callback' ),
1100
			'label_cb'          => 'title' != $args['type'] ? array( $this, 'label' ) : '',
1101
			'column'            => false,
1102
			'js_dependencies'   => array(),
1103
			'show_in_rest'      => null,
1104
		) );
1105
1106
		/*
1107
		 * Deprecated usage:
1108
		 *
1109
		 * 'std' -- use 'default' (no longer works)
1110
		 * 'row_classes' -- use 'class', or 'class_cb'
1111
		 * 'default' -- as callback (use default_cb)
1112
		 */
1113
		$args = $this->convert_deprecated_params( $args );
1114
1115
		$args['repeatable'] = $args['repeatable'] && ! $this->repeatable_exception( $args['type'] );
1116
		$args['inline']     = $args['inline'] || false !== stripos( $args['type'], '_inline' );
1117
1118
		$args['options']    = 'group' == $args['type'] ? wp_parse_args( $args['options'], array(
1119
			'add_button'    => esc_html__( 'Add Group', 'cmb2' ),
1120
			'remove_button' => esc_html__( 'Remove Group', 'cmb2' ),
1121
		) ) : $args['options'];
1122
1123
		$args['_id']        = $args['id'];
1124
		$args['_name']      = $args['id'];
1125
1126
		if ( $this->group ) {
1127
1128
			$args['id']    = $this->group->args( 'id' ) . '_' . $this->group->index . '_' . $args['id'];
1129
			$args['_name'] = $this->group->args( 'id' ) . '[' . $this->group->index . '][' . $args['_name'] . ']';
1130
		}
1131
1132
		if ( 'wysiwyg' == $args['type'] ) {
1133
			$args['id'] = strtolower( str_ireplace( '-', '_', $args['id'] ) );
1134
			$args['options']['textarea_name'] = $args['_name'];
1135
		}
1136
1137
		$option_types = apply_filters( 'cmb2_all_or_nothing_types', array( 'select', 'radio', 'radio_inline', 'taxonomy_select', 'taxonomy_radio', 'taxonomy_radio_inline' ), $this );
1138
1139
		if ( in_array( $args['type'], $option_types, true ) ) {
1140
1141
			$args['show_option_none'] = isset( $args['show_option_none'] ) ? $args['show_option_none'] : null;
1142
			$args['show_option_none'] = true === $args['show_option_none'] ? esc_html__( 'None', 'cmb2' ) : $args['show_option_none'];
1143
1144
			if ( null === $args['show_option_none'] ) {
1145
				$off_by_default = in_array( $args['type'], array( 'select', 'radio', 'radio_inline' ), true );
1146
				$args['show_option_none'] = $off_by_default ? false : esc_html__( 'None', 'cmb2' );
1147
			}
1148
1149
		}
1150
1151
		$args['has_supporting_data'] = in_array(
1152
			$args['type'],
1153
			array(
1154
				// CMB2_Sanitize::_save_file_id_value()/CMB2_Sanitize::_get_group_file_value_array()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1155
				'file',
1156
				// See CMB2_Sanitize::_save_utc_value()
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1157
				'text_datetime_timestamp_timezone',
1158
			),
1159
			true
1160
		);
1161
1162
		return $args;
1163
	}
1164
1165
	/**
1166
	 * Get default field arguments specific to this CMB2 object.
1167
	 * @since  2.2.0
1168
	 * @param  array      $field_args  Metabox field config array.
1169
	 * @param  CMB2_Field $field_group (optional) CMB2_Field object (group parent)
1170
	 * @return array                   Array of field arguments.
1171
	 */
1172
	protected function get_default_args( $field_args, $field_group = null ) {
1173
		$args = parent::get_default_args( array(), $this->group );
1174
1175
		if ( isset( $field_args['field_args'] ) ) {
1176
			$args = wp_parse_args( $field_args, $args );
1177
		} else {
1178
			$args['field_args'] = wp_parse_args( $field_args, $this->args );
1179
		}
1180
1181
		return $args;
1182
	}
1183
1184
	/**
1185
	 * Returns a cloned version of this field object with, but with
1186
	 * modified/overridden field arguments.
1187
	 *
1188
	 * @since  2.2.2
1189
	 * @param  array  $field_args Array of field arguments, or entire array of
1190
	 *                            arguments for CMB2_Field
1191
	 *
1192
	 * @return CMB2_Field         The new CMB2_Field instance.
1193
	 */
1194
	public function get_field_clone( $field_args ) {
1195
		return $this->get_new_field( $field_args );
1196
	}
1197
1198
	/**
1199
	 * Returns the CMB2 instance this field is registered to.
1200
	 *
1201
	 * @since  2.2.2
1202
	 *
1203
	 * @return CMB2|WP_Error If new CMB2_Field is called without cmb_id arg, returns error.
1204
	 */
1205
	public function get_cmb() {
1206
		if ( ! $this->cmb_id ) {
1207
			return new WP_Error( 'no_cmb_id', esc_html__( 'Sorry, this field does not have a cmb_id specified.', 'cmb2' ) );
1208
		}
1209
1210
		return cmb2_get_metabox( $this->cmb_id, $this->object_id, $this->object_type );
1211
	}
1212
1213
	/**
1214
	 * Converts deprecated field parameters to the current/proper parameter, and throws a deprecation notice.
1215
	 * @since 2.2.3
1216
	 * @param array $args Metabox field config array.
1217
	 * @param array       Modified field config array.
1218
	 */
1219
	protected function convert_deprecated_params( $args ) {
1220
1221
		if ( isset( $args['row_classes'] ) ) {
1222
1223
			$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_PARAM, 'row_classes', 'classes' );
1224
1225
			// row_classes param could be a callback
1226
			if ( is_callable( $args['row_classes'] ) ) {
1227
1228
				$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'row_classes', 'classes_cb' );
1229
1230
				$args['classes_cb'] = $args['row_classes'];
1231
				$args['classes'] = null;
1232
			} else {
1233
1234
1235
				$args['classes'] = $args['row_classes'];
1236
			}
1237
1238
			unset( $args['row_classes'] );
1239
		}
1240
1241
1242
		// default param can be passed a callback as well
1243 View Code Duplication
		if ( is_callable( $args['default'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1244
1245
			$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'default', 'default_cb' );
1246
1247
			$args['default_cb'] = $args['default'];
1248
			$args['default'] = null;
1249
		}
1250
1251
		// options param can be passed a callback as well
1252 View Code Duplication
		if ( is_callable( $args['options'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1253
1254
			$this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'options', 'options_cb' );
1255
1256
			$args['options_cb'] = $args['options'];
1257
			$args['options'] = array();
1258
		}
1259
1260
		return $args;
1261
	}
1262
1263
}
1264