PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
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 10.11 All 204 releases
← All changes | includes/_capacity/where_to_save.php +152 -27 10.1.311.8.4 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2
3 -if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly //FixIn: 9.8.0.4
3 +if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly // FixIn: 9.8.0.4.
4 4
5 5 // ---------------------------------------------------------------------------------------------------------------------
6 6 // Check where to save the booking
7 7 // ---------------------------------------------------------------------------------------------------------------------
@@ -6,8 +6,33 @@
6 6 // Check where to save the booking
7 7 // ---------------------------------------------------------------------------------------------------------------------
8 8
9 9 /**
10 + * Check if these dates contain marker '2981-01-13', which is means that this booking was submited without dates - as Contact Form.
11 + *
12 + * @param array|string $dates_sql_arr - array of SQL dates.
13 + *
14 + * @return bool
15 + */
16 +function wpbc_is_these_dates__for__no_dates( $dates_sql_arr ){
17 +
18 + // FixIn: 2981-01-13 13 Jan 2981.
19 +
20 + if ( is_array( $dates_sql_arr ) ) {
21 + foreach ( $dates_sql_arr as $date_ymd ) {
22 + if ( '2981-01-13' === gmdate( 'Y-m-d', mysql2date( 'U', $date_ymd ) ) ) {
23 + return true;
24 + }
25 + }
26 + } elseif ( '2981-01-13' === gmdate( 'Y-m-d', mysql2date( 'U', $dates_sql_arr ) ) ) {
27 + return true;
28 + }
29 +
30 + return false;
31 +}
32 +
33 +
34 +/**
10 35 * Get booking resources for each selected date, where we can save the booking, or false if we can not save it
11 36 *
12 37 * @param array $params = [
13 38 * 'resource_id' => 2
@@ -25,12 +50,16 @@
25 50 * = [ 'result' => 'error', 'message' => 'Booking can not be saved ...' ]
26 51 */
27 52 function wpbc__where_to_save_booking( $local_params ){
28 53
54 + $server_request_uri = ( ( isset( $_SERVER['REQUEST_URI'] ) ) ? sanitize_text_field( $_SERVER['REQUEST_URI'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */
55 + $server_http_referer_uri = ( ( isset( $_SERVER['HTTP_REFERER'] ) ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ /* FixIn: sanitize_unslash */
29 56 $defaults = array(
30 - 'request_uri' => ( ( ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) ? $_SERVER['HTTP_REFERER'] : $_SERVER['REQUEST_URI'] ), // front-end: $_SERVER['REQUEST_URI'] | ajax: $_SERVER['HTTP_REFERER'] // It different in Ajax requests. It's used for change-over days to detect for exception at specific pages
57 + 'request_uri' => ( ( ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) ? $server_http_referer_uri : $server_request_uri ), // front-end: $server_request_uri | ajax: $server_http_referer_uri // It different in Ajax requests. It's used for change-over days to detect for exception at specific pages
58 + 'allow_past' => false,
31 59 'as_single_resource' => false,
32 60 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) ),
61 + 'time_override_source' => '',
33 62 'aggregate_resource_id_arr' => array(),
34 63 'custom_form' => '' //FixIn: 10.0.0.10 // Required for checking all available time-slots and compare with booked time slots
35 64 );
36 65 $local_params = wp_parse_args( $local_params, $defaults );
@@ -45,9 +74,13 @@
45 74 $local_params['time_as_his_arr'] = array(
46 75 wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[0] ),
47 76 wpbc_transform__seconds__in__24_hours_his( $time_as_seconds_arr[1] )
48 77 );
49 -
78 + // FixIn: 2981-01-13 13 Jan 2981
79 + $availability_per_days_arr__params = array();
80 + if ( ( ! empty( $local_params['dates_only_sql_arr'] ) ) && ( is_array( $local_params['dates_only_sql_arr'] ) ) && ( '2981-01-13' === $local_params['dates_only_sql_arr'][0] ) ) {
81 + $availability_per_days_arr__params['is_days_always_available'] = true;
82 + }
50 83 // If we are using the unavailable before/after booking dates, then we need to extend "$local_params['dates_only_sql_arr']" to such dates.
51 84 if ( function_exists( 'wpbc__extend_checking_dates_range__if_used__extra_seconds__before_after' ) ) {
52 85 $maybe_extended__dates_to_check_arr = wpbc__extend_checking_dates_range__if_used__extra_seconds__before_after( $local_params['dates_only_sql_arr'] );
53 86 } else {
@@ -53,21 +86,55 @@
53 86 } else {
54 87 $maybe_extended__dates_to_check_arr = $local_params['dates_only_sql_arr'];
55 88 }
56 89 // [ "dates": [ "2023-11-05": [ "day_availability":4, ... "2": [ "is_day_unavailable":false, ...]], '2023-11-06':[...] ] ,"resources_id_arr__in_dates":[2,12,10,11]}
57 - $availability_per_days = wpbc_get_availability_per_days_arr( array(
58 - 'resource_id' => $local_params['resource_id'],
59 - 'skip_booking_id' => $local_params['skip_booking_id'],
60 - 'dates_to_check' => $maybe_extended__dates_to_check_arr,
61 - 'request_uri' => $local_params['request_uri'],
62 - 'as_single_resource' => $local_params['as_single_resource'], // default FALSE :: get dates as for 'single resource' or 'parent' resource including bookings in all 'child booking resources'
63 - 'additional_bk_types' => $local_params['aggregate_resource_id_arr'],
64 - 'aggregate_type' => $local_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
65 - 'custom_form' => $local_params['custom_form'] //FixIn: 10.0.0.10
66 - ) );
67 90
91 + $availability_per_days = wpbc_get_availability_per_days_arr( wp_parse_args( array(
92 + 'resource_id' => $local_params['resource_id'],
93 + 'skip_booking_id' => $local_params['skip_booking_id'],
94 + 'dates_to_check' => $maybe_extended__dates_to_check_arr,
95 + 'request_uri' => $local_params['request_uri'],
96 + 'allow_past' => ! empty( $local_params['allow_past'] ),
97 + 'as_single_resource' => $local_params['as_single_resource'], // default FALSE :: get dates as for 'single resource' or 'parent' resource including bookings in all 'child booking resources' .
98 + 'additional_bk_types' => $local_params['aggregate_resource_id_arr'],
99 + 'aggregate_type' => empty( $local_params['aggregate_type'] ) ? 'bookings_only' : $local_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.
100 + 'custom_form' => $local_params['custom_form'], // FixIn: 10.0.0.10.
101 + ) , $availability_per_days_arr__params ) );
102 +
103 + // A contact form has no calendar and uses one synthetic date only to satisfy the booking storage schema.
104 + // Keep its requested resource, because calendar availability rules do not apply to a no-date submission.
105 + $is_no_dates_booking = ( is_array( $local_params['dates_only_sql_arr'] ) && ( 1 === count( $local_params['dates_only_sql_arr'] ) ) &&
106 + wpbc_is_these_dates__for__no_dates( $local_params['dates_only_sql_arr'] ) );
107 + if ( $is_no_dates_booking ) {
108 + $requested_resource_id = absint( $local_params['resource_id'] );
109 + $loaded_resource_ids = isset( $availability_per_days['resources_id_arr__in_dates'] ) ? array_map( 'absint', (array) $availability_per_days['resources_id_arr__in_dates'] ) : array();
110 +
111 + if ( ( 0 === $requested_resource_id ) || ! in_array( $requested_resource_id, $loaded_resource_ids, true ) ) {
112 + return array(
113 + 'result' => 'error',
114 + 'message' => 'Wrong ID of booking resource: ' . $requested_resource_id,
115 + );
116 + }
117 +
118 + $storage_resource_ids = array_values(
119 + array_unique( array_merge( array( $requested_resource_id ), $loaded_resource_ids ) )
120 + );
121 + $resources_in_dates = array_fill_keys(
122 + array_values( $local_params['dates_only_sql_arr'] ),
123 + $storage_resource_ids
124 + );
125 +
126 + return array(
127 + 'result' => 'ok',
128 + 'resources_in_dates' => $resources_in_dates,
129 + 'time_to_book' => $local_params['time_as_his_arr'],
130 + 'main__resource_id' => $requested_resource_id,
131 + );
132 + }
133 +
68 134 // Get value of how many booking resources to book
69 135 $how_many_items_to_book = $local_params['how_many_items_to_book'];
136 +
70 137 // -------------------------------------------------------------------------------------------------------------
71 138 // [ 2023-10-18: [ 0:[ resource_id: 2, is_available: true, booked__seconds: [], booked__readable: [], time_to_book__seconds: [ 36030, 39570 ], time_to_book__readable: "10:00:00", "11:00:00" ] ], 1: [...], 2: [...], 3: [...] ], 2023-10-25: [...], 2023-11-25: [...] ]
72 139 $available_slots = wpbc__get_available_slots__for_selected_dates_times__bl( array(
73 140 'dates_sql__arr' => $local_params['dates_only_sql_arr'],
@@ -72,14 +139,15 @@
72 139 $available_slots = wpbc__get_available_slots__for_selected_dates_times__bl( array(
73 140 'dates_sql__arr' => $local_params['dates_only_sql_arr'],
74 141 'time_as_seconds_arr' => $local_params['time_as_seconds_arr'],
75 142 'is_use_booking_recurrent_time' => $local_params['is_use_booking_recurrent_time'],
143 + 'time_override_source' => $local_params['time_override_source'],
76 144 'availability_per_days' => $availability_per_days
77 145 ) );
78 146
79 147 $main__resource_id = 0;
80 148 // == In SAME 'child' booking resources ============================================================
81 - if ( 'On' === get_bk_option( 'booking_is_dissbale_booking_for_different_sub_resources' ) ) {
149 + if ( class_exists( 'wpdev_bk_biz_l' ) && ( 'On' === get_bk_option( 'booking_is_dissbale_booking_for_different_sub_resources' ) ) ) {
82 150
83 151 $availability_in_same_child_resources = $availability_per_days['resources_id_arr__in_dates'];
84 152
85 153 foreach ( $availability_per_days['resources_id_arr__in_dates'] as $child_resource_id ) {
@@ -117,26 +185,26 @@
117 185 } else {
118 186 // Bad not save
119 187 return array(
120 188 'result' => 'error',
121 - 'message' => __( 'These dates and times in this calendar are already booked or unavailable.', 'booking' )
189 + 'message' => wpbc_frontend_messages__get( 'message_dates_times_unavailable', array(), $local_params['resource_id'] )
122 190 . ' <br> '
123 - . __( 'It is not possible to store this sequence of the dates into the one same resource.' , 'booking' )
191 + . wpbc_frontend_messages__get( 'message_cannot_save_in_one_resource', array(), $local_params['resource_id'] )
124 192 . ' <br> '
125 - . __( 'Please choose alternative date(s), times, or adjust the number of slots booked.' , 'booking' )
193 + . wpbc_frontend_messages__get( 'message_choose_alternative_dates', array(), $local_params['resource_id'] )
126 194 . ' <a href="javascript:void(0)" onclick="'
127 195 .'jQuery( this ).next().toggle();'
128 196 .'jQuery( this).hide();'
129 197 .'jQuery( this ).parents(\'.wpbc_alert_message\').parent().on(\'hide\',function(even){jQuery(this).show();});'
130 198 .'">'
131 - . __( 'Show more details' )
199 + . __( 'Show more details', 'booking' )
132 200 . '</a>'
133 201 . ' <div style="display:none;">'
134 202 . '<p><hr><code>'
135 - . json_encode( $available_slots )
203 + . wp_json_encode( $available_slots )
136 204 . '</code></p>'
137 205 . '</div>'
138 - . ' <div style="display:none;">' . json_encode( $available_slots ) . '</div>'
206 + . ' <div style="display:none;">' . wp_json_encode( $available_slots ) . '</div>'
139 207 );
140 208 }
141 209
142 210 } else {
@@ -166,24 +234,26 @@
166 234 // Bad not save
167 235 // We can not store booking in this date day_sql_key2, number of available child booking resources less than required
168 236 return array(
169 237 'result' => 'error',
170 - 'message' => __( 'These dates and times in this calendar are already booked or unavailable.', 'booking' )
238 + 'message' => wpbc_frontend_messages__get( 'message_dates_times_unavailable', array(), $local_params['resource_id'] )
171 239 . ' <br> '
172 - . __( 'Please choose alternative date(s), times, or adjust the number of slots booked.' , 'booking' )
240 + . wpbc_frontend_messages__get( 'message_choose_alternative_dates', array(), $local_params['resource_id'] )
173 241 . ' <a href="javascript:void(0)" onclick="'
174 242 .'jQuery( this ).next().toggle();'
175 243 .'jQuery( this).hide();'
176 244 .'jQuery( this ).parents(\'.wpbc_alert_message\').parent().on(\'hide\',function(even){jQuery(this).show();});'
177 245 .'">'
178 - . __( 'Show more details' )
246 + . __( 'Show more details', 'booking' )
179 247 . '</a>'
180 248 . ' <div style="display:none;">'
181 249 . '<p><strong>'
182 - . sprintf( __( 'Booking can not be saved in this date %s, number of available (single or child) booking resource(s) (%d) less than required (%d).', 'booking' )
250 + /* translators: 1: ... */
251 + . sprintf( __( 'Booking can not be saved in this date %1$s, number of available (single or child) booking resource(s) (%2$d) less than required (%3$d).', 'booking' )
183 252 , $day_sql_key2, count( $available_res_in_day_arr ), $how_many_items_to_book )
184 253 . '</strong><hr><code>'
185 - . json_encode( $available_slots )
254 + . wp_json_encode( $available_slots )
255 + // . wp_json_encode( $local_params, $availability_per_days )
186 256 . '</code></p>'
187 257 . '</div>'
188 258
189 259 );
@@ -233,8 +303,9 @@
233 303 $defaults = array(
234 304 'dates_sql__arr' => array(),
235 305 'time_as_seconds_arr' => array(),
236 306 'availability_per_days' => array(),
307 + 'time_override_source' => '',
237 308 'is_use_booking_recurrent_time' => ( 'On' === get_bk_option( 'booking_recurrent_time' ) )
238 309 );
239 310 $params = wp_parse_args( $params, $defaults );
240 311
@@ -280,9 +351,9 @@
280 351 $date_bookings_obj = $params['availability_per_days']['dates'][ $sql_class_day ];
281 352
282 353 foreach ( $params['availability_per_days']['resources_id_arr__in_dates'] as $child_resource_id ) {
283 354
284 - $merged_seconds_arr = wpbc_get__booking_obj__merged_seconds_arr( $date_bookings_obj[ $child_resource_id ] );
355 + $merged_seconds_arr = wpbc_get__booking_obj__merged_seconds_arr( $date_bookings_obj[ $child_resource_id ], $params['time_override_source'] );
285 356
286 357 $is_intersect = wpbc_is_intersect__merged_seconds_arr__and__seconds_arr( $merged_seconds_arr['merged_seconds'], $this_date_time_as_seconds_arr );
287 358
288 359 $this_date_available_resource = array(
@@ -326,10 +397,24 @@
326 397 * 'merged_seconds' => $merged_seconds,
327 398 * 'merged_readable' => $merged_readable
328 399 * ]
329 400 */
330 - function wpbc_get__booking_obj__merged_seconds_arr( $date_booking_obj ) {
401 + function wpbc_get__booking_obj__merged_seconds_arr( $date_booking_obj, $time_override_source = '' ) {
331 402
403 + $is_times_availability_full_day_status = (
404 + ( 'times_availability' === $time_override_source )
405 + && ( ! empty( $date_booking_obj->is_day_unavailable ) )
406 + && ( ! empty( $date_booking_obj->_day_status ) )
407 + && ( 'full_day_booking' === $date_booking_obj->_day_status )
408 + );
409 +
410 + if ( $is_times_availability_full_day_status ) {
411 + $merged_seconds_arr = wpbc_get__booking_obj__booked_details_seconds_arr( $date_booking_obj );
412 + if ( ! empty( $merged_seconds_arr['merged_seconds'] ) ) {
413 + return $merged_seconds_arr;
414 + }
415 + }
416 +
332 417 if ( $date_booking_obj->is_day_unavailable ){
333 418 $merged_seconds = array( array( 0, 24 * 60 * 60 ) ); // Unavailable
334 419 $merged_readable = array( wpbc_transform_timerange__seconds_arr__in__formated_hours( array( 0, 24 * 60 * 60 ) ) );
335 420 } else {
@@ -340,8 +425,48 @@
340 425 return array(
341 426 'merged_seconds' => $merged_seconds,
342 427 'merged_readable' => $merged_readable
343 428 );
429 + }
430 +
431 +
432 + /**
433 + * Rebuild real booked intervals from details after capacity marks the whole day unavailable.
434 + *
435 + * @param object $date_booking_obj Availability object for a date/resource.
436 + *
437 + * @return array
438 + */
439 + function wpbc_get__booking_obj__booked_details_seconds_arr( $date_booking_obj ) {
440 +
441 + $seconds_arr = array();
442 + $readable_arr = array();
443 +
444 + if ( empty( $date_booking_obj->__booked__times__details ) || ! is_array( $date_booking_obj->__booked__times__details ) ) {
445 + return array(
446 + 'merged_seconds' => array(),
447 + 'merged_readable' => array(),
448 + );
449 + }
450 +
451 + foreach ( $date_booking_obj->__booked__times__details as $time_key => $details ) {
452 + if ( '0' === (string) $time_key || false === strpos( (string) $time_key, '-' ) ) {
453 + $seconds_arr[] = array( 0, 24 * 60 * 60 );
454 + } else {
455 + $seconds_arr[] = wpbc_transform_timerange__s_range__in__seconds_arr( $time_key );
456 + }
457 + }
458 +
459 + $seconds_arr = wpbc_merge_intersected_intervals( $seconds_arr );
460 +
461 + foreach ( $seconds_arr as $booked_time_slots__in_seconds ) {
462 + $readable_arr[] = wpbc_transform_timerange__seconds_arr__in__formated_hours( $booked_time_slots__in_seconds );
463 + }
464 +
465 + return array(
466 + 'merged_seconds' => $seconds_arr,
467 + 'merged_readable' => $readable_arr,
468 + );
344 469 }
345 470
346 471
347 472 /**