PluginProbe
Virtue/Ascend/Pinnacle Toolkit / 4.9.12.2
Virtue/Ascend/Pinnacle Toolkit v4.9.12.2
4.9.12.2 trunk 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.7 All 48 releases
virtue-toolkit / cmb / includes / CMB2_Field.php

CMB2_Field.php in Virtue/Ascend/Pinnacle Toolkit 4.9.12.2, at cmb/includes/CMB2_Field.php

1,645 lines 45.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 public function __construct( $args ) {
133
134 if ( ! empty( $args['group_field'] ) ) {
135 $this->group = $args['group_field'];
136 $this->object_id = $this->group->object_id;
137 $this->object_type = $this->group->object_type;
138 $this->cmb_id = $this->group->cmb_id;
139 } else {
140 $this->object_id = isset( $args['object_id'] ) && '_' !== $args['object_id'] ? $args['object_id'] : 0;
141 $this->object_type = isset( $args['object_type'] ) ? $args['object_type'] : 'post';
142
143 if ( isset( $args['cmb_id'] ) ) {
144 $this->cmb_id = $args['cmb_id'];
145 }
146 }
147
148 $this->args = $this->_set_field_defaults( $args['field_args'] );
149
150 if ( $this->object_id ) {
151 $this->value = $this->get_data();
152 }
153 }
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 public function __call( $name, $arguments ) {
164 if ( 'string' === $name ) {
165 return call_user_func_array( array( $this, 'get_string' ), $arguments );
166 }
167
168 $key = isset( $arguments[0] ) ? $arguments[0] : '';
169 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 public function id( $raw = false ) {
180 $id = $raw ? '_id' : 'id';
181 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 public function args( $key = '', $_key = '' ) {
193 $arg = $this->_data( 'args', $key );
194
195 if ( in_array( $key, array( 'default', 'default_cb' ), true ) ) {
196
197 $arg = $this->get_default();
198
199 } elseif ( $_key ) {
200
201 $arg = isset( $arg[ $_key ] ) ? $arg[ $_key ] : false;
202 }
203
204 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 public function _data( $var, $key = '' ) {
216 $vars = $this->{$var};
217 if ( $key ) {
218 return array_key_exists( $key, $vars ) ? $vars[ $key ] : false;
219 }
220 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 public function value( $key = '' ) {
231 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 public function get_data( $field_id = '', $args = array() ) {
243 if ( $field_id ) {
244 $args['field_id'] = $field_id;
245 } elseif ( $this->group ) {
246 $args['field_id'] = $this->group->id();
247 }
248
249 $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 $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 $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 if ( 'cmb2_field_no_override_val' === $data ) {
291 $data = 'options-page' === $a['type']
292 ? cmb2_options( $a['id'] )->get( $a['field_id'] )
293 : get_metadata( $a['type'], $a['id'], $a['field_id'], ( $a['single'] || $a['repeat'] ) );
294 }
295
296 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 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 */
314 public function update_data( $new_value, $single = true ) {
315 $a = $this->data_args( array(
316 'single' => $single,
317 ) );
318
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 */
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 */
355 $override = apply_filters( "cmb2_override_{$a['field_id']}_meta_save", $override, $a, $this->args(), $this );
356
357 // If override, return that.
358 if ( null !== $override ) {
359 return $override;
360 }
361
362 // Options page handling (or temp data store).
363 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 // Add metadata if not single.
368 if ( ! $a['single'] ) {
369 return add_metadata( $a['type'], $a['id'], $a['field_id'], $a['value'], false );
370 }
371
372 // 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 // 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 * @return mixed
387 */
388 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 * @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 * @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
434 // If no override, remove as usual.
435 if ( null !== $override ) {
436 return $override;
437 } // End if.
438 // Option page handling.
439 elseif ( 'options-page' === $a['type'] || empty( $a['id'] ) ) {
440 return cmb2_options( $a['id'] )->remove( $a['field_id'] );
441 }
442
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 * @return array Updated arguments
453 */
454 public function data_args( $args = array() ) {
455 $args = wp_parse_args( $args, array(
456 'type' => $this->object_type,
457 'id' => $this->object_id,
458 'field_id' => $this->id( true ),
459 'repeat' => $this->args( 'repeatable' ),
460 '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 * @return mixed Possibly sanitized meta value
471 */
472 public function sanitization_cb( $meta_value ) {
473
474 if ( $this->args( 'repeatable' ) && is_array( $meta_value ) ) {
475 // Remove empties.
476 $meta_value = array_filter( $meta_value );
477 }
478
479 // Check if the field has a registered validation callback.
480 $cb = $this->maybe_callback( 'sanitization_cb' );
481 if ( false === $cb ) {
482 // 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 }
488
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 * @param object $sanitizer This `CMB2_Sanitize` object
506 */
507 $override_value = apply_filters( "cmb2_sanitize_{$field_type}", null, $sanitizer->value, $this->object_id, $this->args(), $sanitizer );
508
509 if ( null !== $override_value ) {
510 return $override_value;
511 }
512
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 * @return array|int|bool Result of save, false on failure
523 */
524 public function save_field_from_data( array $data_to_save ) {
525 $this->data_to_save = $data_to_save;
526
527 $meta_value = isset( $this->data_to_save[ $this->id( true ) ] )
528 ? $this->data_to_save[ $this->id( true ) ]
529 : 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 * @return array|int|bool Result of save. false on failure
540 */
541 public function save_field( $meta_value ) {
542
543 $updated = false;
544 $action = '';
545 $new_value = $this->sanitization_cb( $meta_value );
546
547 if ( ! $this->args( 'save_field' ) ) {
548
549 // Nothing to see here.
550 $action = 'disabled';
551
552 } elseif ( $this->args( 'multiple' ) && ! $this->args( 'repeatable' ) && ! $this->group ) {
553
554 $this->remove_data();
555 $count = 0;
556
557 if ( ! empty( $new_value ) ) {
558 foreach ( $new_value as $add_new ) {
559 if ( $this->update_data( $add_new, false ) ) {
560 $count++;
561 }
562 }
563 }
564
565 $updated = $count ? $count : false;
566 $action = 'repeatable';
567
568 } elseif ( ! CMB2_Utils::isempty( $new_value ) && $new_value !== $this->get_data() ) {
569 $updated = $this->update_data( $new_value );
570 $action = 'updated';
571 } elseif ( CMB2_Utils::isempty( $new_value ) ) {
572 $updated = $this->remove_data();
573 $action = 'removed';
574 }
575
576 if ( $updated ) {
577 $this->value = $this->get_data();
578 $this->escaped_value = null;
579 }
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 * @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 * @param CMB2_Field object $field This field object
606 */
607 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 * @return bool True if exempt
617 */
618 public function escaping_exception() {
619 // 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 * @return bool True if type cannot be repeatable
633 */
634 public function repeatable_exception( $type ) {
635 // These types cannot be repeatable.
636 $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_select_hierarchical' => 1,
649 'taxonomy_multicheck' => 1,
650 'taxonomy_multicheck_inline' => 1,
651 'taxonomy_multicheck_hierarchical' => 1,
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 * array( 'my_custom_field' => 1 )
664 */
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 * @return bool True if has own method.
675 */
676 public function has_args_method( $type ) {
677
678 // These types have their own arguments parser.
679 $type_methods = array(
680 'group' => 'set_field_defaults_group',
681 'wysiwyg' => 'set_field_defaults_wysiwyg',
682 );
683
684 if ( isset( $type_methods[ $type ] ) ) {
685 return $type_methods[ $type ];
686 }
687
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_select_hierarchical',
694 'taxonomy_radio',
695 'taxonomy_radio_inline',
696 'taxonomy_radio_hierarchical',
697 ), $this ) );
698
699 if ( isset( $all_or_nothing_types[ $type ] ) ) {
700 return 'set_field_defaults_all_or_nothing_types';
701 }
702
703 return false;
704 }
705
706 /**
707 * Escape the value before output. Defaults to 'esc_attr()'
708 *
709 * @since 1.0.1
710 * @param callable|string $func Escaping function (if not esc_attr()).
711 * @param mixed $meta_value Meta value.
712 * @return mixed Final value.
713 */
714 public function escaped_value( $func = 'esc_attr', $meta_value = '' ) {
715
716 if ( null !== $this->escaped_value ) {
717 return $this->escaped_value;
718 }
719
720 $meta_value = $meta_value ? $meta_value : $this->value();
721
722 // Check if the field has a registered escaping callback.
723 if ( $cb = $this->maybe_callback( 'escape_cb' ) ) {
724 // Ok, callback is good, let's run it.
725 return call_user_func( $cb, $meta_value, $this->args(), $this );
726 }
727
728 $field_type = $this->type();
729
730 /**
731 * Filter the value for escaping before it is ouput.
732 *
733 * The dynamic portion of the hook name, $field_type, refers to the field type.
734 *
735 * Passing a non-null value to the filter will short-circuit the built-in
736 * escaping for this field.
737 *
738 * @param bool|mixed $override_value Escaping override value to return.
739 * Default: null. false to skip it.
740 * @param mixed $meta_value The value to be output.
741 * @param array $field_args The current field's arguments.
742 * @param object $field This `CMB2_Field` object.
743 */
744 $esc = apply_filters( "cmb2_types_esc_{$field_type}", null, $meta_value, $this->args(), $this );
745 if ( null !== $esc ) {
746 return $esc;
747 }
748
749 if ( false === $cb || $this->escaping_exception() ) {
750 // If requesting NO escaping, return meta value.
751 return $this->val_or_default( $meta_value );
752 }
753
754 // escaping function passed in?
755 $func = $func ? $func : 'esc_attr';
756 $meta_value = $this->val_or_default( $meta_value );
757
758 if ( is_array( $meta_value ) ) {
759 foreach ( $meta_value as $key => $value ) {
760 $meta_value[ $key ] = call_user_func( $func, $value );
761 }
762 } else {
763 $meta_value = call_user_func( $func, $meta_value );
764 }
765
766 $this->escaped_value = $meta_value;
767 return $this->escaped_value;
768 }
769
770 /**
771 * Return non-empty value or field default if value IS empty
772 *
773 * @since 2.0.0
774 * @param mixed $meta_value Field value.
775 * @return mixed Field value, or default value
776 */
777 public function val_or_default( $meta_value ) {
778 return ! CMB2_Utils::isempty( $meta_value ) ? $meta_value : $this->get_default();
779 }
780
781 /**
782 * Offset a time value based on timezone
783 *
784 * @since 1.0.0
785 * @return string Offset time string
786 */
787 public function field_timezone_offset() {
788 return CMB2_Utils::timezone_offset( $this->field_timezone() );
789 }
790
791 /**
792 * Return timezone string
793 *
794 * @since 1.0.0
795 * @return string Timezone string
796 */
797 public function field_timezone() {
798 $value = '';
799
800 // Is timezone arg set?
801 if ( $this->args( 'timezone' ) ) {
802 $value = $this->args( 'timezone' );
803 } // End if.
804 // Is there another meta key with a timezone stored as its value we should use?
805 elseif ( $this->args( 'timezone_meta_key' ) ) {
806 $value = $this->get_data( $this->args( 'timezone_meta_key' ) );
807 }
808
809 return $value;
810 }
811
812 /**
813 * Format the timestamp field value based on the field date/time format arg
814 *
815 * @since 2.0.0
816 * @param int $meta_value Timestamp.
817 * @param string $format Either date_format or time_format.
818 * @return string Formatted date
819 */
820 public function format_timestamp( $meta_value, $format = 'date_format' ) {
821 return date( stripslashes( $this->args( $format ) ), $meta_value );
822 }
823
824 /**
825 * Return a formatted timestamp for a field
826 *
827 * @since 2.0.0
828 * @param string $format Either date_format or time_format.
829 * @param string|int $meta_value Optional meta value to check.
830 * @return string Formatted date
831 */
832 public function get_timestamp_format( $format = 'date_format', $meta_value = 0 ) {
833 $meta_value = $meta_value ? $meta_value : $this->escaped_value();
834 if ( empty( $meta_value ) ) {
835 $meta_value = $this->get_default();
836 }
837
838 $meta_value = CMB2_Utils::make_valid_time_stamp( $meta_value );
839 if ( empty( $meta_value ) ) {
840 return '';
841 }
842
843 return is_array( $meta_value )
844 ? array_map( array( $this, 'format_timestamp' ), $meta_value, $format )
845 : $this->format_timestamp( $meta_value, $format );
846 }
847
848 /**
849 * Get timestamp from text date
850 *
851 * @since 2.2.0
852 * @param string $value Date value.
853 * @return mixed Unix timestamp representing the date.
854 */
855 public function get_timestamp_from_value( $value ) {
856 return CMB2_Utils::get_timestamp_from_value( $value, $this->args( 'date_format' ) );
857 }
858
859 /**
860 * Get field render callback and Render the field row
861 *
862 * @since 1.0.0
863 */
864 public function render_field() {
865 $this->render_context = 'edit';
866
867 $this->peform_param_callback( 'render_row_cb' );
868
869 // For chaining.
870 return $this;
871 }
872
873 /**
874 * Default field render callback
875 *
876 * @since 2.1.1
877 */
878 public function render_field_callback() {
879
880 // If field is requesting to not be shown on the front-end.
881 if ( ! is_admin() && ! $this->args( 'on_front' ) ) {
882 return;
883 }
884
885 // If field is requesting to be conditionally shown.
886 if ( ! $this->should_show() ) {
887 return;
888 }
889
890 $field_type = $this->type();
891
892 /**
893 * Hook before field row begins.
894 *
895 * @param CMB2_Field $field The current field object.
896 */
897 do_action( 'cmb2_before_field_row', $this );
898
899 /**
900 * Hook before field row begins.
901 *
902 * The dynamic portion of the hook name, $field_type, refers to the field type.
903 *
904 * @param CMB2_Field $field The current field object.
905 */
906 do_action( "cmb2_before_{$field_type}_field_row", $this );
907
908 $this->peform_param_callback( 'before_row' );
909
910 printf( "<div class=\"cmb-row %s\" data-fieldtype=\"%s\">\n", $this->row_classes(), $field_type );
911
912 if ( ! $this->args( 'show_names' ) ) {
913 echo "\n\t<div class=\"cmb-td\">\n";
914
915 $this->peform_param_callback( 'label_cb' );
916
917 } else {
918
919 if ( $this->get_param_callback_result( 'label_cb' ) ) {
920 echo '<div class="cmb-th">', $this->peform_param_callback( 'label_cb' ), '</div>';
921 }
922
923 echo "\n\t<div class=\"cmb-td\">\n";
924 }
925
926 $this->peform_param_callback( 'before' );
927
928 $types = new CMB2_Types( $this );
929 $types->render();
930
931 $this->peform_param_callback( 'after' );
932
933 echo "\n\t</div>\n</div>";
934
935 $this->peform_param_callback( 'after_row' );
936
937 /**
938 * Hook after field row ends.
939 *
940 * The dynamic portion of the hook name, $field_type, refers to the field type.
941 *
942 * @param CMB2_Field $field The current field object.
943 */
944 do_action( "cmb2_after_{$field_type}_field_row", $this );
945
946 /**
947 * Hook after field row ends.
948 *
949 * @param CMB2_Field $field The current field object.
950 */
951 do_action( 'cmb2_after_field_row', $this );
952
953 // For chaining.
954 return $this;
955 }
956
957 /**
958 * The default label_cb callback (if not a title field)
959 *
960 * @since 2.1.1
961 * @return string Label html markup.
962 */
963 public function label() {
964 if ( ! $this->args( 'name' ) ) {
965 return '';
966 }
967
968 $style = ! $this->args( 'show_names' ) ? ' style="display:none;"' : '';
969
970 return sprintf( "\n" . '<label%1$s for="%2$s">%3$s</label>' . "\n", $style, $this->id(), $this->args( 'name' ) );
971 }
972
973 /**
974 * Defines the classes for the current CMB2 field row
975 *
976 * @since 2.0.0
977 * @return string Space concatenated list of classes
978 */
979 public function row_classes() {
980
981 $classes = array();
982
983 /**
984 * By default, 'text_url' and 'text' fields get table-like styling
985 *
986 * @since 2.0.0
987 *
988 * @param array $field_types The types of fields which should get the 'table-layout' class
989 */
990 $repeat_table_rows_types = apply_filters( 'cmb2_repeat_table_row_types', array(
991 'text_url',
992 'text',
993 ) );
994
995 $conditional_classes = array(
996 'cmb-type-' . str_replace( '_', '-', sanitize_html_class( $this->type() ) ) => true,
997 'cmb2-id-' . str_replace( '_', '-', sanitize_html_class( $this->id() ) ) => true,
998 'cmb-repeat' => $this->args( 'repeatable' ),
999 'cmb-repeat-group-field' => $this->group,
1000 'cmb-inline' => $this->args( 'inline' ),
1001 'table-layout' => 'edit' === $this->render_context && in_array( $this->type(), $repeat_table_rows_types ),
1002 );
1003
1004 foreach ( $conditional_classes as $class => $condition ) {
1005 if ( $condition ) {
1006 $classes[] = $class;
1007 }
1008 }
1009
1010 if ( $added_classes = $this->args( 'classes' ) ) {
1011 $added_classes = is_array( $added_classes ) ? implode( ' ', $added_classes ) : (string) $added_classes;
1012 } elseif ( $added_classes = $this->get_param_callback_result( 'classes_cb' ) ) {
1013 $added_classes = is_array( $added_classes ) ? implode( ' ', $added_classes ) : (string) $added_classes;
1014 }
1015
1016 if ( $added_classes ) {
1017 $classes[] = esc_attr( $added_classes );
1018 }
1019
1020 /**
1021 * Globally filter row classes
1022 *
1023 * @since 2.0.0
1024 *
1025 * @param string $classes Space-separated list of row classes
1026 * @param CMB2_Field object $field This field object
1027 */
1028 return apply_filters( 'cmb2_row_classes', implode( ' ', $classes ), $this );
1029 }
1030
1031 /**
1032 * Get field display callback and render the display value in the column.
1033 *
1034 * @since 2.2.2
1035 */
1036 public function render_column() {
1037 $this->render_context = 'display';
1038
1039 $this->peform_param_callback( 'display_cb' );
1040
1041 // For chaining.
1042 return $this;
1043 }
1044
1045 /**
1046 * The method to fetch the value for this field for the REST API.
1047 *
1048 * @since 2.5.0
1049 */
1050 public function get_rest_value() {
1051 $field_type = $this->type();
1052 $field_id = $this->id( true );
1053
1054 if ( $cb = $this->maybe_callback( 'rest_value_cb' ) ) {
1055 add_filter( "cmb2_get_rest_value_for_{$field_id}", $cb, 99 );
1056 }
1057
1058 $value = $this->get_data();
1059
1060 /**
1061 * Filter the value before it is sent to the REST request.
1062 *
1063 * @since 2.5.0
1064 *
1065 * @param mixed $value The value from CMB2_Field::get_data()
1066 * @param CMB2_Field $field This field object.
1067 */
1068 $value = apply_filters( 'cmb2_get_rest_value', $value, $this );
1069
1070 /**
1071 * Filter the value before it is sent to the REST request.
1072 *
1073 * The dynamic portion of the hook name, $field_type, refers to the field type.
1074 *
1075 * @since 2.5.0
1076 *
1077 * @param mixed $value The value from CMB2_Field::get_data()
1078 * @param CMB2_Field $field This field object.
1079 */
1080 $value = apply_filters( "cmb2_get_rest_value_{$field_type}", $value, $this );
1081
1082 /**
1083 * Filter the value before it is sent to the REST request.
1084 *
1085 * The dynamic portion of the hook name, $field_id, refers to the field id.
1086 *
1087 * @since 2.5.0
1088 *
1089 * @param mixed $value The value from CMB2_Field::get_data()
1090 * @param CMB2_Field $field This field object.
1091 */
1092 return apply_filters( "cmb2_get_rest_value_for_{$field_id}", $value, $this );
1093 }
1094
1095 /**
1096 * Get a field object for a supporting field. (e.g. file field)
1097 *
1098 * @since 2.7.0
1099 *
1100 * @return CMB2_Field|bool Supporting field object, if supported.
1101 */
1102 public function get_supporting_field() {
1103 $suffix = $this->args( 'has_supporting_data' );
1104 if ( empty( $suffix ) ) {
1105 return false;
1106 }
1107
1108 return $this->get_field_clone( array(
1109 'id' => $this->_id( '', false ) . $suffix,
1110 'sanitization_cb' => false,
1111 ) );
1112 }
1113
1114 /**
1115 * Default callback to outputs field value in a display format.
1116 *
1117 * @since 2.2.2
1118 */
1119 public function display_value_callback() {
1120 // If field is requesting to be conditionally shown.
1121 if ( ! $this->should_show() ) {
1122 return;
1123 }
1124
1125 $display = new CMB2_Field_Display( $this );
1126 $field_type = $this->type();
1127
1128 /**
1129 * A filter to bypass the default display.
1130 *
1131 * The dynamic portion of the hook name, $field_type, refers to the field type.
1132 *
1133 * Passing a non-null value to the filter will short-circuit the default display.
1134 *
1135 * @param bool|mixed $pre_output Default null value.
1136 * @param CMB2_Field $field This field object.
1137 * @param CMB2_Field_Display $display The `CMB2_Field_Display` object.
1138 */
1139 $pre_output = apply_filters( "cmb2_pre_field_display_{$field_type}", null, $this, $display );
1140
1141 if ( null !== $pre_output ) {
1142 echo $pre_output;
1143 return;
1144 }
1145
1146 $this->peform_param_callback( 'before_display_wrap' );
1147
1148 printf( "<div class=\"cmb-column %s\" data-fieldtype=\"%s\">\n", $this->row_classes(), $field_type );
1149
1150 $this->peform_param_callback( 'before_display' );
1151
1152 CMB2_Field_Display::get( $this )->display();
1153
1154 $this->peform_param_callback( 'after_display' );
1155
1156 echo "\n</div>";
1157
1158 $this->peform_param_callback( 'after_display_wrap' );
1159
1160 // For chaining.
1161 return $this;
1162 }
1163
1164 /**
1165 * Replaces a hash key - {#} - with the repeatable index
1166 *
1167 * @since 1.2.0
1168 * @param string $value Value to update.
1169 * @return string Updated value
1170 */
1171 public function replace_hash( $value ) {
1172 // Replace hash with 1 based count.
1173 return str_replace( '{#}', ( $this->index + 1 ), $value );
1174 }
1175
1176 /**
1177 * Retrieve text parameter from field's text array (if it has one), or use fallback text
1178 * For back-compatibility, falls back to checking the options array.
1179 *
1180 * @since 2.2.2
1181 * @param string $text_key Key in field's text array.
1182 * @param string $fallback Fallback text.
1183 * @return string Text
1184 */
1185 public function get_string( $text_key, $fallback ) {
1186 // If null, populate with our field strings values.
1187 if ( null === $this->strings ) {
1188 $this->strings = (array) $this->args['text'];
1189
1190 if ( is_callable( $this->args['text_cb'] ) ) {
1191 $strings = call_user_func( $this->args['text_cb'], $this );
1192
1193 if ( $strings && is_array( $strings ) ) {
1194 $this->strings += $strings;
1195 }
1196 }
1197 }
1198
1199 // If we have that string value, send it back.
1200 if ( isset( $this->strings[ $text_key ] ) ) {
1201 return $this->strings[ $text_key ];
1202 }
1203
1204 // Check options for back-compat.
1205 $string = $this->options( $text_key );
1206
1207 return $string ? $string : $fallback;
1208 }
1209
1210 /**
1211 * Retrieve options args.
1212 *
1213 * @since 2.0.0
1214 * @param string $key Specific option to retrieve.
1215 * @return array|mixed Array of options or specific option.
1216 */
1217 public function options( $key = '' ) {
1218 if ( empty( $this->field_options ) ) {
1219 $this->set_options();
1220 }
1221
1222 if ( $key ) {
1223 return array_key_exists( $key, $this->field_options ) ? $this->field_options[ $key ] : false;
1224 }
1225
1226 return $this->field_options;
1227 }
1228
1229 /**
1230 * Generates/sets options args. Calls options_cb if it exists.
1231 *
1232 * @since 2.2.5
1233 *
1234 * @return array Array of options
1235 */
1236 public function set_options() {
1237 $this->field_options = (array) $this->args['options'];
1238
1239 if ( is_callable( $this->args['options_cb'] ) ) {
1240 $options = call_user_func( $this->args['options_cb'], $this );
1241
1242 if ( $options && is_array( $options ) ) {
1243 $this->field_options = $options + $this->field_options;
1244 }
1245 }
1246
1247 return $this->field_options;
1248 }
1249
1250 /**
1251 * Store JS dependencies as part of the field args.
1252 *
1253 * @since 2.2.0
1254 * @param array $dependencies Dependies to register for this field.
1255 */
1256 public function add_js_dependencies( $dependencies = array() ) {
1257 foreach ( (array) $dependencies as $dependency ) {
1258 $this->args['js_dependencies'][ $dependency ] = $dependency;
1259 }
1260
1261 CMB2_JS::add_dependencies( $dependencies );
1262 }
1263
1264 /**
1265 * Send field data to JS.
1266 *
1267 * @since 2.2.0
1268 */
1269 public function register_js_data() {
1270 if ( $this->group ) {
1271 CMB2_JS::add_field_data( $this->group );
1272 }
1273
1274 return CMB2_JS::add_field_data( $this );
1275 }
1276
1277 /**
1278 * Get an array of some of the field data to be used in the Javascript.
1279 *
1280 * @since 2.2.4
1281 *
1282 * @return array
1283 */
1284 public function js_data() {
1285 return array(
1286 'label' => $this->args( 'name' ),
1287 'id' => $this->id( true ),
1288 'type' => $this->type(),
1289 'hash' => $this->hash_id(),
1290 'box' => $this->cmb_id,
1291 'id_attr' => $this->id(),
1292 'name_attr' => $this->args( '_name' ),
1293 'default' => $this->get_default(),
1294 'group' => $this->group_id(),
1295 'index' => $this->group ? $this->group->index : null,
1296 );
1297 }
1298
1299 /**
1300 * Returns a unique hash representing this field.
1301 *
1302 * @since 2.2.4
1303 *
1304 * @return string
1305 */
1306 public function hash_id() {
1307 if ( '' === $this->hash_id ) {
1308 $this->hash_id = CMB2_Utils::generate_hash( $this->cmb_id . '||' . $this->id() );
1309 }
1310
1311 return $this->hash_id;
1312 }
1313
1314 /**
1315 * Gets the id of the group field if this field is part of a group.
1316 *
1317 * @since 2.2.4
1318 *
1319 * @return string
1320 */
1321 public function group_id() {
1322 return $this->group ? $this->group->id( true ) : '';
1323 }
1324
1325 /**
1326 * Get CMB2_Field default value, either from default param or default_cb param.
1327 *
1328 * @since 0.2.2
1329 *
1330 * @return mixed Default field value
1331 */
1332 public function get_default() {
1333 $default = $this->args['default'];
1334
1335 if ( null !== $default ) {
1336 return apply_filters( 'cmb2_default_filter', $default, $this );
1337 }
1338
1339 $param = is_callable( $this->args['default_cb'] ) ? 'default_cb' : 'default';
1340 $default = $this->args['default'] = $this->get_param_callback_result( $param );
1341
1342 // Allow a filter override of the default value.
1343 return apply_filters( 'cmb2_default_filter', $this->args['default'], $this );
1344 }
1345
1346 /**
1347 * Fills in empty field parameters with defaults
1348 *
1349 * @since 1.1.0
1350 *
1351 * @param array $args Field config array.
1352 * @return array Modified field config array.
1353 */
1354 public function _set_field_defaults( $args ) {
1355 $defaults = $this->get_default_field_args( $args );
1356
1357 /**
1358 * Filter the CMB2 Field defaults.
1359 *
1360 * @since 2.6.0
1361 * @param array $defaults Metabox field config array defaults.
1362 * @param string $id Field id for the current field to allow for selective filtering.
1363 * @param string $type Field type for the current field to allow for selective filtering.
1364 * @param CMB2_Field object $field This field object.
1365 */
1366 $defaults = apply_filters( 'cmb2_field_defaults', $defaults, $args['id'], $args['type'], $this );
1367
1368 // Set up blank or default values for empty ones.
1369 $args = wp_parse_args( $args, $defaults );
1370
1371 /**
1372 * Filtering the CMB2 Field arguments once merged with the defaults, but before further processing.
1373 *
1374 * @since 2.6.0
1375 * @param array $args Metabox field config array defaults.
1376 * @param CMB2_Field object $field This field object.
1377 */
1378 $args = apply_filters( 'cmb2_field_arguments_raw', $args, $this );
1379
1380 /*
1381 * Deprecated usage:
1382 *
1383 * 'std' -- use 'default' (no longer works)
1384 * 'row_classes' -- use 'class', or 'class_cb'
1385 * 'default' -- as callback (use default_cb)
1386 */
1387 $args = $this->convert_deprecated_params( $args );
1388
1389 $args['repeatable'] = $args['repeatable'] && ! $this->repeatable_exception( $args['type'] );
1390 $args['inline'] = $args['inline'] || false !== stripos( $args['type'], '_inline' );
1391 $args['_id'] = $args['id'];
1392 $args['_name'] = $args['id'];
1393
1394 if ( $method = $this->has_args_method( $args['type'] ) ) {
1395 $args = $this->{$method}( $args );
1396 }
1397
1398 if ( $this->group ) {
1399 $args = $this->set_group_sub_field_defaults( $args );
1400 }
1401
1402 $with_supporting = array(
1403 // CMB2_Sanitize::_save_file_id_value()/CMB2_Sanitize::_get_group_file_value_array().
1404 'file' => '_id',
1405 // See CMB2_Sanitize::_save_utc_value().
1406 'text_datetime_timestamp_timezone' => '_utc',
1407 );
1408
1409 $args['has_supporting_data'] = isset( $with_supporting[ $args['type'] ] )
1410 ? $with_supporting[ $args['type'] ]
1411 : false;
1412
1413 // Repeatable fields require jQuery sortable library.
1414 if ( ! empty( $args['repeatable'] ) ) {
1415 CMB2_JS::add_dependencies( 'jquery-ui-sortable' );
1416 }
1417
1418 /**
1419 * Filter the CMB2 Field arguments after processing.
1420 *
1421 * @since 2.6.0
1422 * @param array $args Metabox field config array after processing.
1423 * @param CMB2_Field object $field This field object.
1424 */
1425 return apply_filters( 'cmb2_field_arguments', $args, $this );
1426 }
1427
1428 /**
1429 * Sets default arguments for the group field types.
1430 *
1431 * @since 2.2.6
1432 *
1433 * @param array $args Field config array.
1434 * @return array Modified field config array.
1435 */
1436 protected function set_field_defaults_group( $args ) {
1437 $args['options'] = wp_parse_args( $args['options'], array(
1438 'add_button' => esc_html__( 'Add Group', 'cmb2' ),
1439 'remove_button' => esc_html__( 'Remove Group', 'cmb2' ),
1440 'remove_confirm' => '',
1441 ) );
1442
1443 return $args;
1444 }
1445
1446 /**
1447 * Sets default arguments for the wysiwyg field types.
1448 *
1449 * @since 2.2.6
1450 *
1451 * @param array $args Field config array.
1452 * @return array Modified field config array.
1453 */
1454 protected function set_field_defaults_wysiwyg( $args ) {
1455 $args['id'] = strtolower( str_ireplace( '-', '_', $args['id'] ) );
1456 $args['options']['textarea_name'] = $args['_name'];
1457
1458 return $args;
1459 }
1460
1461 /**
1462 * Sets default arguments for the all-or-nothing field types.
1463 *
1464 * @since 2.2.6
1465 *
1466 * @param array $args Field config array.
1467 * @return array Modified field config array.
1468 */
1469 protected function set_field_defaults_all_or_nothing_types( $args ) {
1470 $args['show_option_none'] = isset( $args['show_option_none'] ) ? $args['show_option_none'] : null;
1471 $args['show_option_none'] = true === $args['show_option_none'] ? esc_html__( 'None', 'cmb2' ) : $args['show_option_none'];
1472
1473 if ( null === $args['show_option_none'] ) {
1474 $off_by_default = in_array( $args['type'], array( 'select', 'radio', 'radio_inline' ), true );
1475 $args['show_option_none'] = $off_by_default ? false : esc_html__( 'None', 'cmb2' );
1476 }
1477
1478 return $args;
1479 }
1480
1481 /**
1482 * Sets default arguments for group sub-fields.
1483 *
1484 * @since 2.2.6
1485 *
1486 * @param array $args Field config array.
1487 * @return array Modified field config array.
1488 */
1489 protected function set_group_sub_field_defaults( $args ) {
1490 $args['id'] = $this->group->args( 'id' ) . '_' . $this->group->index . '_' . $args['id'];
1491 $args['_name'] = $this->group->args( 'id' ) . '[' . $this->group->index . '][' . $args['_name'] . ']';
1492
1493 return $args;
1494 }
1495
1496 /**
1497 * Gets the default arguments for all fields.
1498 *
1499 * @since 2.2.6
1500 *
1501 * @param array $args Field config array.
1502 * @return array Field defaults.
1503 */
1504 protected function get_default_field_args( $args ) {
1505 $type = isset( $args['type'] ) ? $args['type'] : '';
1506
1507 return array(
1508 'type' => $type,
1509 'name' => '',
1510 'desc' => '',
1511 'before' => '',
1512 'after' => '',
1513 'options' => array(),
1514 'options_cb' => '',
1515 'text' => array(),
1516 'text_cb' => '',
1517 'attributes' => array(),
1518 'protocols' => null,
1519 'default' => null,
1520 'default_cb' => '',
1521 'classes' => null,
1522 'classes_cb' => '',
1523 'select_all_button' => true,
1524 'multiple' => false,
1525 'repeatable' => 'group' === $type,
1526 'inline' => false,
1527 'on_front' => true,
1528 'show_names' => true,
1529 'save_field' => true, // Will not save if false.
1530 'date_format' => 'm\/d\/Y',
1531 'time_format' => 'h:i A',
1532 'description' => isset( $args['desc'] ) ? $args['desc'] : '',
1533 'preview_size' => 'file' === $type ? array( 350, 350 ) : array( 50, 50 ),
1534 'render_row_cb' => array( $this, 'render_field_callback' ),
1535 'display_cb' => array( $this, 'display_value_callback' ),
1536 'label_cb' => 'title' !== $type ? array( $this, 'label' ) : '',
1537 'column' => false,
1538 'js_dependencies' => array(),
1539 'show_in_rest' => null,
1540 'char_counter' => false,
1541 'char_max' => false,
1542 'char_max_enforce' => false,
1543 );
1544 }
1545
1546 /**
1547 * Get default field arguments specific to this CMB2 object.
1548 *
1549 * @since 2.2.0
1550 * @param array $field_args Metabox field config array.
1551 * @param CMB2_Field $field_group (optional) CMB2_Field object (group parent).
1552 * @return array Array of field arguments.
1553 */
1554 protected function get_default_args( $field_args, $field_group = null ) {
1555 $args = parent::get_default_args( array(), $this->group );
1556
1557 if ( isset( $field_args['field_args'] ) ) {
1558 $args = wp_parse_args( $field_args, $args );
1559 } else {
1560 $args['field_args'] = wp_parse_args( $field_args, $this->args );
1561 }
1562
1563 return $args;
1564 }
1565
1566 /**
1567 * Returns a cloned version of this field object, but with
1568 * modified/overridden field arguments.
1569 *
1570 * @since 2.2.2
1571 * @param array $field_args Array of field arguments, or entire array of
1572 * arguments for CMB2_Field.
1573 *
1574 * @return CMB2_Field The new CMB2_Field instance.
1575 */
1576 public function get_field_clone( $field_args ) {
1577 return $this->get_new_field( $field_args );
1578 }
1579
1580 /**
1581 * Returns the CMB2 instance this field is registered to.
1582 *
1583 * @since 2.2.2
1584 *
1585 * @return CMB2|WP_Error If new CMB2_Field is called without cmb_id arg, returns error.
1586 */
1587 public function get_cmb() {
1588 if ( ! $this->cmb_id ) {
1589 return new WP_Error( 'no_cmb_id', esc_html__( 'Sorry, this field does not have a cmb_id specified.', 'cmb2' ) );
1590 }
1591
1592 return cmb2_get_metabox( $this->cmb_id, $this->object_id, $this->object_type );
1593 }
1594
1595 /**
1596 * Converts deprecated field parameters to the current/proper parameter, and throws a deprecation notice.
1597 *
1598 * @since 2.2.3
1599 * @param array $args Metabox field config array.
1600 * @return array Modified field config array.
1601 */
1602 protected function convert_deprecated_params( $args ) {
1603
1604 if ( isset( $args['row_classes'] ) ) {
1605
1606 // We'll let this one be.
1607 // $this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_PARAM, 'row_classes', 'classes' );
1608 // row_classes param could be a callback. This is definitely deprecated.
1609 if ( is_callable( $args['row_classes'] ) ) {
1610
1611 $this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'row_classes', 'classes_cb' );
1612
1613 $args['classes_cb'] = $args['row_classes'];
1614 $args['classes'] = null;
1615 } else {
1616
1617 $args['classes'] = $args['row_classes'];
1618 }
1619
1620 unset( $args['row_classes'] );
1621 }
1622
1623 // default param can be passed a callback as well.
1624 if ( is_callable( $args['default'] ) ) {
1625
1626 $this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'default', 'default_cb' );
1627
1628 $args['default_cb'] = $args['default'];
1629 $args['default'] = null;
1630 }
1631
1632 // options param can be passed a callback as well.
1633 if ( is_callable( $args['options'] ) ) {
1634
1635 $this->deprecated_param( __CLASS__ . '::__construct()', '2.2.3', self::DEPRECATED_CB_PARAM, 'options', 'options_cb' );
1636
1637 $args['options_cb'] = $args['options'];
1638 $args['options'] = array();
1639 }
1640
1641 return $args;
1642 }
1643
1644 }
1645