PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 All 204 releases
← All changes | includes/page-form-builder/form-settings/options-render.php +227 -81 11.211.8.4 View file →
@@ -1,4 +1,4 @@
1 1 <?php
2 2 /**
3 3 * BFB Settings Options: Simple option row printer.
4 4 *
@@ -8,9 +8,9 @@
8 8 * - scope=ui -> UI-only (no DB save)
9 9 *
10 10 * Args shape:
11 11 * array(
12 - * 'type' => 'toggle'|'select'|'radio'|'length'|'range'|'input'|'textarea',
12 + * 'type' => 'toggle'|'select'|'radio'|'length'|'spacing'|'range'|'color'|'input'|'textarea',
13 13 * 'key' => 'booking_timeslot_picker',
14 14 * 'scope' => 'global'|'form'|'ui',
15 15 * 'save_ui' => 'always'|'when_changed', // only for scope=global
16 16 * 'default' => 'On', // initial value for control
@@ -79,15 +79,32 @@
79 79 $id = isset( $attr['id'] ) ? (string) $attr['id'] : 'wpbc_bfb_setting__' . sanitize_html_class( $key );
80 80
81 81 $default_value = isset( $args['default'] ) ? $args['default'] : '';
82 82
83 - // Wrapper classes.
84 - $row_class = 'wpbc_bfb__form_setting wpbc-setting';
85 - ?>
86 - <div class="<?php echo esc_attr( $row_class ); ?>"
87 - data-scope="<?php echo esc_attr( $scope ); ?>"
88 - data-key="<?php echo esc_attr( $key ); ?>"
89 - data-type="<?php echo esc_attr( $type ); ?>">
83 + // Wrapper classes.
84 + $row_class = 'wpbc_bfb__form_setting wpbc-setting';
85 + if ( ! empty( $args['row_class'] ) && is_scalar( $args['row_class'] ) ) {
86 + $row_extra_classes = preg_split( '/\s+/', trim( (string) $args['row_class'] ) );
87 + foreach ( $row_extra_classes as $row_extra_class ) {
88 + $row_extra_class = sanitize_html_class( $row_extra_class );
89 + if ( '' !== $row_extra_class ) {
90 + $row_class .= ' ' . $row_extra_class;
91 + }
92 + }
93 + }
94 +
95 + $row_attr = ( isset( $args['row_attr'] ) && is_array( $args['row_attr'] ) ) ? $args['row_attr'] : array();
96 + if ( ! empty( $args['row_hidden'] ) ) {
97 + $row_attr['hidden'] = 'hidden';
98 + $row_attr['aria-hidden'] = 'true';
99 + }
100 + $row_attr_str = self::build_attr_string( $row_attr );
101 + ?>
102 + <div class="<?php echo esc_attr( $row_class ); ?>"
103 + data-scope="<?php echo esc_attr( $scope ); ?>"
104 + data-key="<?php echo esc_attr( $key ); ?>"
105 + data-type="<?php echo esc_attr( $type ); ?>"
106 + <?php echo $row_attr_str; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
90 107 <div class="inspector__row" style="justify-content:space-between;">
91 108 <div class="inspector__control" style="flex:1 1 auto;">
92 109
93 110 <?php self::print_control( $args, $id, $key, $scope, $type, $default_value ); ?>
@@ -153,27 +170,42 @@
153 170
154 171 // Radio.
155 172 if ( 'radio' === $type ) {
156 173 $options = ( isset( $args['options'] ) && is_array( $args['options'] ) ) ? $args['options'] : array();
157 - $radio_layout = ( isset( $args['radio_layout'] ) && 'inline' === $args['radio_layout'] ) ? 'inline' : 'stack';
158 - self::print_radio( $id, $key, $scope, $label, $value, $options, $radio_layout );
159 - return;
160 - }
174 + $radio_layout = isset( $args['radio_layout'] ) ? (string) $args['radio_layout'] : 'stack';
175 + $radio_layout = in_array( $radio_layout, array( 'inline', 'choice_grid' ), true ) ? $radio_layout : 'stack';
176 + self::print_radio( $id, $key, $scope, $label, $value, $options, $radio_layout );
177 + return;
178 + }
161 179
162 - // Length.
163 - if ( 'length' === $type ) {
164 - $length = ( isset( $args['length'] ) && is_array( $args['length'] ) ) ? $args['length'] : array();
165 - self::print_length( $id, $key, $scope, $label, $value, $length );
166 - return;
167 - }
180 + // Length.
181 + if ( 'length' === $type ) {
182 + $length = ( isset( $args['length'] ) && is_array( $args['length'] ) ) ? $args['length'] : array();
183 + self::print_length( $id, $key, $scope, $label, $value, $length );
184 + return;
185 + }
186 +
187 + // Spacing: two px number controls saved as CSS shorthand, e.g. "10px 30px".
188 + if ( 'spacing' === $type ) {
189 + $spacing = ( isset( $args['spacing'] ) && is_array( $args['spacing'] ) ) ? $args['spacing'] : array();
190 + self::print_spacing( $id, $key, $scope, $label, $value, $spacing );
191 + return;
192 + }
193 +
194 + // Range (slider number).
195 + if ( 'range' === $type ) {
196 + $range = ( isset( $args['range'] ) && is_array( $args['range'] ) ) ? $args['range'] : array();
197 + self::print_range( $id, $key, $scope, $label, $value, $range, $attr, $css_class );
198 + return;
199 + }
200 +
201 + // Color picker (Coloris).
202 + if ( 'color' === $type ) {
203 + $input_attrs = ( isset( $args['input_attrs'] ) && is_array( $args['input_attrs'] ) ) ? $args['input_attrs'] : array();
204 + self::print_color( $id, $key, $scope, $label, $value, $attr, $css_class, $input_attrs );
205 + return;
206 + }
168 207
169 - // Range (slider number).
170 - if ( 'range' === $type ) {
171 - $range = ( isset( $args['range'] ) && is_array( $args['range'] ) ) ? $args['range'] : array();
172 - self::print_range( $id, $key, $scope, $label, $value, $range, $attr, $css_class );
173 - return;
174 - }
175 -
176 208 // Textarea.
177 209 if ( 'textarea' === $type ) {
178 210 $input_attrs = ( isset( $args['input_attrs'] ) && is_array( $args['input_attrs'] ) ) ? $args['input_attrs'] : array();
179 211 self::print_textarea( $id, $key, $scope, $label, $value, $attr, $css_class, $input_attrs );
@@ -236,14 +268,20 @@
236 268 private static function print_radio( $id, $key, $scope, $label, $value, $options, $radio_layout ) {
237 269
238 270 $v = is_scalar( $value ) ? (string) $value : '';
239 271
240 - $wrapper_style = ( 'inline' === $radio_layout )
241 - ? 'display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin:0;'
242 - : 'margin:0;';
243 - $item_style = ( 'inline' === $radio_layout )
244 - ? ''
245 - : 'display:flex;align-items:center;gap:8px;margin:4px 0;';
272 + $is_choice_grid = ( 'choice_grid' === $radio_layout );
273 + $wrapper_class = $is_choice_grid ? 'wpbc_theme_choice_grid wpbc_bfb_style_choice_grid' : '';
274 + $wrapper_style = ( 'inline' === $radio_layout )
275 + ? 'display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin:0;'
276 + : 'margin:0;';
277 + $item_style = ( 'inline' === $radio_layout )
278 + ? ''
279 + : 'display:flex;align-items:center;gap:8px;margin:4px 0;';
280 + if ( $is_choice_grid ) {
281 + $wrapper_style = '';
282 + $item_style = '';
283 + }
246 284
247 285 // Put fs data on wrapper (JS reads control id from wrapper).
248 286 $wrap_attr = array(
249 287 'data-wpbc-bfb-fs-key' => $key,
@@ -257,27 +295,36 @@
257 295 <div class="wpbc_bfb__form_setting_radio"
258 296 <?php echo $wrap_attr_str; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
259 297 <div style="margin:0 0 6px 0;"><strong><?php echo esc_html( $label ); ?></strong></div>
260 298
261 - <div style="<?php echo esc_attr( $wrapper_style ); ?>">
262 - <?php
263 - $i = 0;
264 - foreach ( $options as $opt_value => $opt_label ) :
265 - $i++;
266 - $rid = $id . '__' . $i;
267 - ?>
268 - <label style="<?php echo esc_attr( $item_style ); ?>">
269 - <input type="radio"
270 - name="<?php echo esc_attr( $id ); ?>"
271 - id="<?php echo esc_attr( $rid ); ?>"
272 - value="<?php echo esc_attr( (string) $opt_value ); ?>"
273 - data-wpbc-bfb-fs-radio="1"
274 - <?php checked( (string) $opt_value, $v ); ?>
275 - />
276 - <?php echo esc_html( (string) $opt_label ); ?>
277 - </label>
278 - <?php endforeach; ?>
279 - </div>
299 + <div class="<?php echo esc_attr( $wrapper_class ); ?>" style="<?php echo esc_attr( $wrapper_style ); ?>">
300 + <?php
301 + $i = 0;
302 + foreach ( $options as $opt_value => $opt_label ) :
303 + $i++;
304 + $rid = $id . '__' . $i;
305 + $item_class = $is_choice_grid ? 'wpbc_theme_choice' : '';
306 + if ( $is_choice_grid && (string) $opt_value === $v ) {
307 + $item_class .= ' is-selected';
308 + }
309 + ?>
310 + <label class="<?php echo esc_attr( $item_class ); ?>" style="<?php echo esc_attr( $item_style ); ?>">
311 + <input type="radio"
312 + name="<?php echo esc_attr( $id ); ?>"
313 + id="<?php echo esc_attr( $rid ); ?>"
314 + value="<?php echo esc_attr( (string) $opt_value ); ?>"
315 + data-wpbc-bfb-fs-radio="1"
316 + <?php checked( (string) $opt_value, $v ); ?>
317 + />
318 + <?php if ( $is_choice_grid ) : ?>
319 + <span class="wpbc_theme_choice_swatch wpbc_theme_choice_swatch_<?php echo esc_attr( sanitize_html_class( (string) $opt_value ) ); ?>"></span>
320 + <span class="wpbc_theme_choice_label"><?php echo esc_html( (string) $opt_label ); ?></span>
321 + <?php else : ?>
322 + <?php echo esc_html( (string) $opt_label ); ?>
323 + <?php endif; ?>
324 + </label>
325 + <?php endforeach; ?>
326 + </div>
280 327 </div>
281 328 <?php
282 329 }
283 330
@@ -360,9 +407,9 @@
360 407 </div>
361 408 <?php
362 409 }
363 410
364 - private static function print_length( $id, $key, $scope, $label, $value, $length ) {
411 + private static function print_length( $id, $key, $scope, $label, $value, $length ) {
365 412
366 413 $units = ( isset( $length['units'] ) && is_array( $length['units'] ) ) ? $length['units'] : array( '%' => '%' );
367 414 $default_unit = isset( $length['default_unit'] ) ? (string) $length['default_unit'] : '%';
368 415 $bounds_map = ( isset( $length['bounds_map'] ) && is_array( $length['bounds_map'] ) ) ? $length['bounds_map'] : array();
@@ -474,12 +521,87 @@
474 521 />
475 522 </div>
476 523 </div>
477 524 <?php
478 - }
525 + }
526 +
527 + private static function print_spacing( $id, $key, $scope, $label, $value, $spacing ) {
528 +
529 + $min = isset( $spacing['min'] ) ? (float) $spacing['min'] : 0;
530 + $max = isset( $spacing['max'] ) ? (float) $spacing['max'] : 120;
531 + $step = isset( $spacing['step'] ) ? (float) $spacing['step'] : 1;
532 +
533 + $raw = is_scalar( $value ) ? trim( (string) $value ) : '';
534 + if ( '' === $raw ) {
535 + $raw = '10px 30px';
536 + }
537 +
538 + preg_match_all( '/-?\d+(?:\.\d+)?/', $raw, $matches );
539 + $numbers = isset( $matches[0] ) ? $matches[0] : array();
540 + $vertical = isset( $numbers[0] ) ? (float) $numbers[0] : 10;
541 + $horizontal = isset( $numbers[1] ) ? (float) $numbers[1] : $vertical;
542 +
543 + $vertical = max( $min, min( $max, $vertical ) );
544 + $horizontal = max( $min, min( $max, $horizontal ) );
545 +
546 + $vertical_value = (string) ( $vertical + 0 );
547 + $horizontal_value = (string) ( $horizontal + 0 );
548 + $combined = $vertical_value . 'px ' . $horizontal_value . 'px';
549 +
550 + $writer_attr = self::with_common_fs_data( array( 'id' => $id ), $key, $scope, 'spacing', $combined );
551 + $writer_attr['data-wpbc-bfb-fs-type'] = 'spacing';
552 + $writer_attr['data-wpbc_spacing_writer'] = '1';
553 +
554 + $common_input_attr = array(
555 + 'data-wpbc-bfb-fs-key' => $key,
556 + 'data-wpbc-bfb-fs-scope' => $scope,
557 + 'data-wpbc-bfb-fs-type' => 'spacing',
558 + );
559 +
560 + ?>
561 + <label class="inspector__label"><strong><?php echo esc_html( $label ); ?></strong></label>
562 +
563 + <div class="inspector__control">
564 + <div class="wpbc_spacing_group wpbc_inline_inputs inspector__w_100">
565 + <label style="display:flex;flex-direction:column;gap:4px;flex:1 1 90px;">
566 + <span class="wpbc_bfb__help" style="margin:0;"><?php esc_html_e( 'Top / bottom', 'booking' ); ?></span>
567 + <input type="number"
568 + class="inspector__input"
569 + data-wpbc_spacing_vertical="1"
570 + autocomplete="off"
571 + min="<?php echo esc_attr( (string) $min ); ?>"
572 + max="<?php echo esc_attr( (string) $max ); ?>"
573 + step="<?php echo esc_attr( (string) $step ); ?>"
574 + value="<?php echo esc_attr( $vertical_value ); ?>"
575 + <?php echo self::build_attr_string( $common_input_attr ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
576 + />
577 + </label>
578 + <label style="display:flex;flex-direction:column;gap:4px;flex:1 1 90px;">
579 + <span class="wpbc_bfb__help" style="margin:0;"><?php esc_html_e( 'Left / right', 'booking' ); ?></span>
580 + <input type="number"
581 + class="inspector__input"
582 + data-wpbc_spacing_horizontal="1"
583 + autocomplete="off"
584 + min="<?php echo esc_attr( (string) $min ); ?>"
585 + max="<?php echo esc_attr( (string) $max ); ?>"
586 + step="<?php echo esc_attr( (string) $step ); ?>"
587 + value="<?php echo esc_attr( $horizontal_value ); ?>"
588 + <?php echo self::build_attr_string( $common_input_attr ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
589 + />
590 + </label>
591 + <input type="text"
592 + class="inspector__input"
593 + style="display:none;"
594 + value="<?php echo esc_attr( $combined ); ?>"
595 + <?php echo self::build_attr_string( $writer_attr ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
596 + />
597 + </div>
598 + </div>
599 + <?php
600 + }
601 +
602 + private static function print_input( $id, $key, $scope, $label, $value, $attr, $css_class, $input_type, $input_attrs ) {
479 603
480 - private static function print_input( $id, $key, $scope, $label, $value, $attr, $css_class, $input_type, $input_attrs ) {
481 -
482 604 $v = is_scalar( $value ) ? (string) $value : '';
483 605
484 606 $control_attr = self::with_common_fs_data( $attr, $key, $scope, 'input', $v );
485 607 $control_attr['data-wpbc-bfb-fs-type'] = 'input';
@@ -496,12 +618,39 @@
496 618 <?php echo $extra_attr_str; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
497 619 />
498 620 </label>
499 621 <?php
500 - }
622 + }
623 +
624 + private static function print_color( $id, $key, $scope, $label, $value, $attr, $css_class, $input_attrs ) {
625 +
626 + $v = is_scalar( $value ) ? (string) $value : '';
627 +
628 + $control_attr = self::with_common_fs_data( $attr, $key, $scope, 'color', $v );
629 + $control_attr['data-wpbc-bfb-fs-type'] = 'color';
630 + $control_attr['data-inspector-type'] = 'color';
631 + $control_attr['data-coloris'] = '';
632 + $control_attr['data-default-color'] = $v;
633 + $control_attr['autocomplete'] = 'off';
634 + $control_attr['placeholder'] = '#ffffff';
635 +
636 + $attr_str = self::build_attr_string( $control_attr );
637 + $extra_attr_str = self::build_attr_string( $input_attrs );
638 + ?>
639 + <label style="display:block;">
640 + <div style="margin:0 0 6px 0;"><strong><?php echo esc_html( $label ); ?></strong></div>
641 + <input type="text"
642 + class="<?php echo esc_attr( $css_class ); ?>"
643 + value="<?php echo esc_attr( $v ); ?>"
644 + <?php echo $attr_str; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
645 + <?php echo $extra_attr_str; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
646 + />
647 + </label>
648 + <?php
649 + }
650 +
651 + private static function print_textarea( $id, $key, $scope, $label, $value, $attr, $css_class, $input_attrs ) {
501 652
502 - private static function print_textarea( $id, $key, $scope, $label, $value, $attr, $css_class, $input_attrs ) {
503 -
504 653 $v = is_scalar( $value ) ? (string) $value : '';
505 654
506 655 $control_attr = self::with_common_fs_data( $attr, $key, $scope, 'textarea', $v );
507 656 $control_attr['data-wpbc-bfb-fs-type'] = 'textarea';
@@ -542,35 +691,32 @@
542 691 } else {
543 692 $value_from = '#' . $id;
544 693 }
545 694
546 - // Stable saver requires nonce + action.
547 - $opt_name = $key; // option name == key
548 - $nonce_action = 'wpbc_nonce_' . $opt_name;
549 - $nonce_value = wp_create_nonce( $nonce_action );
695 + $opt_name = $key; // Option name equals the registered policy name.
550 696
551 - $wrap_class = 'wpbc_bfb__form_setting_save';
552 - $btn_class = 'button button-primary wpbc_bfb__form_setting_save_btn';
697 + $wrap_class = 'wpbc_bfb__form_setting_save';
698 + $btn_class = 'button button-primary wpbc_bfb__form_setting_save_btn';
699 +
700 + if ( 'when_changed' === $save_ui ) {
701 + $wrap_class .= ' is-hidden';
702 + }
703 + $autosave_attr = ! empty( $args['autosave_on_form_save'] ) ? ' data-wpbc-u-autosave-on-form-save="1"' : '';
704 + ?>
705 + <div class="<?php echo esc_attr( $wrap_class ); ?>">
706 + <button type="button"
707 + class="<?php echo esc_attr( $btn_class ); ?>"
553 708
554 - if ( 'when_changed' === $save_ui ) {
555 - $wrap_class .= ' is-hidden';
556 - }
557 - ?>
558 - <div class="<?php echo esc_attr( $wrap_class ); ?>">
559 - <button type="button"
560 - class="<?php echo esc_attr( $btn_class ); ?>"
709 + data-wpbc-u-save="1"
710 + data-wpbc-u-save-name="<?php echo esc_attr( $opt_name ); ?>"
711 + data-wpbc-u-busy-text="<?php echo esc_attr__( 'Saving…', 'booking' ); ?>"
561 712
562 - data-wpbc-u-save="1"
563 - data-wpbc-u-save-name="<?php echo esc_attr( $opt_name ); ?>"
564 - data-wpbc-u-save-nonce="<?php echo esc_attr( $nonce_value ); ?>"
565 - data-wpbc-u-save-action="<?php echo esc_attr( $nonce_action ); ?>"
566 - data-wpbc-u-busy-text="<?php echo esc_attr__( 'Saving…', 'booking' ); ?>"
567 -
568 - data-wpbc-u-save-ui="<?php echo esc_attr( $save_ui ); ?>"
569 - data-wpbc-u-save-scope="global"
570 - data-wpbc-u-save-value-from="<?php echo esc_attr( $value_from ); ?>"
571 - ><?php echo esc_html__( 'Save', 'booking' ); ?></button>
572 - </div>
713 + data-wpbc-u-save-ui="<?php echo esc_attr( $save_ui ); ?>"
714 + data-wpbc-u-save-scope="global"
715 + data-wpbc-u-save-value-from="<?php echo esc_attr( $value_from ); ?>"
716 + <?php echo $autosave_attr; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
717 + ><?php echo esc_html__( 'Save', 'booking' ); ?></button>
718 + </div>
573 719 <?php
574 720 }
575 721
576 722