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 / field-packs / coupon / field-coupon.php

field-coupon.php in Booking Calendar 11.9, at includes/page-form-builder/field-packs/coupon/field-coupon.php

332 lines 11.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WPBC BFB Pack: Discount Coupon field.
4 *
5 * Adds the visual Form Builder counterpart of the Advanced Mode `[coupon]`
6 * shortcode. The Builder field is visible in every edition so lower editions
7 * can show the established upgrade badge, while its exporter activates only
8 * when the Business Large coupon service is available.
9 *
10 * @package Booking Calendar
11 * @since 11.8.5
12 */
13
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 /**
19 * Check whether the installed edition provides coupon discounts.
20 *
21 * Coupon calculation, validation, and usage tracking are owned by the
22 * Business Large service represented by this established edition class.
23 *
24 * @since 11.8.5
25 *
26 * @return bool True when Business Large or a higher edition is active.
27 */
28 function wpbc_bfb_coupon_is_supported() {
29 return class_exists( 'wpdev_bk_biz_l' );
30 }
31
32 /**
33 * Convert a scalar Coupon property to a string without array/object warnings.
34 *
35 * @since 11.8.5
36 *
37 * @param mixed $property_value Candidate property value.
38 *
39 * @return string Scalar string, or an empty string for compound values.
40 */
41 function wpbc_bfb_coupon_string_value( $property_value ) {
42 return is_scalar( $property_value ) ? (string) $property_value : '';
43 }
44
45 /**
46 * Sanitize a Coupon shortcode field name.
47 *
48 * The public shortcode parser accepts an ASCII token beginning with a letter.
49 * Invalid or empty names fall back to the canonical legacy Coupon field name
50 * so the generated form and Booking Data token remain usable.
51 *
52 * @since 11.8.5
53 *
54 * @param mixed $field_name Candidate field name.
55 *
56 * @return string Safe shortcode field name.
57 */
58 function wpbc_bfb_coupon_sanitize_field_name( $field_name ) {
59 $field_name = preg_replace( '/[^A-Za-z0-9_-]/', '', wpbc_bfb_coupon_string_value( $field_name ) );
60 $field_name = substr( $field_name, 0, 80 );
61
62 if ( '' === $field_name || ! preg_match( '/^[A-Za-z]/', $field_name ) ) {
63 return 'coupon';
64 }
65
66 return $field_name;
67 }
68
69 /**
70 * Sanitize a space-separated CSS class list for Coupon field persistence.
71 *
72 * @since 11.8.5
73 *
74 * @param mixed $class_list Candidate class list.
75 *
76 * @return string Safe class list containing at most ten class tokens.
77 */
78 function wpbc_bfb_coupon_sanitize_css_classes( $class_list ) {
79 $class_tokens = preg_split( '/\s+/', trim( wpbc_bfb_coupon_string_value( $class_list ) ) );
80 $safe_class_tokens = array();
81
82 foreach ( (array) $class_tokens as $class_token ) {
83 $class_token = sanitize_html_class( $class_token );
84 if ( '' === $class_token || in_array( $class_token, $safe_class_tokens, true ) ) {
85 continue;
86 }
87
88 $safe_class_tokens[] = $class_token;
89 if ( 10 === count( $safe_class_tokens ) ) {
90 break;
91 }
92 }
93
94 return implode( ' ', $safe_class_tokens );
95 }
96
97 /**
98 * Bound a sanitized Coupon field string without requiring multibyte support.
99 *
100 * @since 11.8.5
101 *
102 * @param string $field_text Sanitized field text.
103 * @param int $max_length Maximum character count.
104 *
105 * @return string Bounded field text.
106 */
107 function wpbc_bfb_coupon_limit_text( $field_text, $max_length ) {
108 $field_text = wpbc_bfb_coupon_string_value( $field_text );
109 $max_length = max( 0, (int) $max_length );
110
111 if ( function_exists( 'mb_substr' ) ) {
112 return mb_substr( $field_text, 0, $max_length );
113 }
114
115 return substr( $field_text, 0, $max_length );
116 }
117
118 /**
119 * Normalize a Coupon field checkbox value to a strict boolean.
120 *
121 * Form Builder normally sends a JSON boolean, but the save boundary also
122 * handles scalar values from modified requests without treating the string
123 * `false` as enabled.
124 *
125 * @since 11.8.5
126 *
127 * @param mixed $checkbox_value Candidate checkbox value.
128 *
129 * @return bool True only for recognized enabled values.
130 */
131 function wpbc_bfb_coupon_sanitize_boolean( $checkbox_value ) {
132 return in_array( $checkbox_value, array( true, 1, '1', 'true', 'required' ), true );
133 }
134
135 /**
136 * Sanitize Coupon fields inside a Form Builder structure before persistence.
137 *
138 * This is a narrow save-boundary filter. It normalizes only Coupon field-node
139 * data and leaves unrelated pages, sections, fields, and extension values
140 * unchanged. Edition support is intentionally not stored in the structure;
141 * the current server edition remains authoritative when the exporter runs.
142 *
143 * @since 11.8.5
144 *
145 * @param array $structure_branch Current Form Builder structure branch.
146 *
147 * @return array Structure branch with Coupon field properties normalized.
148 */
149 function wpbc_bfb_sanitize_structure__coupon( $structure_branch ) {
150 if (
151 'field' === ( isset( $structure_branch['type'] ) ? $structure_branch['type'] : '' ) &&
152 isset( $structure_branch['data'] ) &&
153 is_array( $structure_branch['data'] ) &&
154 'coupon' === ( isset( $structure_branch['data']['type'] ) ? $structure_branch['data']['type'] : '' )
155 ) {
156 $coupon_data = $structure_branch['data'];
157
158 $coupon_data['label'] = wpbc_bfb_coupon_limit_text(
159 sanitize_text_field( wpbc_bfb_coupon_string_value( isset( $coupon_data['label'] ) ? $coupon_data['label'] : '' ) ),
160 200
161 );
162 $coupon_data['name'] = wpbc_bfb_coupon_sanitize_field_name(
163 isset( $coupon_data['name'] ) ? $coupon_data['name'] : 'coupon'
164 );
165 $coupon_data['placeholder'] = wpbc_bfb_coupon_limit_text(
166 sanitize_text_field( wpbc_bfb_coupon_string_value( isset( $coupon_data['placeholder'] ) ? $coupon_data['placeholder'] : '' ) ),
167 200
168 );
169 $coupon_data['required'] = wpbc_bfb_coupon_sanitize_boolean(
170 isset( $coupon_data['required'] ) ? $coupon_data['required'] : false
171 );
172 $coupon_data['help'] = wpbc_bfb_coupon_limit_text(
173 sanitize_textarea_field( wpbc_bfb_coupon_string_value( isset( $coupon_data['help'] ) ? $coupon_data['help'] : '' ) ),
174 1000
175 );
176 $coupon_data['cssclass'] = wpbc_bfb_coupon_sanitize_css_classes(
177 isset( $coupon_data['cssclass'] ) ? $coupon_data['cssclass'] : ''
178 );
179 $coupon_data['html_id'] = wpbc_bfb_coupon_limit_text(
180 sanitize_html_class( wpbc_bfb_coupon_string_value( isset( $coupon_data['html_id'] ) ? $coupon_data['html_id'] : '' ) ),
181 80
182 );
183
184 unset( $coupon_data['is_supported'], $coupon_data['upgrade_text'] );
185 $structure_branch['data'] = $coupon_data;
186 }
187
188 foreach ( $structure_branch as $branch_key => $branch_value ) {
189 if ( is_array( $branch_value ) ) {
190 $structure_branch[ $branch_key ] = wpbc_bfb_sanitize_structure__coupon( $branch_value );
191 }
192 }
193
194 return $structure_branch;
195 }
196 add_filter( 'wpbc_bfb_sanitize_structure_before_save', 'wpbc_bfb_sanitize_structure__coupon', 30, 1 );
197
198 /**
199 * Register the Discount Coupon field schema and Inspector controls.
200 *
201 * @since 11.8.5
202 *
203 * @param array $packs Registered Form Builder field packs.
204 *
205 * @return array Updated field packs.
206 */
207 function wpbc_bfb_register_field_packs__coupon( $packs ) {
208 $description = wpbc_bfb_coupon_is_supported()
209 ? __( 'Add a coupon-code input that recalculates the booking cost after a visitor enters a code.', 'booking' )
210 : __( 'This field is available only in Booking Calendar Business Large or higher versions.', 'booking' );
211
212 $packs['coupon'] = array(
213 'kind' => 'field',
214 'type' => 'coupon',
215 'label' => __( 'Discount Coupon', 'booking' ),
216 'icon' => 'wpbc-bi-ticket-perforated',
217 'usage_key' => 'coupon',
218 'schema' => array(
219 'props' => array(
220 'label' => array( 'type' => 'string', 'default' => __( 'Discount Coupon', 'booking' ) ),
221 'name' => array( 'type' => 'string', 'default' => 'coupon' ),
222 'placeholder' => array( 'type' => 'string', 'default' => '' ),
223 'required' => array( 'type' => 'boolean', 'default' => false ),
224 'help' => array( 'type' => 'string', 'default' => '' ),
225 'cssclass' => array( 'type' => 'string', 'default' => '' ),
226 'html_id' => array( 'type' => 'string', 'default' => '' ),
227 ),
228 ),
229 'inspector_ui' => array(
230 'title' => __( 'Discount Coupon', 'booking' ),
231 'description' => $description,
232 'header_variant' => 'toolbar',
233 'header_actions' => array( 'deselect', 'scrollto', 'move-up', 'move-down', 'delete' ),
234 'groups' => array(
235 array(
236 'key' => 'basic',
237 'label' => __( 'Basic', 'booking' ),
238 'open' => true,
239 'controls' => array(
240 array( 'type' => 'text', 'key' => 'label', 'label' => __( 'Label', 'booking' ) ),
241 array( 'type' => 'text', 'key' => 'name', 'label' => __( 'Name', 'booking' ) ),
242 array( 'type' => 'text', 'key' => 'placeholder', 'label' => __( 'Placeholder', 'booking' ) ),
243 array( 'type' => 'checkbox', 'key' => 'required', 'label' => __( 'Required', 'booking' ) ),
244 array( 'type' => 'textarea', 'key' => 'help', 'label' => __( 'Help text', 'booking' ), 'rows' => 3 ),
245 ),
246 ),
247 array(
248 'key' => 'appearance',
249 'label' => __( 'Appearance', 'booking' ),
250 'controls' => array(
251 array( 'type' => 'text', 'key' => 'cssclass', 'label' => __( 'CSS class', 'booking' ) ),
252 array( 'type' => 'text', 'key' => 'html_id', 'label' => __( 'HTML ID', 'booking' ) ),
253 ),
254 ),
255 ),
256 ),
257 );
258
259 return $packs;
260 }
261 add_filter( 'wpbc_bfb_register_field_packs', 'wpbc_bfb_register_field_packs__coupon' );
262
263 /**
264 * Enqueue the Discount Coupon renderer and exporters on the Builder page.
265 *
266 * The runtime asset is loaded from `_out`; `_src` remains the editable source.
267 * Edition support and upgrade messaging are supplied by the server instead of
268 * being trusted from saved structure JSON.
269 *
270 * @since 11.8.5
271 *
272 * @param string $page Current administration page slug.
273 *
274 * @return void
275 */
276 function wpbc_bfb_enqueue__coupon_js( $page ) {
277 wp_enqueue_script(
278 'wpbc-bfb_field_coupon',
279 wpbc_plugin_url( '/includes/page-form-builder/field-packs/coupon/_out/field-coupon.js' ),
280 array( 'wpbc-bfb' ),
281 WP_BK_VERSION_NUM,
282 true
283 );
284
285 wp_localize_script(
286 'wpbc-bfb_field_coupon',
287 'WPBC_BFB_Coupon_Boot',
288 array(
289 'is_supported' => wpbc_bfb_coupon_is_supported() ? 1 : 0,
290 'upgrade_text' => __( 'This field is available only in Booking Calendar Business Large or higher versions.', 'booking' ),
291 )
292 );
293 }
294 add_action( 'wpbc_enqueue_js_field_pack', 'wpbc_bfb_enqueue__coupon_js', 10, 1 );
295
296 /**
297 * Add Discount Coupon to the standard Fields palette.
298 *
299 * The one-per-form limit matches the Advanced Mode guidance and the legacy
300 * coupon parser, which exposes one canonical coupon value to pricing logic.
301 *
302 * @since 11.8.5
303 *
304 * @param string $group Palette group.
305 * @param string $position Position inside the group.
306 *
307 * @return void
308 */
309 function wpbc_bfb_palette_register_items__coupon( $group, $position ) {
310 if ( 'standard' !== $group || 'bottom' !== $position ) {
311 return;
312 }
313 ?>
314 <li class="wpbc_bfb__field"
315 data-id="coupon"
316 data-type="coupon"
317 data-usage_key="coupon"
318 data-usagenumber="1"
319 data-label="<?php echo esc_attr( __( 'Discount Coupon', 'booking' ) ); ?>"
320 data-name="coupon"
321 data-required="false">
322 <i class="menu_icon icon-1x wpbc-bi-ticket-perforated"></i>
323 <span class="wpbc_bfb__field-label"><?php echo esc_html__( 'Discount Coupon', 'booking' ); ?></span>
324 <?php if ( ! wpbc_bfb_coupon_is_supported() ) : ?>
325 <span class="wpbc_pro_label">Pro | BL+</span>
326 <?php endif; ?>
327 <span class="wpbc_bfb__field-type">coupon</span>
328 </li>
329 <?php
330 }
331 add_action( 'wpbc_bfb_palette_register_items', 'wpbc_bfb_palette_register_items__coupon', 10, 2 );
332