may show per-row Save UI (save_ui: always|when_changed)
* - scope=form -> saved only via "Save Form" (settings_json: {"options":{key:value}})
* - scope=ui -> UI-only (no DB save)
*
* Args shape:
* array(
* 'type' => 'toggle'|'select'|'radio'|'length'|'spacing'|'range'|'color'|'input'|'textarea',
* 'key' => 'booking_timeslot_picker',
* 'scope' => 'global'|'form'|'ui',
* 'save_ui' => 'always'|'when_changed', // only for scope=global
* 'default' => 'On', // initial value for control
* 'label' => __( '...', 'booking' ),
* 'help' => __( '...', 'booking' ),
* 'attr' => array( 'id' => '...', 'class' => '...' ),
*
* // select/radio
* 'options' => array( 'value' => 'Label', ... ),
* 'radio_layout' => 'inline'|'stack',
*
* // input
* 'input_type' => 'text'|'number'|...,
* 'input_attrs' => array( 'placeholder' => '...', ... ),
*
* // length
* 'length' => array(
* 'default_unit' => '%',
* 'units' => array( '%' => '%', 'px' => 'px', ... ),
* 'bounds_map' => array( '%' => array('min'=>30,'max'=>100,'step'=>1), ... ), // optional
* ),
*
* // range (slider number)
* 'range' => array(
* 'min' => 0,
* 'max' => 100,
* 'step' => 1,
* ),
* )
*
* @package Booking Calendar
* @since 11.0.x
* @file ../includes/page-form-builder/form-settings/options-render.php
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class WPBC_BFB_Setting_Options {
/**
* Print one option row.
*
* @param array $args
*/
public static function print_option( $args ) {
if ( ! is_array( $args ) ) {
return;
}
$type = isset( $args['type'] ) ? (string) $args['type'] : 'input';
$key = isset( $args['key'] ) ? (string) $args['key'] : '';
$scope = isset( $args['scope'] ) ? (string) $args['scope'] : 'ui';
$save_ui = isset( $args['save_ui'] ) ? (string) $args['save_ui'] : 'when_changed';
if ( '' === $key ) {
return;
}
$label = isset( $args['label'] ) ? (string) $args['label'] : '';
$help = isset( $args['help'] ) ? (string) $args['help'] : '';
$attr = ( isset( $args['attr'] ) && is_array( $args['attr'] ) ) ? $args['attr'] : array();
$id = isset( $attr['id'] ) ? (string) $attr['id'] : 'wpbc_bfb_setting__' . sanitize_html_class( $key );
$default_value = isset( $args['default'] ) ? $args['default'] : '';
// Wrapper classes.
$row_class = 'wpbc_bfb__form_setting wpbc-setting';
if ( ! empty( $args['row_class'] ) && is_scalar( $args['row_class'] ) ) {
$row_extra_classes = preg_split( '/\s+/', trim( (string) $args['row_class'] ) );
foreach ( $row_extra_classes as $row_extra_class ) {
$row_extra_class = sanitize_html_class( $row_extra_class );
if ( '' !== $row_extra_class ) {
$row_class .= ' ' . $row_extra_class;
}
}
}
$row_attr = ( isset( $args['row_attr'] ) && is_array( $args['row_attr'] ) ) ? $args['row_attr'] : array();
if ( ! empty( $args['row_hidden'] ) ) {
$row_attr['hidden'] = 'hidden';
$row_attr['aria-hidden'] = 'true';
}
$row_attr_str = self::build_attr_string( $row_attr );
?>
/>
$key,
'data-wpbc-bfb-fs-scope' => $scope,
'data-wpbc-bfb-fs-type' => 'radio',
'data-wpbc-bfb-fs-initial' => $v,
'data-wpbc-bfb-fs-controlid' => $id,
);
$wrap_attr_str = self::build_attr_string( $wrap_attr );
?>
...
*
*/
private static function print_range( $id, $key, $scope, $label, $value, $range, $attr, $css_class ) {
$min = isset( $range['min'] ) ? (float) $range['min'] : 0;
$max = isset( $range['max'] ) ? (float) $range['max'] : 100;
$step = isset( $range['step'] ) ? (float) $range['step'] : 1;
$v = is_scalar( $value ) ? (string) $value : '';
if ( '' === trim( $v ) ) {
$v = (string) $min;
}
// Clamp numeric value.
if ( is_numeric( $v ) ) {
$n = (float) $v;
if ( $n < $min ) { $n = $min; }
if ( $n > $max ) { $n = $max; }
// Keep formatting simple.
$v = (string) $n;
}
// Number input = writer (id stays here, Save UI reads #id).
// Keep FS type as "input" for compatibility with existing apply/collect code.
$num_attr = self::with_common_fs_data( $attr, $key, $scope, 'input', $v );
$num_attr['data-wpbc-bfb-fs-type'] = 'input';
$num_attr['data-wpbc_slider_range_value'] = '1';
$num_attr['data-wpbc_slider_range_writer'] = '1';
// Ensure the number input keeps the $id.
$num_attr['id'] = $id;
$num_attr_str = self::build_attr_string( $num_attr );
// Number input CSS (adds width helper).
$num_class = trim( $css_class . ' inspector__w_30' );
?>
'%' );
$default_unit = isset( $length['default_unit'] ) ? (string) $length['default_unit'] : '%';
$bounds_map = ( isset( $length['bounds_map'] ) && is_array( $length['bounds_map'] ) ) ? $length['bounds_map'] : array();
$raw = is_scalar( $value ) ? trim( (string) $value ) : '';
$num = '';
$unit = '';
if ( preg_match( '/^\s*([\-]?\d+(?:\.\d+)?)\s*([a-z%]*)\s*$/i', $raw, $m ) ) {
$num = isset( $m[1] ) ? (string) $m[1] : '';
$unit = isset( $m[2] ) ? (string) $m[2] : '';
}
if ( '' === $unit ) {
$unit = $default_unit;
}
if ( '' === $num && '' !== $raw ) {
$num = $raw;
}
// Ensure unit exists in list.
if ( ! isset( $units[ $unit ] ) ) {
$unit = $default_unit;
}
// Bounds for current unit.
$bounds = array();
if ( isset( $bounds_map[ $unit ] ) && is_array( $bounds_map[ $unit ] ) ) {
$bounds = $bounds_map[ $unit ];
} elseif ( isset( $bounds_map[ $default_unit ] ) && is_array( $bounds_map[ $default_unit ] ) ) {
$bounds = $bounds_map[ $default_unit ];
}
$min = isset( $bounds['min'] ) ? (float) $bounds['min'] : 0;
$max = isset( $bounds['max'] ) ? (float) $bounds['max'] : 128;
$step = isset( $bounds['step'] ) ? (float) $bounds['step'] : 1;
// Clamp numeric value to bounds when it is numeric.
if ( '' !== $num && is_numeric( $num ) ) {
$n = (float) $num;
if ( $n < $min ) {
$n = $min;
}
if ( $n > $max ) {
$n = $max;
}
$num = (string) $n;
}
$combined = ( '' === $num ) ? '' : ( $num . $unit );
// Writer input (main value) must have the FS markers + special type="length".
// Add the new strict writer marker for wpbc_slider_len_groups.js
$writer_attr = self::with_common_fs_data( array( 'id' => $id ), $key, $scope, 'length', $combined );
$writer_attr['data-wpbc-bfb-fs-type'] = 'length';
$writer_attr['data-wpbc_slider_len_writer'] = '1';
$writer_attr_str = self::build_attr_string( $writer_attr );
// Bounds JSON for JS.
$bounds_json = ( ! empty( $bounds_map ) ) ? wp_json_encode( $bounds_map ) : '';
?>
$id ), $key, $scope, 'spacing', $combined );
$writer_attr['data-wpbc-bfb-fs-type'] = 'spacing';
$writer_attr['data-wpbc_spacing_writer'] = '1';
$common_input_attr = array(
'data-wpbc-bfb-fs-key' => $key,
'data-wpbc-bfb-fs-scope' => $scope,
'data-wpbc-bfb-fs-type' => 'spacing',
);
?>
$v ) {
if ( ! is_scalar( $k ) || '' === trim( (string) $k ) ) {
continue;
}
$attr_key = strtolower( trim( (string) $k ) );
// Block inline handlers.
if ( 0 === strpos( $attr_key, 'on' ) ) {
continue;
}
if ( null === $v ) {
continue;
}
$out .= ' ' . esc_attr( $attr_key ) . '="' . esc_attr( (string) $v ) . '"';
}
return $out;
}
}