← 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. |