'steps', 'services_view' => 'list', 'staff_view' => 'cards', 'card_cols' => 'auto', 'photo_size' => 'm', 'photo_shape' => 'round', 'slots_view' => 'tickets', 'employee_mode' => 'choose', 'step_order' => 'service_first', 'button_style' => 'filled', 'card_style' => 'bordered', 'sidebar_style' => 'tinted', 'date_view' => 'month', 'logo' => '', 'animations' => true, 'popup_label' => '', 'popup_align' => 'left', 'width' => 860, 'text' => '#172026', 'muted' => '#55626c', 'bg' => '#ffffff', 'border' => '#dfe5ea', 'on_primary' => '#ffffff', 'success' => '#15803d', 'error' => '#b42318', 'font_size' => 15, 'heading_weight'=> 800, 'radius' => 12, 'shadow' => 'none', 'card_border' => true, 'time_format' => 'auto', 'show' => array_fill_keys( self::SHOW, true ), 'labels' => array_fill_keys( self::LABELS, '' ), ); } /** Saved design merged over defaults (nested arrays too). */ public static function get() { $d = (array) Settings::get( 'design', array() ); $def = self::defaults(); $out = array_merge( $def, $d ); $out['show'] = array_merge( $def['show'], (array) ( $d['show'] ?? array() ) ); $out['labels'] = array_merge( $def['labels'], (array) ( $d['labels'] ?? array() ) ); return $out; } public static function sanitize( array $in ) { $def = self::defaults(); $pick = function ( $v, array $allowed, $fallback ) { return in_array( $v, $allowed, false ) ? ( is_int( $fallback ) ? (int) $v : (string) $v ) : $fallback; }; $out = array( 'layout' => $pick( $in['layout'] ?? '', self::LAYOUTS, $def['layout'] ), 'services_view' => $pick( $in['services_view'] ?? '', self::SERVICES, $def['services_view'] ), 'staff_view' => $pick( $in['staff_view'] ?? '', self::STAFF, $def['staff_view'] ), 'card_cols' => $pick( (string) ( $in['card_cols'] ?? '' ), self::COLS, $def['card_cols'] ), 'photo_size' => $pick( $in['photo_size'] ?? '', self::PHOTO, $def['photo_size'] ), 'photo_shape' => $pick( $in['photo_shape'] ?? '', self::SHAPES, $def['photo_shape'] ), 'slots_view' => $pick( $in['slots_view'] ?? '', self::SLOTS, $def['slots_view'] ), 'employee_mode' => $pick( $in['employee_mode'] ?? '', self::EMP_MODE, $def['employee_mode'] ), 'step_order' => $pick( $in['step_order'] ?? '', self::ORDER, $def['step_order'] ), 'button_style' => $pick( $in['button_style'] ?? '', self::BUTTONS, $def['button_style'] ), 'card_style' => $pick( $in['card_style'] ?? '', self::CARDS, $def['card_style'] ), 'sidebar_style' => $pick( $in['sidebar_style'] ?? '', self::SIDEBARS, $def['sidebar_style'] ), 'date_view' => $pick( $in['date_view'] ?? '', self::DATES, $def['date_view'] ), 'popup_align' => $pick( $in['popup_align'] ?? '', self::POPUP_AT, $def['popup_align'] ), 'logo' => esc_url_raw( (string) ( $in['logo'] ?? '' ) ), 'animations' => ! isset( $in['animations'] ) || ! empty( $in['animations'] ), 'popup_label' => sanitize_text_field( (string) ( $in['popup_label'] ?? '' ) ), 'width' => $pick( (int) ( $in['width'] ?? -1 ), self::WIDTHS, $def['width'] ), 'font_size' => $pick( (int) ( $in['font_size'] ?? 0 ), self::SIZES, $def['font_size'] ), 'heading_weight' => $pick( (int) ( $in['heading_weight'] ?? 0 ), self::WEIGHTS, $def['heading_weight'] ), 'radius' => $pick( (int) ( $in['radius'] ?? -1 ), self::RADII, $def['radius'] ), 'shadow' => $pick( $in['shadow'] ?? '', self::SHADOWS, $def['shadow'] ), 'card_border' => ! empty( $in['card_border'] ), 'time_format' => $pick( (string) ( $in['time_format'] ?? '' ), self::TIMES, $def['time_format'] ), 'show' => array(), 'labels' => array(), ); foreach ( array( 'text', 'muted', 'bg', 'border', 'on_primary', 'success', 'error' ) as $c ) { $out[ $c ] = sanitize_hex_color( $in[ $c ] ?? '' ) ?: $def[ $c ]; } foreach ( self::SHOW as $k ) { $out['show'][ $k ] = ! isset( $in['show'][ $k ] ) || ! empty( $in['show'][ $k ] ); } foreach ( self::LABELS as $k ) { $out['labels'][ $k ] = sanitize_text_field( (string) ( $in['labels'][ $k ] ?? '' ) ); } return $out; } /** CSS custom properties for the front end (plus the Pro custom CSS). */ public static function css( array $s ) { $d = self::get(); $shadows = array( 'none' => 'none', 'soft' => '0 6px 24px rgba(16,24,40,.06), 0 1px 3px rgba(16,24,40,.05)', 'strong' => '0 18px 50px rgba(16,24,40,.14), 0 3px 8px rgba(16,24,40,.06)', ); $r = (int) $d['radius']; $vars = array( '--bkz-primary' => $s['primary_color'], '--bkz-accent' => $s['accent_color'], '--bkz-font' => $s['font_family'], '--bkz-ink' => $d['text'], '--bkz-ink-2' => $d['muted'], '--bkz-bg' => $d['bg'], '--bkz-line' => $d['border'], '--bkz-on-primary' => $d['on_primary'], '--bkz-success' => $d['success'], '--bkz-error' => $d['error'], '--bkz-size' => $d['font_size'] . 'px', '--bkz-hw' => (string) $d['heading_weight'], '--bkz-r' => $r . 'px', '--bkz-r-sm' => max( 0, $r - 2 ) . 'px', '--bkz-r-lg' => ( $r ? $r + 6 : 0 ) . 'px', '--bkz-shadow' => $shadows[ $d['shadow'] ], '--bkz-card-border'=> $d['card_border'] ? '1px solid ' . $d['border'] : '0', '--bkz-width' => $d['width'] ? $d['width'] . 'px' : 'none', ); $css = '.bkz-root{'; foreach ( $vars as $k => $v ) { $css .= $k . ':' . str_replace( array( ';', '}', '{' ), '', (string) $v ) . ';'; } $css .= '}'; return $css; } /** Classes on each widget root; shortcode attributes can override per page. */ public static function classes( array $atts = array() ) { $d = self::get(); $layout = in_array( $atts['layout'] ?? '', self::LAYOUTS, true ) ? $atts['layout'] : $d['layout']; $services = in_array( $atts['services'] ?? '', self::SERVICES, true ) ? $atts['services'] : $d['services_view']; $staff = in_array( $atts['staff'] ?? '', self::STAFF, true ) ? $atts['staff'] : $d['staff_view']; $slots = in_array( $atts['slots'] ?? '', self::SLOTS, true ) ? $atts['slots'] : $d['slots_view']; $cls = array( 'bkz-root', 'bkz-l-' . $layout, 'bkz-sv-' . $services, 'bkz-st-' . $staff, 'bkz-sl-' . $slots, 'bkz-btn-' . $d['button_style'], 'bkz-cs-' . $d['card_style'], 'bkz-sb-' . $d['sidebar_style'], 'bkz-dv-' . ( in_array( $atts['dates'] ?? '', self::DATES, true ) ? $atts['dates'] : $d['date_view'] ), 'bkz-cols-' . $d['card_cols'], 'bkz-ph-' . $d['photo_size'], 'bkz-ps-' . $d['photo_shape'], $d['animations'] ? 'bkz-anim' : 'bkz-noanim', ); if ( 'popup' === $layout ) { $cls[] = 'bkz-popup-' . $d['popup_align']; } return implode( ' ', $cls ); } /** What the JS needs. */ public static function public_config() { $d = self::get(); return array( 'show' => $d['show'], 'labels' => array_filter( $d['labels'] ), 'timeFormat' => $d['time_format'], 'employee' => $d['employee_mode'], 'order' => $d['step_order'], 'logo' => $d['logo'], 'popupLabel' => $d['popup_label'], ); } }