| @@ -213,10 +213,94 @@ | ||
| 213 | 213 | // --------------------------------------------------------------------------------------------------------------------- |
| 214 | 214 | // == Save Booking |
| 215 | 215 | // --------------------------------------------------------------------------------------------------------------------- |
| 216 | 216 | |
| 217 | -/** | |
| 218 | - * Save Booking - ADD NEW or UPDATE exist booking | |
| 217 | +/** | |
| 218 | + * Resolve and validate the final booking destination against current storage. | |
| 219 | + * | |
| 220 | + * This function contains the availability, Appointment working-time, and | |
| 221 | + * Appointment buffer checks that must be repeated if the database connection | |
| 222 | + * loses its advisory lock before persistence. The caller clears the relevant | |
| 223 | + * request-local cache before every invocation. | |
| 224 | + * | |
| 225 | + * @param array $local_params Parsed booking parameters, passed by reference because force-save mode fixes capacity at one. | |
| 226 | + * @param array $cleaned_params Sanitized booking request parameters. | |
| 227 | + * @param array $php_performance Performance measurements, passed by reference. | |
| 228 | + * | |
| 229 | + * @return array|WP_Error Validated storage destination, or a visitor-safe validation error. | |
| 230 | + */ | |
| 231 | +function wpbc_booking_validate_save_availability( &$local_params, $cleaned_params, &$php_performance ) { | |
| 232 | + | |
| 233 | + // Privileged imports and other established integrations may intentionally force a save. | |
| 234 | + if ( ! empty( $cleaned_params['save_booking_even_if_unavailable'] ) ) { | |
| 235 | + $local_params['how_many_items_to_book'] = 1; | |
| 236 | + $dates_keys_arr = array_values( $local_params['dates_only_sql_arr'] ); | |
| 237 | + $resources_in_dates = array_fill_keys( $dates_keys_arr, array( $local_params['initial_resource_id'] ) ); | |
| 238 | + $where_to_save_booking = array( | |
| 239 | + 'result' => 'ok', | |
| 240 | + 'resources_in_dates' => $resources_in_dates, | |
| 241 | + 'time_to_book' => $local_params['time_as_his_arr'], | |
| 242 | + 'main__resource_id' => $local_params['initial_resource_id'], | |
| 243 | + ); | |
| 244 | + } else { | |
| 245 | + $php_performance = wpbc_php_performance_START( 'wpbc__where_to_save_booking', $php_performance ); | |
| 246 | + | |
| 247 | + $where_to_save_booking = wpbc__where_to_save_booking( | |
| 248 | + array( | |
| 249 | + 'resource_id' => $local_params['initial_resource_id'], | |
| 250 | + 'skip_booking_id' => $local_params['skip_booking_id'], | |
| 251 | + 'dates_only_sql_arr' => $local_params['dates_only_sql_arr'], | |
| 252 | + 'time_as_seconds_arr' => $local_params['time_as_seconds_arr'], | |
| 253 | + 'how_many_items_to_book' => $local_params['how_many_items_to_book'], | |
| 254 | + 'request_uri' => $cleaned_params['request_uri'], | |
| 255 | + 'allow_past' => ! empty( $cleaned_params['allow_past'] ), | |
| 256 | + 'is_use_booking_recurrent_time' => $local_params['is_use_booking_recurrent_time'], | |
| 257 | + 'time_override_source' => ! empty( $local_params['time_override_arr']['source'] ) ? $local_params['time_override_arr']['source'] : '', | |
| 258 | + 'as_single_resource' => false, | |
| 259 | + 'aggregate_resource_id_arr' => $local_params['aggregate_resource_id_arr'], | |
| 260 | + 'aggregate_type' => $cleaned_params['aggregate_type'], | |
| 261 | + 'custom_form' => $cleaned_params['custom_form'], | |
| 262 | + ) | |
| 263 | + ); | |
| 264 | + | |
| 265 | + if ( 'error' === $where_to_save_booking['result'] ) { | |
| 266 | + return new WP_Error( 'booking_can_not_save', $where_to_save_booking['message'] ); | |
| 267 | + } | |
| 268 | + | |
| 269 | + $php_performance = wpbc_php_performance_END( 'wpbc__where_to_save_booking', $php_performance ); | |
| 270 | + } | |
| 271 | + | |
| 272 | + if ( ! empty( $local_params['appointment_service'] ) && function_exists( 'wpbc_appointment_services_check_working_time' ) ) { | |
| 273 | + $working_time_check = wpbc_appointment_services_check_working_time( | |
| 274 | + $local_params['appointment_service'], | |
| 275 | + $where_to_save_booking['main__resource_id'], | |
| 276 | + array_keys( $where_to_save_booking['resources_in_dates'] ), | |
| 277 | + $local_params['time_as_seconds_arr'] | |
| 278 | + ); | |
| 279 | + if ( is_wp_error( $working_time_check ) ) { | |
| 280 | + return $working_time_check; | |
| 281 | + } | |
| 282 | + } | |
| 283 | + | |
| 284 | + if ( ! empty( $local_params['appointment_service'] ) && function_exists( 'wpbc_appointment_services_check_buffer_conflicts' ) ) { | |
| 285 | + $buffer_check = wpbc_appointment_services_check_buffer_conflicts( | |
| 286 | + $local_params['appointment_service'], | |
| 287 | + $where_to_save_booking['main__resource_id'], | |
| 288 | + array_keys( $where_to_save_booking['resources_in_dates'] ), | |
| 289 | + $local_params['time_as_seconds_arr'], | |
| 290 | + $local_params['skip_booking_id'] | |
| 291 | + ); | |
| 292 | + if ( is_wp_error( $buffer_check ) ) { | |
| 293 | + return $buffer_check; | |
| 294 | + } | |
| 295 | + } | |
| 296 | + | |
| 297 | + return $where_to_save_booking; | |
| 298 | +} | |
| 299 | + | |
| 300 | + | |
| 301 | +/** | |
| 302 | + * Save Booking - ADD NEW or UPDATE exist booking | |
| 219 | 303 | * |
| 220 | 304 | * @param $request_params = [ |
| 221 | 305 | * resource_id = 2 REQUIRED Default: 1 |
| 222 | 306 | * dates_ddmmyy_csv = '27.10.2023, 28.10.2023, 29.10.2023' REQUIRED |
| @@ -521,16 +605,18 @@ | ||
| 521 | 605 | $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 522 | 606 | return array( 'ajx_data' => $ajx_data_arr ); |
| 523 | 607 | } |
| 524 | 608 | |
| 525 | - $has_verified_classic_context = true; | |
| 609 | + $has_verified_classic_context = true; | |
| 526 | 610 | $re_cleaned_params['allow_past'] = ! empty( $classic_context['allow_past'] ) ? 1 : 0; |
| 611 | + // Pass only the signed canonical set into final availability and persistence decisions. | |
| 612 | + $re_cleaned_params['aggregate_resource_id_arr'] = implode( ',', $classic_context['aggregate_resource_ids'] ); | |
| 527 | 613 | } |
| 528 | 614 | |
| 529 | 615 | if ( $is_public_booking_create_request && ! $has_verified_classic_context ) { |
| 530 | 616 | $ajx_data_arr['status'] = 'error'; |
| 531 | 617 | $ajx_data_arr['status_error'] = 'classic_booking_context_required'; |
| 532 | - $ajx_data_arr['ajx_after_action_message'] = __( 'The booking form context has expired. Please reload the page and try again.', 'booking' ); | |
| 618 | + $ajx_data_arr['ajx_after_action_message'] = wpbc_classic_booking_context_get_visitor_message( 'message_booking_form_context_required', $re_cleaned_params['resource_id'] ); | |
| 533 | 619 | $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; |
| 534 | 620 | return array( 'ajx_data' => $ajx_data_arr ); |
| 535 | 621 | } |
| 536 | 622 | |
| @@ -617,143 +703,108 @@ | ||
| 617 | 703 | // ----------------------------------------------------------------------------------------------------------------- |
| 618 | 704 | // Here GO |
| 619 | 705 | // ----------------------------------------------------------------------------------------------------------------- |
| 620 | 706 | |
| 621 | - // Force - resource saving parameters, instead of wpbc__where_to_save_booking() | |
| 622 | - if ( ! empty( $re_cleaned_params["save_booking_even_if_unavailable"] ) ) { | |
| 623 | - | |
| 624 | - $local_params['how_many_items_to_book'] = 1; | |
| 625 | - | |
| 626 | - $dates_keys_arr = array_values( $local_params['dates_only_sql_arr'] ); // [ '2023-09-23', '2023-09-24' ] | |
| 627 | - | |
| 628 | - $resources_in_dates = array_fill_keys( $dates_keys_arr , array( $local_params['initial_resource_id'] ) ); // [ 2023-09-23 = [ 2 ], 2023-09-24 = [ 2 ] ] | |
| 629 | - | |
| 630 | - $where_to_save_booking = array(); | |
| 631 | - $where_to_save_booking['result'] = 'ok'; | |
| 632 | - $where_to_save_booking['resources_in_dates'] = $resources_in_dates; // [ 2023-09-23 = [ 2, 10, 11 ], 2023-09-24 = [ 2, 10, 11 ] | |
| 633 | - $where_to_save_booking['time_to_book'] = $local_params['time_as_his_arr']; // [ "00:00:00", "24:00:00" ] | |
| 634 | - $where_to_save_booking['main__resource_id'] = $local_params['initial_resource_id']; // here edit or request (parent/single) resource | |
| 635 | - | |
| 636 | - } else { | |
| 637 | - // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > | |
| 638 | - $php_performance = wpbc_php_performance_START( 'wpbc__where_to_save_booking' , $php_performance ); | |
| 639 | - // </editor-fold> | |
| 640 | - | |
| 641 | - /** | |
| 642 | - * Get slots [] where we can save booking = [ 'resources_in_dates' => [ 2023-10-18 = [ 2, 12, 10, 11 ] | |
| 643 | - * 2023-10-19 = [ 2, 12, 10, 11 ] | |
| 644 | - * 2023-10-20 = [ 2, 12, 10, 11 ] | |
| 645 | - * ], | |
| 646 | - * 'time_to_book' => [ "14:00:01" , "12:00:01" ], | |
| 647 | - * 'result' => 'ok' | |
| 648 | - * 'main__resource_id' => 2 | |
| 649 | - * ] | |
| 650 | - * OR | |
| 651 | - * [ 'result' => 'error', 'message' => 'Booking can not be saved ...' ] | |
| 652 | - */ | |
| 653 | - $where_to_save_booking = wpbc__where_to_save_booking( array( | |
| 654 | - 'resource_id' => $local_params['initial_resource_id'], // 2 //TODO: If edit booking. What to pass 'edit' or 'parent' resource ID? | |
| 655 | - 'skip_booking_id' => $local_params['skip_booking_id'], // '', | 125 if edit booking | |
| 656 | - 'dates_only_sql_arr' => $local_params['dates_only_sql_arr'], // [ "2023-10-18", "2023-10-25", "2023-11-25" ] | |
| 657 | - 'time_as_seconds_arr' => $local_params['time_as_seconds_arr'], // [ 36000, 39600 ] | |
| 658 | - 'how_many_items_to_book' => $local_params['how_many_items_to_book'], // 1 | |
| 659 | - 'request_uri' => $re_cleaned_params['request_uri'], // 'http://beta/resource-id2/' | |
| 660 | - 'allow_past' => ! empty( $re_cleaned_params['allow_past'] ), | |
| 661 | - 'is_use_booking_recurrent_time' => $local_params['is_use_booking_recurrent_time'], // true | false | |
| 662 | - 'time_override_source' => ! empty( $local_params['time_override_arr']['source'] ) ? $local_params['time_override_arr']['source'] : '', | |
| 663 | - 'as_single_resource' => false, // false | |
| 664 | - 'aggregate_resource_id_arr' => $local_params['aggregate_resource_id_arr'], // Optional can be '' | |
| 665 | - 'aggregate_type' => $re_cleaned_params['aggregate_type'], //TODO: this parameter does not transfer during saving, so here will be always default value 'bookings_only' // FixIn: 10.0.0.7. | |
| 666 | - 'custom_form' => $re_cleaned_params['custom_form'] // FixIn: 10.0.0.10. | |
| 667 | - )); | |
| 668 | - // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- NO SLOTS TO SAVE " > | |
| 669 | - if ( 'error' == $where_to_save_booking['result'] ) { | |
| 670 | - $ajx_data_arr['status'] = 'error'; | |
| 671 | - $ajx_data_arr['status_error'] = 'booking_can_not_save'; | |
| 672 | - $ajx_data_arr['ajx_after_action_message'] = $where_to_save_booking['message']; | |
| 673 | - $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; | |
| 674 | - return array( 'ajx_data' => $ajx_data_arr ); | |
| 675 | - } | |
| 676 | - // </editor-fold> | |
| 677 | - | |
| 678 | - // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > | |
| 679 | - $php_performance = wpbc_php_performance_END( 'wpbc__where_to_save_booking' , $php_performance ); | |
| 680 | - // </editor-fold> | |
| 707 | + $availability_guard = wpbc_booking_availability_guard_acquire(); | |
| 708 | + if ( is_wp_error( $availability_guard ) ) { | |
| 709 | + $ajx_data_arr['status'] = 'error'; | |
| 710 | + $ajx_data_arr['status_error'] = $availability_guard->get_error_code(); | |
| 711 | + $ajx_data_arr['ajx_after_action_message'] = $availability_guard->get_error_message(); | |
| 712 | + $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; | |
| 713 | + | |
| 714 | + return array( 'ajx_data' => $ajx_data_arr ); | |
| 681 | 715 | } |
| 682 | 716 | |
| 683 | - if ( ! empty( $local_params['appointment_service'] ) && function_exists( 'wpbc_appointment_services_check_buffer_conflicts' ) ) { | |
| 684 | - $buffer_check = wpbc_appointment_services_check_buffer_conflicts( | |
| 685 | - $local_params['appointment_service'], | |
| 686 | - $where_to_save_booking['main__resource_id'], | |
| 687 | - array_keys( $where_to_save_booking['resources_in_dates'] ), | |
| 688 | - $local_params['time_as_seconds_arr'], | |
| 689 | - $local_params['skip_booking_id'] | |
| 690 | - ); | |
| 691 | - if ( is_wp_error( $buffer_check ) ) { | |
| 692 | - $ajx_data_arr['status'] = 'error'; | |
| 693 | - $ajx_data_arr['status_error'] = 'appointment_service_buffer_conflict'; | |
| 694 | - $ajx_data_arr['ajx_after_action_message'] = $buffer_check->get_error_message(); | |
| 695 | - $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; | |
| 696 | - return array( 'ajx_data' => $ajx_data_arr ); | |
| 697 | - } | |
| 698 | - } | |
| 717 | + $guard_revalidation_attempts = 0; | |
| 718 | + try { | |
| 719 | + while ( true ) { | |
| 720 | + wpbc_cache__clear( 'wpbc__sql__get_booking_dates' ); | |
| 721 | + $where_to_save_booking = wpbc_booking_validate_save_availability( $local_params, $re_cleaned_params, $php_performance ); | |
| 699 | 722 | |
| 723 | + if ( is_wp_error( $where_to_save_booking ) ) { | |
| 724 | + $ajx_data_arr['status'] = 'error'; | |
| 725 | + $ajx_data_arr['status_error'] = $where_to_save_booking->get_error_code(); | |
| 726 | + $ajx_data_arr['ajx_after_action_message'] = $where_to_save_booking->get_error_message(); | |
| 727 | + $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; | |
| 700 | 728 | |
| 701 | - // Get parameters, from REQUEST | |
| 702 | - $create_params = $local_params; | |
| 703 | - $create_params['resource_id'] = ( ! empty( $local_params['edit_resource_id'] ) ) | |
| 704 | - ? $local_params['edit_resource_id'] // If we edit, then use original resource ??? | |
| 705 | - : $where_to_save_booking['main__resource_id']; // Here is important TIP, resource can be where is free, and not where we submit | |
| 706 | - /** | |
| 707 | - * TODO: I think it's resolved! Just test about this situation, when we edit the booking - and it's means that we have $local_params['edit_resource_id'] | |
| 708 | - * but what, if $where_to_save_booking do not contain this $local_params['edit_resource_id'] as available resource. | |
| 709 | - * or even we have $local_params['edit_resource_id'] = 2 and $where_to_save_booking contain resources like [ 1, 2, 3, 4 ] | |
| 710 | - * we make booking for 3 slots | |
| 711 | - * in this case, main resource will be 2 | |
| 712 | - * but then when we loop resources in wpbc_db__booking_save() we will save child booking resources for dates like: 2, 3, 4 ( and it's wrong ) | |
| 713 | - * "(205, '2023-10-04 00:00:00', 0, NULL)" <- main resource '2' e.g. $local_params['edit_resource_id'] = 2 | |
| 714 | - * "(205, '2023-10-04 00:00:00', 0, 2)" ? <- child resource '2' e.g. [ .., 2, .. ] in $where_to_save_booking WHICH IS WRONG | |
| 715 | - */ | |
| 716 | - $create_params['is_emails_send'] = $re_cleaned_params['is_emails_send']; | |
| 717 | - $create_params['custom_form'] = $re_cleaned_params['custom_form']; | |
| 718 | - | |
| 719 | - make_bk_action( 'check_multiuser_params_for_client_side', $create_params['resource_id'] ); // Activate working with specific user in WP MU | |
| 720 | - | |
| 721 | - // <editor-fold defaultstate="collapsed" desc=" = PERFORMANCE = " > | |
| 722 | - $php_performance = wpbc_php_performance_START( 'wpbc_db__booking_save' , $php_performance ); | |
| 723 | - // </editor-fold> | |
| 724 | - | |
| 725 | - // ----------------------------------------------------------------------------------------------------------------- | |
| 726 | - // == CREATE_THE 'NEW_BOOKING' == | |
| 727 | - // ----------------------------------------------------------------------------------------------------------------- | |
| 728 | - $create_booking_params = array( | |
| 729 | - 'resource_id' => $create_params['resource_id'], | |
| 730 | - 'custom_form' => $create_params['custom_form'], | |
| 731 | - 'all_booking_data_arr' => $create_params['all_booking_data_arr'], | |
| 732 | - 'dates_only_sql_arr' => $create_params['dates_only_sql_arr'], | |
| 733 | - 'time_as_his_arr' => $create_params['time_as_his_arr'], | |
| 734 | - 'is_from_admin_panel' => $create_params['is_from_admin_panel'], | |
| 735 | - 'is_edit_booking' => $create_params['is_edit_booking'], | |
| 736 | - 'is_duplicate_booking' => $create_params['is_duplicate_booking'], | |
| 737 | - 'is_approve_booking' => $create_params['is_approve_booking'], | |
| 738 | - 'how_many_items_to_book' => $create_params['how_many_items_to_book'], | |
| 739 | - 'is_use_booking_recurrent_time' => $create_params['is_use_booking_recurrent_time'] // true | false | |
| 740 | - ); | |
| 741 | - if ( ! empty( $create_params['appointment_service'] ) ) { $create_booking_params['appointment_service'] = $create_params['appointment_service']; } | |
| 742 | - if ( ! empty( $create_params['sync_gid'] ) ) { $create_booking_params['sync_gid'] = $create_params['sync_gid']; } | |
| 743 | - | |
| 744 | - $booking_new_arr = wpbc_db__booking_save( $create_booking_params, $where_to_save_booking ); | |
| 745 | - | |
| 746 | - // <editor-fold defaultstate="collapsed" desc=" :: ERROR :: <- BOOKING CREATION " > | |
| 747 | - if ( 'ok' !== $booking_new_arr['status'] ) { | |
| 748 | - $ajx_data_arr['status'] = $booking_new_arr['status']; | |
| 749 | - $ajx_data_arr['status_error'] = 'booking_can_not_save'; | |
| 750 | - $ajx_data_arr['ajx_after_action_message'] = $booking_new_arr['message']; | |
| 751 | - $ajx_data_arr['ajx_after_action_message_status'] = 'error'; | |
| 752 | - return array( 'ajx_data' => $ajx_data_arr ); | |
| 729 | + return array( 'ajx_data' => $ajx_data_arr ); | |
| 730 | + } | |
| 731 | + | |
| 732 | + // Get parameters, from REQUEST. | |
| 733 | + $create_params = $local_params; | |
| 734 | + $create_params['resource_id'] = ( ! empty( $local_params['edit_resource_id'] ) ) | |
| 735 | + ? $local_params['edit_resource_id'] | |
| 736 | + : $where_to_save_booking['main__resource_id']; | |
| 737 | + $create_params['is_emails_send'] = $re_cleaned_params['is_emails_send']; | |
| 738 | + $create_params['custom_form'] = $re_cleaned_params['custom_form']; | |
| 739 | + | |
| 740 | + make_bk_action( 'check_multiuser_params_for_client_side', $create_params['resource_id'] ); | |
| 741 | + | |
| 742 | + $create_booking_params = array( | |
| 743 | + 'resource_id' => $create_params['resource_id'], | |
| 744 | + 'custom_form' => $create_params['custom_form'], | |
| 745 | + 'all_booking_data_arr' => $create_params['all_booking_data_arr'], | |
| 746 | + 'dates_only_sql_arr' => $create_params['dates_only_sql_arr'], | |
| 747 | + 'time_as_his_arr' => $create_params['time_as_his_arr'], | |
| 748 | + 'is_from_admin_panel' => $create_params['is_from_admin_panel'], | |
| 749 | + 'is_edit_booking' => $create_params['is_edit_booking'], | |
| 750 | + 'is_duplicate_booking' => $create_params['is_duplicate_booking'], | |
| 751 | + 'is_approve_booking' => $create_params['is_approve_booking'], | |
| 752 | + 'how_many_items_to_book' => $create_params['how_many_items_to_book'], | |
| 753 | + 'is_use_booking_recurrent_time' => $create_params['is_use_booking_recurrent_time'], | |
| 754 | + ); | |
| 755 | + if ( ! empty( $create_params['appointment_service'] ) ) { | |
| 756 | + $create_booking_params['appointment_service'] = $create_params['appointment_service']; | |
| 757 | + } | |
| 758 | + if ( ! empty( $create_params['sync_gid'] ) ) { | |
| 759 | + $create_booking_params['sync_gid'] = $create_params['sync_gid']; | |
| 760 | + } | |
| 761 | + | |
| 762 | + if ( ! wpbc_booking_availability_guard_is_owned( $availability_guard ) ) { | |
| 763 | + wpbc_booking_availability_guard_release( $availability_guard ); | |
| 764 | + if ( 1 <= $guard_revalidation_attempts ) { | |
| 765 | + $availability_guard = wpbc_booking_availability_guard_get_busy_error(); | |
| 766 | + } else { | |
| 767 | + ++$guard_revalidation_attempts; | |
| 768 | + $availability_guard = wpbc_booking_availability_guard_acquire(); | |
| 769 | + } | |
| 770 | + | |
| 771 | + if ( is_wp_error( $availability_guard ) ) { | |
| 772 | + $ajx_data_arr['status'] = 'error'; | |
| 773 | + $ajx_data_arr['status_error'] = $availability_guard->get_error_code(); | |
| 774 | + $ajx_data_arr['ajx_after_action_message'] = $availability_guard->get_error_message(); | |
| 775 | + $ajx_data_arr['ajx_after_action_message_status'] = 'warning'; | |
| 776 | + | |
| 777 | + return array( 'ajx_data' => $ajx_data_arr ); | |
| 778 | + } | |
| 779 | + | |
| 780 | + continue; | |
| 781 | + } | |
| 782 | + | |
| 783 | + $php_performance = wpbc_php_performance_START( 'wpbc_db__booking_save', $php_performance ); | |
| 784 | + $booking_new_arr = wpbc_db__booking_save( $create_booking_params, $where_to_save_booking ); | |
| 785 | + if ( 'ok' !== $booking_new_arr['status'] ) { | |
| 786 | + $ajx_data_arr['status'] = $booking_new_arr['status']; | |
| 787 | + $ajx_data_arr['status_error'] = 'booking_can_not_save'; | |
| 788 | + $ajx_data_arr['ajx_after_action_message'] = $booking_new_arr['message']; | |
| 789 | + $ajx_data_arr['ajx_after_action_message_status'] = 'error'; | |
| 790 | + | |
| 791 | + return array( 'ajx_data' => $ajx_data_arr ); | |
| 792 | + } | |
| 793 | + | |
| 794 | + // Appointment buffers must become visible before the serialized availability section ends. | |
| 795 | + if ( function_exists( 'wpbc_appointment_services_after_booking_save' ) ) { | |
| 796 | + wpbc_appointment_services_after_booking_save( $booking_new_arr['booking_id'], $create_booking_params, $where_to_save_booking ); | |
| 797 | + } | |
| 798 | + | |
| 799 | + break; | |
| 800 | + } | |
| 801 | + } finally { | |
| 802 | + wpbc_cache__clear( 'wpbc__sql__get_booking_dates' ); | |
| 803 | + wpbc_booking_availability_guard_release( $availability_guard ); | |
| 753 | 804 | } |
| 754 | - // </editor-fold> | |
| 755 | 805 | |
| 806 | + // Released compatibility hook: arbitrary callbacks must not extend the database lock duration. | |
| 756 | 807 | do_action( 'wpbc_booking_after_save', $booking_new_arr['booking_id'], $create_booking_params, $where_to_save_booking ); |
| 757 | 808 | |
| 758 | 809 | // FixIn: 9.9.0.36. |
| 759 | 810 | if ( |