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-add-booking/add_booking__component.php +183 -27 11.0 → 11.9 View file →
@@ -1,4 +1,4 @@
1 1 <?php /**
2 2 * @version 1.0
3 3 * @package Booking Calendar
4 4 * @category Reusable Add Booking component
@@ -18,9 +18,9 @@
18 18 * Check if current user can access the Add Booking workflow.
19 19 *
20 20 * @return bool
21 21 */
22 - public static function current_user_can_add_booking() {
22 + public static function current_user_can_add_booking() {
23 23
24 24 $user_role = get_bk_option( 'booking_user_role_addbooking' );
25 25 $cap = 'read';
26 26
@@ -29,10 +29,35 @@
29 29 } elseif ( class_exists( 'WPBC_Admin_Menus' ) && isset( WPBC_Admin_Menus::$capability['subscriber'] ) ) {
30 30 $cap = WPBC_Admin_Menus::$capability['subscriber'];
31 31 }
32 32
33 - return current_user_can( $cap );
34 - }
33 + return current_user_can( $cap );
34 + }
35 +
36 +
37 + /**
38 + * Create the administrator booking nonce for an authorized page context.
39 + *
40 + * The public booking endpoint accepts signed-out requests, so administrator
41 + * behavior must be enabled by a user-bound nonce and the same capability and
42 + * MultiUser checks that the server repeats during booking creation.
43 + *
44 + * @return string Administrator booking nonce, or an empty string when the
45 + * current user cannot use the administrator booking workflow.
46 + */
47 + public static function get_admin_booking_nonce() {
48 +
49 + if (
50 + ! is_user_logged_in()
51 + || ! self::current_user_can_add_booking()
52 + || ! function_exists( 'wpbc_is_mu_user_can_be_here' )
53 + || ! wpbc_is_mu_user_can_be_here( 'activated_user' )
54 + ) {
55 + return '';
56 + }
57 +
58 + return wp_create_nonce( 'wpbc_admin_booking_create' );
59 + }
35 60
36 61 /**
37 62 * Render the component and echo by default.
38 63 *
@@ -133,10 +158,16 @@
133 158 'start_month_calendar' => false,
134 159 'calendar_dates_start' => '',
135 160 'calendar_dates_end' => '',
136 161 'booking_hash' => '',
162 + 'allow_past' => null,
163 + 'selected_dates' => '',
137 164 'selected_date' => '',
138 165 'selected_time' => '',
166 + 'time_override_enabled' => 0,
167 + 'time_override_source' => '',
168 + 'time_override_start' => '',
169 + 'time_override_end' => '',
139 170 'is_toolbar_visible' => true,
140 171 'is_booking_page_js' => true,
141 172 'is_booking_page_popover' => true,
142 173 'is_show_before_content_spacer' => true,
@@ -152,9 +183,9 @@
152 183 $args['_is_explicit_booking_form'] = ( ( null !== $args['custom_booking_form'] ) && ( '' !== (string) $args['custom_booking_form'] ) )
153 184 || ( ( null !== $args['booking_form'] ) && ( '' !== (string) $args['booking_form'] ) );
154 185
155 186 $resource_id = self::get_explicit_or_get_resource_id( $args );
156 - $form_name = self::get_explicit_or_get_booking_form( $args );
187 + $form_name = self::get_explicit_or_get_booking_form( $args, $resource_id );
157 188
158 189 $calendar_params = self::get_calendar_params( $args );
159 190
160 191 $args['resource_id'] = $resource_id;
@@ -164,11 +195,17 @@
164 195
165 196 $args['selected_dates_without_calendar'] = ( null !== $args['selected_dates_without_calendar'] ) ? (string) $args['selected_dates_without_calendar'] : '';
166 197 $args['calendar_dates_start'] = (string) $args['calendar_dates_start'];
167 198 $args['calendar_dates_end'] = (string) $args['calendar_dates_end'];
168 - $args['booking_hash'] = sanitize_text_field( wp_unslash( (string) $args['booking_hash'] ) );
199 + $args['booking_hash'] = ( '' !== (string) $args['booking_hash'] ) ? sanitize_text_field( wp_unslash( (string) $args['booking_hash'] ) ) : ( isset( $_GET['booking_hash'] ) ? sanitize_text_field( wp_unslash( $_GET['booking_hash'] ) ) : '' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
200 + $args['allow_past'] = ( null !== $args['allow_past'] ) ? ( ! empty( $args['allow_past'] ) ? 1 : 0 ) : ( isset( $_GET['allow_past'] ) ? 1 : 0 ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
201 + $args['selected_dates'] = sanitize_text_field( wp_unslash( (string) $args['selected_dates'] ) );
169 202 $args['selected_date'] = sanitize_text_field( wp_unslash( (string) $args['selected_date'] ) );
170 203 $args['selected_time'] = sanitize_text_field( wp_unslash( (string) $args['selected_time'] ) );
204 + $args['time_override_enabled'] = ! empty( $args['time_override_enabled'] ) ? 1 : 0;
205 + $args['time_override_source'] = sanitize_key( wp_unslash( (string) $args['time_override_source'] ) );
206 + $args['time_override_start'] = sanitize_text_field( wp_unslash( (string) $args['time_override_start'] ) );
207 + $args['time_override_end'] = sanitize_text_field( wp_unslash( (string) $args['time_override_end'] ) );
171 208
172 209 return $args;
173 210 }
174 211
@@ -179,29 +216,92 @@
179 216 * @param array $args Component options.
180 217 *
181 218 * @return void
182 219 */
183 - private static function print_context_js( $args ) {
184 -
185 - $booking_hash = isset( $args['booking_hash'] ) ? (string) $args['booking_hash'] : '';
186 - $context = array(
187 - 'resource_id' => absint( $args['resource_id'] ),
220 + private static function print_context_js( $args ) {
221 +
222 + $booking_hash = isset( $args['booking_hash'] ) ? (string) $args['booking_hash'] : '';
223 + $admin_booking_nonce = self::get_admin_booking_nonce();
224 + $allow_past_date_arr = self::get_allow_past_min_date_arr( $args );
225 + $context = array(
226 + 'resource_id' => absint( $args['resource_id'] ),
188 227 'selected_dates_without_calendar' => (string) $args['selected_dates_without_calendar'],
228 + 'selected_dates' => (string) $args['selected_dates'],
189 229 'selected_date' => (string) $args['selected_date'],
190 230 'selected_time' => (string) $args['selected_time'],
191 - );
192 - ?>
193 - <script type="text/javascript">
194 - window.wpbc_add_booking_component_context = <?php echo wp_json_encode( $context ); ?>;
195 - if ( 'undefined' !== typeof _wpbc ) {
196 - _wpbc.set_other_param( 'this_page_booking_hash', <?php echo wp_json_encode( $booking_hash ); ?> );
197 - }
198 - </script>
231 + 'time_override_enabled' => absint( $args['time_override_enabled'] ),
232 + 'time_override_source' => (string) $args['time_override_source'],
233 + 'time_override_start' => (string) $args['time_override_start'],
234 + 'time_override_end' => (string) $args['time_override_end'],
235 + 'allow_past' => ! empty( $args['allow_past'] ) ? 1 : 0,
236 + );
237 + $booking_context_js = "_wpbc.set_other_param( 'this_page_booking_hash', " . wp_json_encode( $booking_hash ) . ' );';
238 + $booking_context_js .= "_wpbc.set_other_param( 'this_page_allow_past', " . wp_json_encode( ! empty( $args['allow_past'] ) ? 1 : 0 ) . ' );';
239 + $booking_context_js .= "_wpbc.set_other_param( 'this_page_allow_past_arr', " . wp_json_encode( $allow_past_date_arr ) . ' );';
240 + $booking_context_js .= "_wpbc.set_other_param( 'this_page_admin_booking_nonce', " . wp_json_encode( $admin_booking_nonce ) . ' );';
241 +
242 + $is_context_queued = false;
243 + if ( ! wp_doing_ajax() && class_exists( 'WPBC_FE_Assets' ) ) {
244 + $is_context_queued = WPBC_FE_Assets::add_jq_ready_js_to_wp_script(
245 + 'wpbc_all',
246 + $booking_context_js,
247 + 'wpbc:add-booking-admin-context:' . md5( $booking_context_js )
248 + );
249 + }
250 + ?>
251 + <script type="text/javascript">
252 + window.wpbc_add_booking_component_context = <?php echo wp_json_encode( $context ); ?>;
253 + <?php if ( ! $is_context_queued ) : ?>
254 + ( function () {
255 + function apply_booking_context() {
256 + if ( 'undefined' === typeof _wpbc ) {
257 + return;
258 + }
259 +
260 + <?php echo $booking_context_js; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Values are JSON encoded above. ?>
261 + }
262 +
263 + if ( 'undefined' !== typeof _wpbc ) {
264 + apply_booking_context();
265 + } else {
266 + document.addEventListener( 'DOMContentLoaded', apply_booking_context );
267 + }
268 + }() );
269 + <?php endif; ?>
270 + </script>
199 271 <?php
200 272 }
201 273
202 274
203 275 /**
276 + * Get minimum date array for modal/admin contexts that allow selecting past days.
277 + *
278 + * @param array $args Component options.
279 + *
280 + * @return array
281 + */
282 + public static function get_allow_past_min_date_arr( $args ) {
283 +
284 + if ( empty( $args['allow_past'] ) && empty( $args['booking_hash'] ) ) {
285 + return array();
286 + }
287 +
288 + if (
289 + ! function_exists( 'wpbc_get_max_visible_days_in_calendar' )
290 + || ! function_exists( 'wpbc_datetime_localized__use_wp_timezone' )
291 + || ! function_exists( 'wpbc_csv_numbers_to_int_array' )
292 + ) {
293 + return array();
294 + }
295 +
296 + $gmt_time = gmdate( 'Y-m-d H:i:s', strtotime( '-' . intval( wpbc_get_max_visible_days_in_calendar() ) . ' days' ) );
297 + $local_csv = wpbc_datetime_localized__use_wp_timezone( $gmt_time, 'Y,m,d,H,i' );
298 +
299 + return wpbc_csv_numbers_to_int_array( $local_csv );
300 + }
301 +
302 +
303 + /**
204 304 * Resolve booking resource id: explicit component args first, then legacy $_GET.
205 305 *
206 306 * @param array $args Component options.
207 307 *
@@ -225,16 +325,53 @@
225 325 }
226 326
227 327
228 328 /**
229 - * Resolve booking form: explicit component args first, then legacy $_GET.
329 + * Resolve default booking form for specific booking resource.
230 330 *
231 - * @param array $args Component options.
331 + * @param int $resource_id Booking resource ID.
332 + * @param string $default_form Fallback form name.
232 333 *
233 334 * @return string
234 335 */
235 - private static function get_explicit_or_get_booking_form( $args ) {
336 + public static function get_default_booking_form_for_resource( $resource_id, $default_form = 'standard' ) {
236 337
338 + $resource_id = absint( $resource_id );
339 + $default_form = ( '' !== (string) $default_form ) ? (string) $default_form : 'standard';
340 +
341 + if ( $resource_id <= 0 ) {
342 + return sanitize_text_field( wp_unslash( $default_form ) );
343 + }
344 +
345 + $default_custom_form_name = '';
346 + if ( function_exists( 'apply_bk_filter' ) ) {
347 + $default_custom_form_name = apply_bk_filter( 'wpbc_get_default_custom_form', '', $resource_id );
348 + }
349 +
350 + if (
351 + ( '' === (string) $default_custom_form_name )
352 + && class_exists( 'WPBC_FE_Custom_Form_Helper' )
353 + && method_exists( 'WPBC_FE_Custom_Form_Helper', 'get_default_custom_form__for__booking_resource' )
354 + ) {
355 + $default_custom_form_name = WPBC_FE_Custom_Form_Helper::get_default_custom_form__for__booking_resource( $resource_id );
356 + }
357 +
358 + $default_custom_form_name = sanitize_text_field( wp_unslash( (string) $default_custom_form_name ) );
359 +
360 + return ( '' !== $default_custom_form_name ) ? $default_custom_form_name : sanitize_text_field( wp_unslash( $default_form ) );
361 + }
362 +
363 +
364 + /**
365 + * Resolve booking form: explicit component args first, then legacy $_GET, then resource default.
366 + *
367 + * @param array $args Component options.
368 + * @param int $resource_id Booking resource ID.
369 + *
370 + * @return string
371 + */
372 + private static function get_explicit_or_get_booking_form( $args, $resource_id = 0 ) {
373 +
237 374 if ( ( null !== $args['custom_booking_form'] ) && ( '' !== (string) $args['custom_booking_form'] ) ) {
238 375 return sanitize_text_field( wp_unslash( (string) $args['custom_booking_form'] ) );
239 376 }
240 377
@@ -241,9 +378,13 @@
241 378 if ( ( null !== $args['booking_form'] ) && ( '' !== (string) $args['booking_form'] ) ) {
242 379 return sanitize_text_field( wp_unslash( (string) $args['booking_form'] ) );
243 380 }
244 381
245 - return WPBC_GET_Request::has_non_empty_get( 'booking_form' ) ? WPBC_GET_Request::get_sanitized( 'booking_form' ) : 'standard';
382 + if ( WPBC_GET_Request::has_non_empty_get( 'booking_form' ) ) {
383 + return WPBC_GET_Request::get_sanitized( 'booking_form' );
384 + }
385 +
386 + return self::get_default_booking_form_for_resource( $resource_id, 'standard' );
246 387 }
247 388
248 389
249 390 /**
@@ -290,12 +431,27 @@
290 431 * Get Calendar Options of specific User.
291 432 *
292 433 * @return array Number of months and calendar options parameter.
293 434 */
294 - public static function get_saved_user_calendar_options() {
435 + public static function get_saved_user_calendar_options() {
436 +
437 + return self::format_calendar_options( self::get_saved_user_calendar_settings() );
438 + }
439 +
440 +
441 + /**
442 + * Get the raw per-user Add Booking calendar settings.
443 + *
444 + * The inspector needs the individual saved fields, while
445 + * get_saved_user_calendar_options() preserves the renderer-formatted public
446 + * result used by the Booking Form component.
447 + *
448 + * @return array<string,mixed> Raw saved calendar settings.
449 + */
450 + public static function get_saved_user_calendar_settings() {
451 +
452 + $user_calendar_options = get_user_option( 'booking_custom_' . 'add_booking_calendar_options', wpbc_get_current_user_id() );
295 453
296 - $user_calendar_options = get_user_option( 'booking_custom_' . 'add_booking_calendar_options', wpbc_get_current_user_id() );
297 -
298 454 if ( false === $user_calendar_options ) {
299 455 $user_calendar_options = array();
300 456 } else {
301 457 $user_calendar_options = maybe_unserialize( $user_calendar_options );
@@ -300,10 +456,10 @@
300 456 } else {
301 457 $user_calendar_options = maybe_unserialize( $user_calendar_options );
302 458 }
303 459
304 - return self::format_calendar_options( $user_calendar_options );
305 - }
460 + return is_array( $user_calendar_options ) ? $user_calendar_options : array();
461 + }
306 462
307 463
308 464 /**
309 465 * Convert calendar option values to the shortcode option string used by the renderer.