PluginProbe
Cool Flipbox – Shortcode & Gutenberg Block / 1.4
Cool Flipbox – Shortcode & Gutenberg Block v1.4
trunk 1.4 1.5 1.6 1.6.2 1.7.1 1.8.3 1.9.0 1.9.1 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1
flip-boxes / CMB2 / includes / CMB2_Types.php

CMB2_Types.php in Cool Flipbox – Shortcode & Gutenberg Block 1.4, at CMB2/includes/CMB2_Types.php

670 lines 21.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * CMB field type objects
4 *
5 * @since 1.0.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 _name()
15 * @method string _desc()
16 * @method string _text()
17 * @method string concat_attrs()
18 */
19 class CMB2_Types {
20
21 /**
22 * An iterator value for repeatable fields
23 *
24 * @var integer
25 * @since 1.0.0
26 */
27 public $iterator = 0;
28
29 /**
30 * Current CMB2_Field field object
31 *
32 * @var CMB2_Field object
33 * @since 1.0.0
34 */
35 public $field;
36
37 /**
38 * Current CMB2_Type_Base object
39 *
40 * @var CMB2_Type_Base object
41 * @since 2.2.2
42 */
43 public $type = null;
44
45 public function __construct( CMB2_Field $field ) {
46 $this->field = $field;
47 }
48
49 /**
50 * Default fallback. Allows rendering fields via "cmb2_render_$fieldtype" hook
51 *
52 * @since 1.0.0
53 * @param string $fieldtype Non-existent field type name
54 * @param array $arguments All arguments passed to the method
55 */
56 public function __call( $fieldtype, $arguments ) {
57
58 // Check for methods to be proxied to the CMB2_Type_Base object.
59 if ( $exists = $this->maybe_proxy_method( $fieldtype, $arguments ) ) {
60 return $exists['value'];
61 }
62
63 // Check for custom field type class.
64 if ( $object = $this->maybe_custom_field_object( $fieldtype, $arguments ) ) {
65 return $object->render();
66 }
67
68 /**
69 * Pass non-existent field types through an action.
70 *
71 * The dynamic portion of the hook name, $fieldtype, refers to the field type.
72 *
73 * @param array $field The passed in `CMB2_Field` object
74 * @param mixed $escaped_value The value of this field escaped.
75 * It defaults to `sanitize_text_field`.
76 * If you need the unescaped value, you can access it
77 * via `$field->value()`
78 * @param int $object_id The ID of the current object
79 * @param string $object_type The type of object you are working with.
80 * Most commonly, `post` (this applies to all post-types),
81 * but could also be `comment`, `user` or `options-page`.
82 * @param object $field_type_object This `CMB2_Types` object
83 */
84 do_action( "cmb2_render_{$fieldtype}", $this->field, $this->field->escaped_value(), $this->field->object_id, $this->field->object_type, $this );
85 }
86
87 /**
88 * Render a field (and handle repeatable)
89 *
90 * @since 1.1.0
91 */
92 public function render() {
93 if ( $this->field->args( 'repeatable' ) ) {
94 $this->render_repeatable_field();
95 } else {
96 $this->_render();
97 }
98 }
99
100 /**
101 * Render a field type
102 *
103 * @since 1.1.0
104 */
105 protected function _render() {
106 $this->field->peform_param_callback( 'before_field' );
107 echo $this->{$this->field->type()}();
108 $this->field->peform_param_callback( 'after_field' );
109 }
110
111 /**
112 * Proxies the method call to the CMB2_Type_Base object, if it exists, otherwise returns a default fallback value.
113 *
114 * @since 2.2.2
115 *
116 * @param string $method Method to call on the CMB2_Type_Base object.
117 * @param mixed $default Default fallback value if method is not found.
118 * @param array $args Optional arguments to pass to proxy method.
119 *
120 * @return mixed Results from called method.
121 */
122 protected function proxy_method( $method, $default, $args = array() ) {
123 if ( ! is_object( $this->type ) ) {
124 $this->guess_type_object( $method );
125 }
126
127 if ( is_object( $this->type ) && method_exists( $this->type, $method ) ) {
128
129 return empty( $args )
130 ? $this->type->$method()
131 : call_user_func_array( array( $this->type, $method ), $args );
132 }
133
134 return $default;
135 }
136
137 /**
138 * If no CMB2_Types::$type object is initiated when a proxy method is called, it means
139 * it's a custom field type (which SHOULD be instantiating a Type), but let's try and
140 * guess the type object for them and instantiate it.
141 *
142 * @since 2.2.3
143 *
144 * @param string $method Method attempting to be called on the CMB2_Type_Base object.
145 * @return bool
146 */
147 protected function guess_type_object( $method ) {
148 $fieldtype = $this->field->type();
149
150 // Try to "guess" the Type object based on the method requested.
151 switch ( $method ) {
152 case 'select_option':
153 case 'list_input':
154 case 'list_input_checkbox':
155 case 'concat_items':
156 $this->get_new_render_type( $fieldtype, 'CMB2_Type_Select' );
157 break;
158 case 'is_valid_img_ext':
159 case 'img_status_output':
160 case 'file_status_output':
161 $this->get_new_render_type( $fieldtype, 'CMB2_Type_File_Base' );
162 break;
163 case 'parse_picker_options':
164 $this->get_new_render_type( $fieldtype, 'CMB2_Type_Text_Date' );
165 break;
166 case 'get_object_terms':
167 case 'get_terms':
168 $this->get_new_render_type( $fieldtype, 'CMB2_Type_Taxonomy_Multicheck' );
169 break;
170 case 'date_args':
171 case 'time_args':
172 $this->get_new_render_type( $fieldtype, 'CMB2_Type_Text_Datetime_Timestamp' );
173 break;
174 case 'parse_args':
175 $this->get_new_render_type( $fieldtype, 'CMB2_Type_Text' );
176 break;
177 }
178
179 return null !== $this->type;
180 }
181
182 /**
183 * Check for methods to be proxied to the CMB2_Type_Base object.
184 *
185 * @since 2.2.4
186 * @param string $method The possible method to proxy.
187 * @param array $arguments All arguments passed to the method.
188 * @return bool|array False if not proxied, else array with 'value' key being the return of the method.
189 */
190 public function maybe_proxy_method( $method, $arguments ) {
191 $exists = false;
192
193 $proxied = array(
194 'get_object_terms' => array(),
195 'is_valid_img_ext' => false,
196 'parse_args' => array(),
197 'concat_items' => '',
198 'select_option' => '',
199 'list_input' => '',
200 'list_input_checkbox' => '',
201 'img_status_output' => '',
202 'file_status_output' => '',
203 'parse_picker_options' => array(),
204 );
205 if ( isset( $proxied[ $method ] ) ) {
206 $exists = array(
207 // Ok, proxy the method call to the CMB2_Type_Base object.
208 'value' => $this->proxy_method( $method, $proxied[ $method ], $arguments ),
209 );
210 }
211
212 return $exists;
213 }
214
215 /**
216 * Checks for a custom field CMB2_Type_Base class to use for rendering.
217 *
218 * @since 2.2.4
219 *
220 * @param string $fieldtype Non-existent field type name.
221 * @param array $args Optional field arguments.
222 *
223 * @return bool|CMB2_Type_Base Type object if custom field is an object, false if field was added with
224 * `cmb2_render_{$field_type}` action.
225 * @throws Exception if custom field type class does not extend CMB2_Type_Base.
226 */
227 public function maybe_custom_field_object( $fieldtype, $args = array() ) {
228 if ( $render_class_name = $this->get_render_type_class( $fieldtype ) ) {
229 $this->type = new $render_class_name( $this, $args );
230
231 if ( ! ( $this->type instanceof CMB2_Type_Base ) ) {
232 throw new Exception( __( 'Custom CMB2 field type classes must extend CMB2_Type_Base.', 'cmb2' ) );
233 }
234
235 return $this->type;
236 }
237
238 return false;
239 }
240
241 /**
242 * Gets the render type CMB2_Type_Base object to use for rendering the field.
243 *
244 * @since 2.2.4
245 * @param string $fieldtype The type of field being rendered.
246 * @param string $render_class_name The default field type class to use. Defaults to null.
247 * @param array $args Optional arguments to pass to type class.
248 * @param mixed $additional Optional additional argument to pass to type class.
249 * @return CMB2_Type_Base Type object.
250 */
251 public function get_new_render_type( $fieldtype, $render_class_name = null, $args = array(), $additional = '' ) {
252 $render_class_name = $this->get_render_type_class( $fieldtype, $render_class_name );
253 $this->type = new $render_class_name( $this, $args, $additional );
254
255 return $this->type;
256 }
257
258 /**
259 * Checks for the render type class to use for rendering the field.
260 *
261 * @since 2.2.4
262 * @param string $fieldtype The type of field being rendered.
263 * @param string $render_class_name The default field type class to use. Defaults to null.
264 * @return string The field type class to use.
265 */
266 public function get_render_type_class( $fieldtype, $render_class_name = null ) {
267 $render_class_name = $this->field->args( 'render_class' ) ? $this->field->args( 'render_class' ) : $render_class_name;
268
269 if ( has_action( "cmb2_render_class_{$fieldtype}" ) ) {
270
271 /**
272 * Filters the custom field type class used for rendering the field. Class is required to extend CMB2_Type_Base.
273 *
274 * The dynamic portion of the hook name, $fieldtype, refers to the (custom) field type.
275 *
276 * @since 2.2.4
277 *
278 * @param string $render_class_name The custom field type class to use. Default null.
279 * @param object $field_type_object This `CMB2_Types` object.
280 */
281 $render_class_name = apply_filters( "cmb2_render_class_{$fieldtype}", $render_class_name, $this );
282 }
283
284 return $render_class_name && class_exists( $render_class_name ) ? $render_class_name : false;
285 }
286
287 /**
288 * Retrieve text parameter from field's options array (if it has one), or use fallback text
289 *
290 * @since 2.0.0
291 * @param string $text_key Key in field's options array.
292 * @param string $fallback Fallback text.
293 * @return string
294 */
295 public function _text( $text_key, $fallback = '' ) {
296 return $this->field->get_string( $text_key, $fallback );
297 }
298
299 /**
300 * Determine a file's extension
301 *
302 * @since 1.0.0
303 * @param string $file File url
304 * @return string|false File extension or false
305 */
306 public function get_file_ext( $file ) {
307 return CMB2_Utils::get_file_ext( $file );
308 }
309
310 /**
311 * Get the file name from a url
312 *
313 * @since 2.0.0
314 * @param string $value File url or path
315 * @return string File name
316 */
317 public function get_file_name_from_path( $value ) {
318 return CMB2_Utils::get_file_name_from_path( $value );
319 }
320
321 /**
322 * Combines attributes into a string for a form element
323 *
324 * @since 1.1.0
325 * @param array $attrs Attributes to concatenate
326 * @param array $attr_exclude Attributes that should NOT be concatenated
327 * @return string String of attributes for form element
328 */
329 public function concat_attrs( $attrs, $attr_exclude = array() ) {
330 return CMB2_Utils::concat_attrs( $attrs, $attr_exclude );
331 }
332
333 /**
334 * Generates repeatable field table markup
335 *
336 * @since 1.0.0
337 */
338 public function render_repeatable_field() {
339 $table_id = $this->field->id() . '_repeat';
340
341 $this->_desc( true, true, true );
342 ?>
343
344 <div id="<?php echo $table_id; ?>" class="cmb-repeat-table cmb-nested">
345 <div class="cmb-tbody cmb-field-list">
346 <?php $this->repeatable_rows(); ?>
347 </div>
348 </div>
349 <p class="cmb-add-row">
350 <button type="button" data-selector="<?php echo $table_id; ?>" class="cmb-add-row-button button-secondary"><?php echo esc_html( $this->_text( 'add_row_text', esc_html__( 'Add Row', 'cmb2' ) ) ); ?></button>
351 </p>
352
353 <?php
354 // reset iterator
355 $this->iterator = 0;
356 }
357
358 /**
359 * Generates repeatable field rows
360 *
361 * @since 1.1.0
362 */
363 public function repeatable_rows() {
364 $meta_value = array_filter( (array) $this->field->escaped_value() );
365 // check for default content
366 $default = $this->field->get_default();
367
368 // check for saved data
369 if ( ! empty( $meta_value ) ) {
370 $meta_value = is_array( $meta_value ) ? array_filter( $meta_value ) : $meta_value;
371 $meta_value = ! empty( $meta_value ) ? $meta_value : $default;
372 } else {
373 $meta_value = $default;
374 }
375
376 // Loop value array and add a row
377 if ( ! empty( $meta_value ) ) {
378 $count = count( $meta_value );
379 foreach ( (array) $meta_value as $val ) {
380 $this->field->escaped_value = $val;
381 $this->repeat_row();
382 $this->iterator++;
383 }
384 } else {
385
386 // If value is empty (including empty array), then clear the value.
387 $this->field->escaped_value = $this->field->value = null;
388
389 // Otherwise add one row
390 $this->repeat_row();
391 }
392
393 // Then add an empty row
394 $this->field->escaped_value = $default;
395 $this->iterator = $this->iterator ? $this->iterator : 1;
396 $this->repeat_row( 'empty-row hidden' );
397 }
398
399 /**
400 * Generates a repeatable row's markup
401 *
402 * @since 1.1.0
403 * @param string $class Repeatable table row's class
404 */
405 protected function repeat_row( $class = 'cmb-repeat-row' ) {
406 ?>
407
408 <div class="cmb-row <?php echo $class; ?>">
409 <div class="cmb-td">
410 <?php $this->_render(); ?>
411 </div>
412 <div class="cmb-td cmb-remove-row">
413 <button type="button" class="button-secondary cmb-remove-row-button" title="<?php echo esc_attr( $this->_text( 'remove_row_button_title', esc_html__( 'Remove Row', 'cmb2' ) ) ); ?>"><?php echo esc_html( $this->_text( 'remove_row_text', esc_html__( 'Remove', 'cmb2' ) ) ); ?></button>
414 </div>
415 </div>
416
417 <?php
418 }
419
420 /**
421 * Generates description markup.
422 *
423 * @since 1.0.0
424 * @param bool $paragraph Paragraph tag or span.
425 * @param bool $echo Whether to echo description or only return it.
426 * @param bool $repeat_group Whether to repeat the group.
427 * @return string Field's description markup.
428 */
429 public function _desc( $paragraph = false, $echo = false, $repeat_group = false ) {
430 // Prevent description from printing multiple times for repeatable fields
431 if ( ! $repeat_group && ( $this->field->args( 'repeatable' ) || $this->iterator > 0 ) ) {
432 return '';
433 }
434
435 $desc = $this->field->args( 'description' );
436
437 if ( ! $desc ) {
438 return;
439 }
440
441 $tag = $paragraph ? 'p' : 'span';
442 $desc = sprintf( "\n" . '<%1$s class="cmb2-metabox-description">%2$s</%1$s>' . "\n", $tag, $desc );
443
444 if ( $echo ) {
445 echo $desc;
446 }
447
448 return $desc;
449 }
450
451 /**
452 * Generate field name attribute
453 *
454 * @since 1.1.0
455 * @param string $suffix For multi-part fields
456 * @return string Name attribute
457 */
458 public function _name( $suffix = '' ) {
459 return $this->field->args( '_name' ) . ( $this->field->args( 'repeatable' ) ? '[' . $this->iterator . ']' : '' ) . $suffix;
460 }
461
462 /**
463 * Generate field id attribute
464 *
465 * @since 1.1.0
466 * @param string $suffix For multi-part fields
467 * @return string Id attribute
468 */
469 public function _id( $suffix = '' ) {
470 return $this->field->id() . $suffix . ( $this->field->args( 'repeatable' ) ? '_' . $this->iterator . '" data-iterator="' . $this->iterator : '' );
471 }
472
473 /**
474 * Handles outputting an 'input' element
475 *
476 * @since 1.1.0
477 * @param array $args Override arguments
478 * @param string $type Field type
479 * @return string Form input element
480 */
481 public function input( $args = array(), $type = __FUNCTION__ ) {
482 return $this->get_new_render_type( 'text', 'CMB2_Type_Text', $args, $type )->render();
483 }
484
485 /**
486 * Handles outputting an 'textarea' element
487 *
488 * @since 1.1.0
489 * @param array $args Override arguments
490 * @return string Form textarea element
491 */
492 public function textarea( $args = array() ) {
493 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Textarea', $args )->render();
494 }
495
496 /**
497 * Begin Field Types
498 */
499
500 public function text() {
501 return $this->input();
502 }
503
504 public function hidden() {
505 $args = array(
506 'type' => 'hidden',
507 'desc' => '',
508 'class' => 'cmb2-hidden',
509 );
510 if ( $this->field->group ) {
511 $args['data-groupid'] = $this->field->group->id();
512 $args['data-iterator'] = $this->iterator;
513 }
514
515 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text', $args, 'input' )->render();
516 }
517
518 public function text_small() {
519 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text', array(
520 'class' => 'cmb2-text-small',
521 'desc' => $this->_desc(),
522 ), 'input' )->render();
523 }
524
525 public function text_medium() {
526 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text', array(
527 'class' => 'cmb2-text-medium',
528 'desc' => $this->_desc(),
529 ), 'input' )->render();
530 }
531
532 public function text_email() {
533 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text', array(
534 'class' => 'cmb2-text-email cmb2-text-medium',
535 'type' => 'email',
536 ), 'input' )->render();
537 }
538
539 public function text_url() {
540 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text', array(
541 'class' => 'cmb2-text-url cmb2-text-medium regular-text',
542 'value' => $this->field->escaped_value( 'esc_url' ),
543 ), 'input' )->render();
544 }
545
546 public function text_money() {
547 $input = $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text', array(
548 'class' => 'cmb2-text-money',
549 'desc' => $this->_desc(),
550 ), 'input' )->render();
551 return ( ! $this->field->get_param_callback_result( 'before_field' ) ? '$ ' : ' ' ) . $input;
552 }
553
554 public function textarea_small() {
555 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Textarea', array(
556 'class' => 'cmb2-textarea-small',
557 'rows' => 4,
558 ) )->render();
559 }
560
561 public function textarea_code( $args = array() ) {
562 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Textarea_Code', $args )->render();
563 }
564
565 public function wysiwyg( $args = array() ) {
566 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Wysiwyg', $args )->render();
567 }
568
569 public function text_date( $args = array() ) {
570 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text_Date', $args )->render();
571 }
572
573 // Alias for text_date
574 public function text_date_timestamp( $args = array() ) {
575 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text_Date', $args )->render();
576 }
577
578 public function text_time( $args = array() ) {
579 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text_Time', $args )->render();
580 }
581
582 public function text_datetime_timestamp( $args = array() ) {
583 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text_Datetime_Timestamp', $args )->render();
584 }
585
586 public function text_datetime_timestamp_timezone( $args = array() ) {
587 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Text_Datetime_Timestamp_Timezone', $args )->render();
588 }
589
590 public function select_timezone( $args = array() ) {
591 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Select_Timezone', $args )->render();
592 }
593
594 public function colorpicker( $args = array(), $meta_value = '' ) {
595 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Colorpicker', $args, $meta_value )->render();
596 }
597
598 public function title( $args = array() ) {
599 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Title', $args )->render();
600 }
601
602 public function select( $args = array() ) {
603 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Select', $args )->render();
604 }
605
606 public function taxonomy_select( $args = array() ) {
607 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Taxonomy_Select', $args )->render();
608 }
609
610 public function radio( $args = array(), $type = __FUNCTION__ ) {
611 return $this->get_new_render_type( $type, 'CMB2_Type_Radio', $args, $type )->render();
612 }
613
614 public function radio_inline( $args = array() ) {
615 return $this->radio( $args, __FUNCTION__ );
616 }
617
618 public function multicheck( $type = 'checkbox' ) {
619 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Multicheck', array(), $type )->render();
620 }
621
622 public function multicheck_inline() {
623 return $this->multicheck( 'multicheck_inline' );
624 }
625
626 public function checkbox( $args = array(), $is_checked = null ) {
627 // Avoid get_new_render_type since we need a different default for the 3rd argument than ''.
628 $render_class_name = $this->get_render_type_class( __FUNCTION__, 'CMB2_Type_Checkbox' );
629 $this->type = new $render_class_name( $this, $args, $is_checked );
630 return $this->type->render();
631 }
632
633 public function taxonomy_radio( $args = array() ) {
634 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Taxonomy_Radio', $args )->render();
635 }
636
637 public function taxonomy_radio_hierarchical( $args = array() ) {
638 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Taxonomy_Radio_Hierarchical', $args )->render();
639 }
640
641 public function taxonomy_radio_inline( $args = array() ) {
642 return $this->taxonomy_radio( $args );
643 }
644
645 public function taxonomy_multicheck( $args = array() ) {
646 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Taxonomy_Multicheck', $args )->render();
647 }
648
649 public function taxonomy_multicheck_hierarchical( $args = array() ) {
650 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Taxonomy_Multicheck_Hierarchical', $args )->render();
651 }
652
653 public function taxonomy_multicheck_inline( $args = array() ) {
654 return $this->taxonomy_multicheck( $args );
655 }
656
657 public function oembed( $args = array() ) {
658 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_Oembed', $args )->render();
659 }
660
661 public function file_list( $args = array() ) {
662 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_File_List', $args )->render();
663 }
664
665 public function file( $args = array() ) {
666 return $this->get_new_render_type( __FUNCTION__, 'CMB2_Type_File', $args )->render();
667 }
668
669 }
670