PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
11.9 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 All 205 releases
booking / includes / page-form-builder / bfb-schemas.php

bfb-schemas.php in Booking Calendar 11.9, at includes/page-form-builder/bfb-schemas.php

183 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Hybrid++ Schemas utilities: normalize/validate/merge/extract.
4 *
5 * @package Booking Calendar.
6 * @author wpdevelop, oplugins
7 * @web-site https://wpbookingcalendar.com/
8 * @email [email protected]
9 *
10 * @since 11.0.0
11 * @modified 2025-08-29
12 * @version 1.0
13 */
14
15 // ---------------------------------------------------------------------------------------------------------------------
16 // == File bfb-schemas.php == Time point: 2025-08-29 12:25
17 // ---------------------------------------------------------------------------------------------------------------------
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit; // Exit if accessed directly.
20 }
21
22 /**
23 * Utilities for working with field/section/component packs.
24 */
25 class WPBC_BFB_Schemas_Util {
26
27 /**
28 * Normalize a single pack to a safe, known shape.
29 *
30 * @param array $pack Raw pack from a filter callback.
31 *
32 * @return array Normalized pack.
33 */
34 public static function normalize_pack( $pack ) {
35 $pack = is_array( $pack ) ? $pack : array();
36
37 $pack['kind'] = isset( $pack['kind'] ) ? sanitize_key( $pack['kind'] ) : 'field';
38 $pack['type'] = isset( $pack['type'] ) ? sanitize_key( $pack['type'] ) : '';
39 $pack['schema'] = ( isset( $pack['schema'] ) && is_array( $pack['schema'] ) ) ? $pack['schema'] : array();
40 if ( ! isset( $pack['schema']['props'] ) || ! is_array( $pack['schema']['props'] ) ) {
41 $pack['schema']['props'] = array();
42 }
43
44 $pack['inspector_ui'] = ( isset( $pack['inspector_ui'] ) && is_array( $pack['inspector_ui'] ) ) ? $pack['inspector_ui'] : array();
45
46 if ( ! isset( $pack['inspector_ui']['groups'] ) || ! is_array( $pack['inspector_ui']['groups'] ) ) {
47 $pack['inspector_ui']['groups'] = array();
48 }
49
50 $pack['header_actions'] = ( isset( $pack['header_actions'] ) && is_array( $pack['header_actions'] ) ) ? array_values( $pack['header_actions'] ) : array();
51
52 $pack['templates_printer'] = ( isset( $pack['templates_printer'] ) && is_callable( $pack['templates_printer'] ) ) ? $pack['templates_printer'] : null;
53
54 return $pack;
55 }
56
57 /**
58 * Basic validation: keep only supported prop/control types and JSON-serializable data.
59 *
60 * @param array $pack Normalized pack.
61 *
62 * @return array Validated pack (unsafe bits removed).
63 */
64 public static function validate_pack( $pack ) {
65
66 // Allow extra prop/control types used by the Inspector Factory.
67 $allowed_prop_types = array( 'string', 'number', 'boolean', 'array', 'int', 'float', 'enum', 'color' );
68 // Expanded to support Factory extras and color control.
69 $allowed_control_types = array( 'text', 'number', 'checkbox', 'textarea', 'select', 'range_number', 'len', 'color', 'slot' );
70
71 // Validate prop meta.
72 foreach ( $pack['schema']['props'] as $prop_key => $meta ) {
73
74 if ( ! is_array( $meta ) ) {
75 unset( $pack['schema']['props'][ $prop_key ] );
76 continue;
77 }
78 $meta['type'] = isset( $meta['type'] ) ? $meta['type'] : 'string';
79 if ( ! in_array( $meta['type'], $allowed_prop_types, true ) ) {
80 unset( $pack['schema']['props'][ $prop_key ] );
81 continue;
82 }
83 // Drop non-serializable values.
84 foreach ( $meta as $k => $v ) {
85 if ( is_object( $v ) && ! ( $v instanceof JsonSerializable ) ) {
86 unset( $meta[ $k ] );
87 }
88 }
89 $pack['schema']['props'][ $prop_key ] = $meta;
90 }
91
92 // Validate inspector groups/controls.
93 if ( ! empty( $pack['inspector_ui']['groups'] ) ) {
94 foreach ( $pack['inspector_ui']['groups'] as $g_i => $group ) {
95 if ( ! is_array( $group ) ) {
96 unset( $pack['inspector_ui']['groups'][ $g_i ] );
97 continue;
98 }
99 $group['controls'] = ( isset( $group['controls'] ) && is_array( $group['controls'] ) ) ? $group['controls'] : array();
100
101 foreach ( $group['controls'] as $c_i => $control ) {
102 if ( ! is_array( $control ) ) {
103 unset( $group['controls'][ $c_i ] );
104 continue;
105 }
106 if ( empty( $control['key'] ) || empty( $control['type'] ) || ! in_array( $control['type'], $allowed_control_types, true ) ) {
107 unset( $group['controls'][ $c_i ] );
108 continue;
109 }
110 if ( 'slot' === $control['type'] ) {
111 $control['slot'] = isset( $control['slot'] ) ? sanitize_key( $control['slot'] ) : '';
112 if ( '' === $control['slot'] ) {
113 unset( $group['controls'][ $c_i ] );
114 continue;
115 }
116 }
117 // Remove objects in control meta.
118 foreach ( $control as $k => $v ) {
119 if ( is_object( $v ) && ! ( $v instanceof JsonSerializable ) ) {
120 unset( $control[ $k ] );
121 }
122 }
123 $group['controls'][ $c_i ] = $control;
124 }
125 $pack['inspector_ui']['groups'][ $g_i ] = $group;
126 }
127 }
128
129 // Sanitize header action keys.
130 if ( ! empty( $pack['header_actions'] ) ) {
131 $san = array();
132 foreach ( $pack['header_actions'] as $act ) {
133 $san[] = sanitize_key( $act );
134 }
135 $pack['header_actions'] = array_values( array_unique( $san ) );
136 }
137
138 return $pack;
139 }
140
141 /**
142 * Merge a list of packs keyed by type. Later packs win on conflicts.
143 *
144 * @param array $packs Packs list.
145 *
146 * @return array Merged packs keyed by type.
147 */
148 public static function merge_packs( $packs ) {
149 $merged = array();
150 foreach ( (array) $packs as $pack ) {
151 $pack = self::normalize_pack( $pack );
152 $pack = self::validate_pack( $pack );
153 if ( empty( $pack['type'] ) ) {
154 continue;
155 }
156 $merged[ $pack['type'] ] = $pack; // last writer wins.
157 }
158
159 return $merged;
160 }
161
162 /**
163 * Extract only the JS-safe schema bits for localization.
164 *
165 * @param array $packs_by_type Merged packs keyed by type.
166 *
167 * @return array Array keyed by type for JS (small payload).
168 */
169 public static function extract_schemas_for_js( $packs_by_type ) {
170 $out = array();
171 foreach ( (array) $packs_by_type as $type => $pack ) {
172 $out[ $type ] = array(
173 'kind' => isset( $pack['kind'] ) ? $pack['kind'] : 'field',
174 'schema' => isset( $pack['schema'] ) ? $pack['schema'] : array( 'props' => array() ),
175 'inspector_ui' => isset( $pack['inspector_ui'] ) ? $pack['inspector_ui'] : array( 'groups' => array() ),
176 'header_actions' => isset( $pack['header_actions'] ) ? array_values( $pack['header_actions'] ) : array(),
177 );
178 }
179
180 return $out;
181 }
182 }
183