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
← All changes | includes/page-form-builder/field-packs/custom-shortcode/field-custom-shortcode.php +116 -9 11.8.3 → 11.9 View file →
@@ -1,12 +1,12 @@
1 1 <?php
2 2 /**
3 3 * WPBC BFB Pack: Custom Shortcode.
4 4 *
5 - * Adds one literal, bare shortcode token to the Advanced Booking Form. This is
6 - * intentionally domain-neutral: paid editions may later resolve a token such
7 - * as `[airport_transfer_hint]`, while Form Builder only stores and exports the
8 - * authorized form author's exact token.
5 + * Adds one validated shortcode token to the Advanced Booking Form. The token
6 + * may include Booking Calendar options and quoted values, such as
7 + * `[coupon discount ""]`, while the field pack remains independent of the
8 + * runtime service that interprets the selected shortcode.
9 9 *
10 10 * @package Booking Calendar
11 11 * @since 11.8.2
12 12 */
@@ -15,12 +15,119 @@
15 15 exit;
16 16 }
17 17
18 18 /**
19 + * Normalize one Custom Shortcode value for persistence.
20 + *
21 + * This mirrors the browser-side syntax boundary so a direct or modified save
22 + * request cannot persist nested tokens, HTML delimiters, control characters,
23 + * unbalanced quotes, or an excessively long shortcode through this field pack.
24 + * Runtime shortcode support remains the responsibility of the public form
25 + * parser and edition-specific token producers.
26 + *
27 + * @since 11.8.4
28 + *
29 + * @param mixed $shortcode_value Candidate Custom Shortcode value.
30 + *
31 + * @return string Normalized shortcode, or an empty string when invalid.
32 + */
33 +function wpbc_bfb_normalize_custom_shortcode( $shortcode_value ) {
34 + $shortcode = trim( (string) $shortcode_value );
35 +
36 + if ( strlen( $shortcode ) > 4000 ) {
37 + return '';
38 + }
39 +
40 + $shortcode_characters = array();
41 + $shortcode_length = preg_match_all( '/./us', $shortcode, $shortcode_characters );
42 +
43 + if (
44 + false === $shortcode_length ||
45 + $shortcode_length < 3 ||
46 + $shortcode_length > 1000 ||
47 + '[' !== substr( $shortcode, 0, 1 ) ||
48 + ']' !== substr( $shortcode, -1 )
49 + ) {
50 + return '';
51 + }
52 +
53 + $shortcode_body = trim( substr( $shortcode, 1, -1 ) );
54 +
55 + if ( '' === $shortcode_body || preg_match( '/[\x00-\x1F\x7F<>\[\]]/', $shortcode_body ) ) {
56 + return '';
57 + }
58 +
59 + $shortcode_name_end = strpos( $shortcode_body, ' ' );
60 + $shortcode_name = false === $shortcode_name_end
61 + ? $shortcode_body
62 + : substr( $shortcode_body, 0, $shortcode_name_end );
63 +
64 + if ( ! preg_match( '/^[A-Za-z0-9_.*-]+$/D', $shortcode_name ) ) {
65 + return '';
66 + }
67 +
68 + $active_quote = '';
69 + $body_length = strlen( $shortcode_body );
70 +
71 + for ( $index = strlen( $shortcode_name ); $index < $body_length; $index++ ) {
72 + $character = $shortcode_body[ $index ];
73 +
74 + if ( '' !== $active_quote ) {
75 + if ( $character === $active_quote ) {
76 + $active_quote = '';
77 + }
78 + continue;
79 + }
80 +
81 + if ( '"' === $character || "'" === $character ) {
82 + $active_quote = $character;
83 + }
84 + }
85 +
86 + return '' === $active_quote ? '[' . $shortcode_body . ']' : '';
87 +}
88 +
89 +/**
90 + * Sanitize Custom Shortcode values inside a Form Builder structure.
91 + *
92 + * The recursive traversal understands only the standard field-node envelope
93 + * and leaves every unrelated field, section, page, and unknown extension value
94 + * untouched.
95 + *
96 + * @since 11.8.4
97 + *
98 + * @param array $structure Form Builder structure about to be persisted.
99 + *
100 + * @return array Structure with Custom Shortcode values normalized.
101 + */
102 +function wpbc_bfb_sanitize_structure__custom_shortcode( $structure ) {
103 + if (
104 + 'field' === ( isset( $structure['type'] ) ? $structure['type'] : '' ) &&
105 + isset( $structure['data'] ) &&
106 + is_array( $structure['data'] ) &&
107 + 'custom_shortcode' === ( isset( $structure['data']['type'] ) ? $structure['data']['type'] : '' )
108 + ) {
109 + $structure['data']['shortcode'] = wpbc_bfb_normalize_custom_shortcode(
110 + isset( $structure['data']['shortcode'] ) ? $structure['data']['shortcode'] : ''
111 + );
112 + }
113 +
114 + foreach ( $structure as $structure_key => $structure_value ) {
115 + if ( is_array( $structure_value ) ) {
116 + $structure[ $structure_key ] = wpbc_bfb_sanitize_structure__custom_shortcode( $structure_value );
117 + }
118 + }
119 +
120 + return $structure;
121 +}
122 +add_filter( 'wpbc_bfb_sanitize_structure_before_save', 'wpbc_bfb_sanitize_structure__custom_shortcode', 10, 1 );
123 +
124 +/**
19 125 * Register the Custom Shortcode field schema and Inspector control.
20 126 *
21 - * The field stores one executable-free string. The browser pack validates that
22 - * it is one bare bracketed token before exporting it to the Advanced form.
127 + * The field stores one string. The browser pack applies a bounded allow-list
128 + * before exporting it, and the existing save endpoint applies WordPress KSES
129 + * to the complete generated Advanced Booking Form.
23 130 *
24 131 * @param array $packs Registered Builder field packs.
25 132 *
26 133 * @return array Updated field packs.
@@ -41,9 +148,9 @@
41 148 ),
42 149 ),
43 150 'inspector_ui' => array(
44 151 'title' => __( 'Custom Shortcode', 'booking' ),
45 - 'description' => __( 'Add one supported shortcode to the booking form. For a Form Options Cost hint, use its form field name followed by _hint.', 'booking' ),
152 + 'description' => __( 'Add one supported Booking Calendar shortcode. Options and quoted values are allowed, for example [coupon discount ""]. For a Form Options Cost hint, use its field name followed by _hint.', 'booking' ),
46 153 'header_variant' => 'toolbar',
47 154 'header_actions' => array( 'deselect', 'scrollto', 'move-up', 'move-down', 'duplicate', 'delete' ),
48 155 'groups' => array(
49 156 array(
@@ -90,9 +197,9 @@
90 197 'wpbc-bfb_field_custom_shortcode',
91 198 'WPBC_BFB_Custom_Shortcode_Boot',
92 199 array(
93 200 'example_shortcode' => '[field_name_hint]',
94 - 'invalid_message' => __( 'Enter one shortcode in square brackets, for example [field_name_hint].', 'booking' ),
201 + 'invalid_message' => __( 'Enter one complete shortcode, for example [field_name_hint] or [coupon discount ""].', 'booking' ),
95 202 )
96 203 );
97 204 }
98 205 add_action( 'wpbc_enqueue_js_field_pack', 'wpbc_bfb_enqueue__custom_shortcode_js', 10, 1 );
@@ -100,9 +207,9 @@
100 207 /**
101 208 * Add Custom Shortcode to the Cost Hints palette group.
102 209 *
103 210 * The palette placement reflects the primary Form Options Costs use case, but
104 - * the field itself remains a generic literal-token exporter.
211 + * the field itself remains a generic single-token exporter.
105 212 *
106 213 * @param string $group Palette group.
107 214 * @param string $position Position inside the group.
108 215 *