PluginProbe
Booking Calendar / 11.8.3
Booking Calendar v11.8.3
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 10.11.2 All 203 releases
booking / includes / page-bookings / bookings__sql.php

bookings__sql.php in Booking Calendar 11.8.3, at includes/page-bookings/bookings__sql.php

3,134 lines 134.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php /**
2 * @version 1.0
3 * @description Bookings Listing SQL
4 * @category Booking Listing
5 * @author wpdevelop
6 *
7 * @web-site http://oplugins.com/
8 * @email info@oplugins.com
9 *
10 * @modified 2022-04-07
11 * @file ../includes/page-bookings/bookings__sql.php
12 */
13
14 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
15
16 // <editor-fold defaultstate="collapsed" desc=" D E F A U L T R E Q U E S T " >
17
18 /**
19 * Get params names for escaping and/or default value of such params
20 *
21 * @param string $structure_type 'validate_and_default' (default) | 'validate' | 'default'
22 *
23 * @return array
24 * if $structure_type == '' array ( 'keyword' => array( 'validate' => 's', 'default' => '' )
25 * , 'wh_booking_date' => array( 'validate' => 'digit_or_date', 'default' => '3' ), ...
26 * if $structure_type == 'validate' array ( 'keyword' => 's'
27 * , 'wh_booking_date' => 'digit_or_date'), ...
28 * if $structure_type == 'default' array ( 'keyword' => '' )
29 * , 'wh_booking_date' => '3' ), ...
30 */
31 function wpbc_ajx_get__request_params__names_default( $structure_type = 'validate_and_default' ){
32
33 // Clean specific $_REQUEST params, if param is NOT set then return "default"
34 $params_for_cleaning = array(
35 // 'wh_booking_id' => array( 'validate' => 'digit_or_date', 'default' => '' ),
36
37 // 'digit_or_csd' can check about 'digit_or_csd' in arrays, as well
38 'wh_booking_type' => array( 'validate' => 'digit_or_csd', 'default' => array( '0' ) ) // if ['0'] - All booking resources, ['-1'] - lost bookings in deleted resources
39
40 , 'wh_approved' => array( 'validate' => 'digit_or_csd', 'default' => '' ) // '0' | '1' | ''
41
42 , 'wh_booking_date' => array( 'validate' => 'array', 'default' => array( "3" ) ) // array( "0" ) - Current dates, | array( "3" ) - All dates // number | date 2016-07-20
43 , 'ui_wh_booking_date_radio' => array( 'validate' => 'd', 'default' => 0 ) // '1' | '2' ....
44 , 'ui_wh_booking_date_next' => array( 'validate' => 'd', 'default' => 0 ) // '1' | '2' ....
45 , 'ui_wh_booking_date_prior' => array( 'validate' => 'd', 'default' => 0 ) // '1' | '2' ....
46 , 'ui_wh_booking_date_checkin' => array( 'validate' => 'digit_or_date', 'default' => '' ) // number | date 2016-07-20
47 , 'ui_wh_booking_date_checkout' => array( 'validate' => 'digit_or_date', 'default' => '' ) // number | date 2016-07-20
48
49 , 'wh_what_bookings' => array( 'validate' => array( 'any', 'new', 'imported', 'in_plugin' ), 'default' => 'any' ) // '1' | ''
50
51 , 'wh_modification_date' => array( 'validate' => 'array', 'default' => array( "3" ) ) // number | date 2016-07-20
52 , 'ui_wh_modification_date_radio' => array( 'validate' => 'd', 'default' => 0 ) // '1' | '2' ....
53 , 'ui_wh_modification_date_prior' => array( 'validate' => 'd', 'default' => 0 ) // '1' | '2' ....
54 , 'ui_wh_modification_date_checkin' => array( 'validate' => 'digit_or_date', 'default' => '' ) // number | date 2016-07-20
55 , 'ui_wh_modification_date_checkout' => array( 'validate' => 'digit_or_date', 'default' => '' ) // number | date 2016-07-20
56
57 , 'keyword' => array( 'validate' => 's', 'default' => '' ) //string
58
59 , 'wh_pay_status' => array( 'validate' => 'array', 'default' => array( 'all' ) )
60 , 'ui_wh_pay_status_radio' => array( 'validate' => 's', 'default' => '' ) // string
61 , 'ui_wh_pay_status_custom' => array( 'validate' => 's', 'default' => '' ) // string
62
63 , 'wh_cost' => array( 'validate' => 'float_or_empty', 'default' => '' ) // '1' | ''
64 , 'wh_cost2' => array( 'validate' => 'float_or_empty', 'default' => '' ) // '1' | ''
65
66 , 'wh_sort' => array( 'validate' => array(
67 'booking_id__asc',
68 'booking_id__desc',
69 'dates__asc',
70 'dates__desc',
71 'resource__asc',
72 'resource__desc',
73 'cost__asc',
74 'cost__desc'
75 ), 'default' => 'booking_id__desc' )
76 , 'wh_trash' => array( 'validate' => array( '0', 'trash', 'any' ), 'default' => 'any' )
77
78 , 'page_num' => array( 'validate' => 'd', 'default' => 1 ) // '1' | ''
79 , 'page_items_count' => array( 'validate' => 'd', 'default' => 10 ) // '1' | ''
80
81 , 'ui_usr__send_emails' => array( 'validate' => array( 'send', 'not_send' ), 'default' => 'send' )
82 , 'ui_usr__is_expand_remarks' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' )
83 , 'ui_usr__default_selected_toolbar' => array( 'validate' => array( 'filters', 'actions', 'options' ), 'default' => 'filters' )
84
85 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
86 , 'ui_reset' => array( 'validate' => 's', 'default' => '' ) // string
87 , 'ui_usr__dates_short_wide' => array( 'validate' => array( 'short', 'wide' ), 'default' => 'short' )
88 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
89 , 'view_days_num' => array( 'validate' => 'd', 'default' => 30 ) // '1' | '' // FixIn: 8.9.2.1.
90 , 'scroll_start_date' => array( 'validate' => 'digit_or_date', 'default' => '' ) // number | date 2016-07-20
91 , 'scroll_day' => array( 'validate' => 'd', 'default' => 0 ) // '1' | ''
92 , 'scroll_month' => array( 'validate' => 'd', 'default' => 0 ) // '1' | ''
93 , 'limit_hours' => array( 'validate' => 'digit_or_csd', 'default' => '' ) //
94 , 'only_booked_resources' => array( 'validate' => 'd', 'default' => 0 ) // '1' | ''
95
96 );
97
98 /**
99 * Filter the Booking Listing request schema before values are sanitized.
100 *
101 * Extensions may add narrowly scoped listing filters without duplicating the
102 * saved-user-request or AJAX sanitization pipeline.
103 *
104 * @param array<string,array<string,mixed>> $params_for_cleaning Request validation and default definitions.
105 * @param string $structure_type Requested schema representation.
106 */
107 $params_for_cleaning = apply_filters( 'wpbc_booking_listing_request_params_schema', $params_for_cleaning, $structure_type );
108
109 if ( 'validate_and_default' == $structure_type ) {
110 return $params_for_cleaning;
111 }
112
113 $return_simple_arr = array();
114
115 foreach ( $params_for_cleaning as $key => $value ) {
116 $return_simple_arr[ $key ] = $value[ $structure_type ];
117 }
118 return $return_simple_arr;
119 }
120
121 // </editor-fold>
122
123
124 // <editor-fold defaultstate="collapsed" desc=" S A V E U S E R R E Q U E S T " >
125
126 /**
127 * Save user filter request - saving user filters in toolbar
128 *
129 * @param array $params
130 * @param integer $user_id
131 *
132 * @return bool|int
133 */
134 function wpbc_ajx__user_request_params__save( $params, $user_id ) {
135
136 // Reset some parameters, like selected page
137 if ( isset( $params['page_num'] ) ) {
138 $params['page_num'] = 1;
139 $params['keyword'] = '';
140 }
141
142 return update_user_option( (int) $user_id, 'booking_listing_request_params' , $params );
143 }
144
145 /**
146 * Delete saved user request - used for resetting user filters in toolbar
147 * @param integer $user_id
148 *
149 * @return bool
150 */
151 function wpbc_ajx__user_request_params__delete( $user_id ) {
152
153 if ( empty( $user_id ) ) {
154 $user_id = wpbc_get_current_user_id();
155 }
156
157 return delete_user_option( (int) $user_id, 'booking_listing_request_params' );
158 }
159
160 /**
161 * Get saved user filter request - params for user filters in toolbar
162 *
163 * @param integer $user_id
164 *
165 * @return false|mixed
166 */
167 function wpbc_ajx__user_request_params__get( $user_id ) {
168
169 if ( empty( $user_id ) ) {
170 $user_id = wpbc_get_current_user_id();
171 }
172
173 // wpbc_ajx__user_request_params__delete($user_id); //For debugging. delete it.
174
175 return get_user_option( 'booking_listing_request_params', (int) $user_id );
176 }
177
178 /**
179 * Get sanitized array of use request parameters that was saved before
180 *
181 * @param $user_id int
182 *
183 * @return array|false
184 */
185 function wpbc_ajx__user_request_params__get_sanitized( $user_id ) {
186
187 $request_params_values_arr = wpbc_ajx__user_request_params__get( $user_id ); // - $request_params_values_arr - unserialized here automatically
188
189 if ( false !== $request_params_values_arr ) {
190
191 $request_params_structure = wpbc_ajx_get__request_params__names_default(); /**
192 * array( 'page_num' => array( 'validate' => 'd', 'default' => 1 )
193 * , 'page_items_count' => array( 'validate' => 'd', 'default' => 10 )
194 * , 'sort' => array( 'validate' => array( 'booking_id' ), 'default' => 'booking_id' )
195 * , 'sort_type' => array( 'validate' => array( 'ASC', 'DESC'),'default' => 'DESC' )
196 * , 'keyword' => array( 'validate' => 's', 'default' => '' )
197 * , 'create_date' => array( 'validate' => 'date', 'default' => '' )
198 * )
199 */
200
201 $escaped_request_params = wpbc_sanitize_params_in_arr( $request_params_values_arr, $request_params_structure ); // Escaping params here
202
203
204 return $escaped_request_params;
205 } else {
206 return false;
207 }
208 }
209
210 /**
211 * Get user saved option from Request in Booking Listing
212 *
213 * @param $user_id int 1
214 * @param $option_name string 'ui_usr__send_emails'
215 *
216 * @return false|mixed
217 */
218 function wpbc_ajx__user_request_params__get_option( $user_id, $option_name ){
219
220 // Get User saved option from request
221 $escaped_request_params = wpbc_ajx__user_request_params__get_sanitized( $user_id );
222 if ( ( ! empty( $escaped_request_params ) ) && ( ! empty( $escaped_request_params[ $option_name ] ) ) ) {
223 return $escaped_request_params[ $option_name ];
224 }
225
226 // Get default option
227 $default_param_values = wpbc_ajx_get__request_params__names_default( 'default' );
228 if ( ! empty( $default_param_values[ $option_name ] ) ) {
229 return $default_param_values[ $option_name ];
230 }
231
232 // There is no such option
233 return false;
234 }
235
236
237 /**
238 * Is send emails ? Check DB SAVED user defined option from Options toolbar.
239 * @param $user_id int ID of user
240 *
241 * @return int 1 | 0
242 */
243 function wpbc_ajx__user_request_option__is_send_emails( $user_id ){
244
245 $is_send_emeils = wpbc_ajx__user_request_params__get_option( $user_id, 'ui_usr__send_emails' );
246
247 $is_send_emeils = ( 'send' == $is_send_emeils ) ? 1 : 0;
248
249 return $is_send_emeils;
250 }
251
252 /**
253 * Is expand remarks by default ? Check DB SAVED user defined option from Options toolbar.
254 *
255 * It's useful only, when we are checking during Ajax action requests, where need to check data in Database,
256 * For templates, need to use JavaScript:
257 * <# if ( 'Off' === wpbc_ajx_booking_listing.search_get_param('ui_usr__is_expand_remarks') ) { #>display: none;<# } #>
258 *
259 *
260 * @param $user_id int ID of user
261 *
262 * @return int 1 | 0
263 */
264 function wpbc_ajx__user_request_option__is_expand_remarks( $user_id ){
265
266 $is_send_emeils = wpbc_ajx__user_request_params__get_option( $user_id, 'ui_usr__is_expand_remarks' );
267
268 $is_send_emeils = ( 'On' == $is_send_emeils ) ? 1 : 0;
269
270 return $is_send_emeils;
271 }
272
273
274 // </editor-fold>
275
276
277 // <editor-fold defaultstate="collapsed" desc=" S Q L " >
278
279
280 /**
281 * Get array of bookings and total number of items in all pages.
282 *
283 * @param array $request_params = Array(
284 [wh_booking_id] =>
285 [wh_booking_type] =>
286 [booking_type] =>
287 [wh_approved] =>
288 [wh_booking_date] =>
289 [wh_booking_date2] =>
290 [wh_booking_datenext] => 0
291 [wh_booking_dateprior] => 0
292 [wh_booking_datefixeddates] =>
293 [wh_booking_date2fixeddates] =>
294 [wh_is_new] => 0
295 [wh_modification_date] =>
296 [wh_modification_date2] =>
297 [wh_modification_dateprior] => 0
298 [wh_modification_datefixeddates] =>
299 [wh_modification_date2fixeddates] =>
300 [wh_pay_statuscustom] =>
301 [wh_pay_status] =>
302 [wh_cost] => 0
303 [wh_cost2] => 0
304 [wh_sort] =>
305 [wh_trash] =>
306 [page_num] => 1
307 [page_items_count] => 10
308 [view_days_num] => 30
309 [scroll_start_date] =>
310 [scroll_day] => 0
311 [scroll_month] => 0
312 [limit_hours] =>
313 [only_booked_resources] => 0
314 )
315 *
316 * @return array = Array(
317 [count] => 14
318 [data_arr] => Array (
319 [0] => Array (
320 [ajx_booking_id] => 14
321 [last_check_booking_id] => 0
322 [status] =>
323 [last_run_date] =>
324 [booking] => Array (
325 [email_template] => super_new
326 [conditions] => Array (
327 [0] => Array (
328 [if] => __system__|source
329 [sign] => >=
330 [value] => 1"0'0\0
331 )
332 ), ...
333 )
334 [ru_create_date] => 2020-01-25 10:36:55
335 ...
336 ), ...
337 */
338 function wpbc_ajx_get_booking_data_arr( $request_params ){
339
340 // 1. Get booking resources (sql)
341 $resources_arr = wpbc_ajx_get_all_booking_resources_arr(); /**
342 * Array ( [0] => Array ( [booking_type_id] => 1
343 [title] => Standard
344 [users] => 1
345 [import] =>
346 [export] =>
347 [cost] => 25
348 [default_form] => standard
349 [prioritet] => 0
350 [parent] => 0
351 [visitors] => 2
352 ), ... */
353
354 $resources_arr_sorted = wpbc_ajx_get_sorted_booking_resources_arr( $resources_arr );
355
356 // 2. Get all bookings (sql)
357 $bookings = wpbc_ajx_get__bookings_obj__sql( $request_params ); /**
358 * Array ( [count] => 172, [bookings] => Array (
359 * [0] => stdClass Object (
360 [booking_id] => 175
361 [trash] => 0
362 [sync_gid] =>
363 [is_new] => 1
364 [status] =>
365 [sort_date] => 2022-04-19 12:00:01
366 [modification_date] => 2022-04-03 08:05:13
367 [form] => selectbox-one^rangetime5^12:00 - 14:00~text^name5^test data~ ... ~checkbox^term_and_condition5[]^I Accept terms
368 [hash] => ae964965356f7c735139764eebe12a63
369 [booking_type] => 5
370 [remark] =>
371 [cost] => 50.00
372 [pay_status] => 164896951360.82
373 [pay_request] => 0
374 ), ....
375 */
376 $bookings_obj = $bookings['bookings'];
377 $bookings_count = $bookings['count'];
378
379
380 // 3. Get booking dates (sql)
381 $booking_dates_obj = wpbc_ajx_get__booking_dates_obj__sql( $bookings_obj ); /**
382 * Array ( [0] => stdClass Object (
383 [booking_dates_id] => 333
384 [booking_id] => 165
385 [booking_date] => 2022-03-28 11:00:01
386 [approved] => 0
387 [type_id] =>
388 )
389 [1] => ....
390 */
391
392
393 // 4. Include dates into bookings (Wide and Short dates view)
394 $bookings_with_dates = wpbc_ajx_include_bookingdates_in_the_bookings( $bookings_obj, $booking_dates_obj );
395 /**
396 Array ( [182] => stdClass Object (
397
398 [booking_db] => stdClass Object (
399 [booking_id] => 182
400 [trash] => 0
401 [sync_gid] =>
402 [is_new] => 1
403 [status] =>
404 [sort_date] => 2023-01-23 10:00:01
405 [modification_date] => 2022-04-18 12:23:30
406 [form] => selectbox-one^rangetime2^10:00 - 12:00~text^name2^rr~text^secondname2^hjk~email^email2^hyui@nbco.csdf~text^phone2^h~text^address2^khj~text^city2^e~text^postcode2^hj~selectbox-one^country2^HT~selectbox-one^visitors2^1~selectbox-one^children2^0~textarea^details2^djkh~checkbox^term_and_condition2[]^I Accept term and conditions
407 [hash] => a1ae510d8fee961b7f8ae53101632151
408 [booking_type] => 2
409 [remark] =>
410 [cost] => 75.00
411 [pay_status] => 165028101080.84
412 [pay_request] => 0
413 )
414 [id] => 182
415 [approved] => 0
416 [dates] => Array (
417 [0] => 2023-01-23 10:00:01
418 [1] => 2023-01-25 00:00:00
419 [2] => 2023-01-27 12:00:02
420 )
421 [child_id] => Array (
422 [0] =>
423 [1] =>
424 [2] =>
425 )
426 [short_dates] => Array (
427 [0] => 2023-01-23 10:00:01
428 [1] => ,
429 [2] => 2023-01-25 00:00:00
430 [3] => ,
431 [4] => 2023-01-27 12:00:02
432 )
433 [short_dates_child_id] => Array (
434 [0] =>
435 [1] =>
436 [2] =>
437 [3] =>
438 [4] =>
439 )
440 )
441 [181] => stdClass Object ...
442 */
443
444 // 4.5 remove some bookings, that does not fit to Dates conditions
445 list( $bookings_with_dates, $bookings_count ) = wpbc_ajx_get__remove_bookings__where_dates_outside( $request_params, $bookings_with_dates, $bookings_count );
446
447 // 5. Parse forms
448 $parsed_bookings = wpbc_ajx_parse_bookings( $bookings_with_dates, $resources_arr );
449 /** array( [188] => stdClass Object (
450 [booking_db] => stdClass Object (
451 [booking_id] => 188
452 [trash] => 0
453 [sync_gid] =>
454 [is_new] => 1
455 [status] =>
456 [sort_date] => 2023-03-05 10:00:01
457 [modification_date] => 2022-04-19 11:58:31
458 [form] => text^selected_short_dates_hint4^March 5, 2023~text^days_number_hint4^1~text^cost_hint4^&amp;#36;95~selectbox-one^rangetime4^10:00 - 12:00~text^name4^test~email^email4^test@wpbookingcalendar.com~selectbox-one^my_select4^1~selectbox-multiple^multi_select4[]^0,1,2,3~checkbox^my_checkbx4[]^false~checkbox^my_multi_checkbx4[]^1~checkbox^my_multi_checkbx4[]^~checkbox^my_multi_checkbx4[]^3~checkbox^exclusive_multi_checkbx4^~checkbox^exclusive_multi_checkbx4^2~checkbox^exclusive_multi_checkbx4^~radio^my_radio4^2~selectbox-one^country4^GB~textarea^details4^s~checkbox^term_and_condition4[]^I Accept term and conditions
459 [hash] => dd12c3a61f14aaca693f52d110d2723a
460 [booking_type] => 4
461 [remark] =>
462 [cost] => 95.00
463 [pay_status] => 165036591118.88
464 [pay_request] => 0 )
465 [id] => 188
466 [approved] => 0
467 [dates] => Array ( [0] => 2023-03-05 10:00:01 [1] => 2023-03-05 12:00:02 )
468 [child_id] => Array([0] => [1] => )
469 [short_dates] => Array ( [0] => 2023-03-05 10:00:01 [1] => - [2] => 2023-03-05 12:00:02 )
470 [short_dates_child_id] => Array ( [0] => [1] => [2] => )
471 [form_data] => Array
472 (
473 [selected_short_dates_hint] => March 5, 2023
474 [days_number_hint] => 1
475 [cost_hint] => &amp;#36;95
476 [rangetime] => 10:00 AM - 12:00 PM
477 [name] => test
478 ...
479 [term_and_condition] => I Accept term and conditions
480 [booking_id] => 188
481 [trash] => 0
482 [sync_gid] =>
483 [is_new] => 1
484 [status] =>
485 [sort_date] => 2023-03-05 10:00:01
486 [modification_date] => 2022-04-19 11:58:31
487 [hash] => dd12c3a61f14aaca693f52d110d2723a
488 [booking_type] => 4
489 [cost] => 95.00
490 [pay_status] => 165036591118.88
491 [pay_request] => 0
492 [id] => 188
493 [approved] => 0
494 [resource_title] => Apartment#3
495 [_form_show] => "<div class="payment-content-form"><strong>Times</strong>:<span class="fieldvalue">10:00 AM - 12:00 PM</span>&nbsp;&nbsp; ...."
496 )
497 ...
498 */
499
500 // Reset array keys for correct DESC sorting during sending Ajax request.
501 $parsed_bookings = array_values( $parsed_bookings );
502
503 return array(
504 'booking_resources' => $resources_arr_sorted, //$resources_arr,
505 'data_arr' => $parsed_bookings,
506 'count' => $bookings_count
507 );
508 }
509
510 /**
511 * R E S O U R C E S - Get SORTED booking resources as array
512 *
513 * @param $resources_arr array Array ( [1] => Array (
514 [booking_type_id] => 1
515 [title] => Standard
516 [users] => 1
517 [import] =>
518 [export] =>
519 [cost] => 25
520 [default_form] => standard
521 [prioritet] => 0
522 [parent] => 0
523 [visitors] => 2
524 ), ...
525 *
526 * @return array
527 */
528 function wpbc_ajx_get_sorted_booking_resources_arr( $resources_arr ) {
529
530 if ( ! empty( $resources_arr ) ) {
531 $resources_arr_sorted = wpbc_ajx_arrange_booking_resources_arr( $resources_arr );
532 $resources_arr_sorted = $resources_arr_sorted['linear_resources'];
533 foreach ( $resources_arr_sorted as $key_id => $resource ) {
534 $resources_arr_sorted[ $key_id ]['title'] = wpbc_lang( $resources_arr_sorted[ $key_id ]['title'] );
535 }
536 // Reset keys for having correct sorting (important for parent/child resources) after ajax response
537 $resources_arr_sorted = array_values( $resources_arr_sorted );
538 } else {
539 $resources_arr_sorted = $resources_arr;
540 }
541
542 return $resources_arr_sorted;
543 }
544
545
546 /**
547 * R E S O U R C E S - Get all booking resources as array
548 *
549 * @return array Array ( [1] => Array (
550 [booking_type_id] => 1
551 [title] => Standard
552 [users] => 1
553 [import] =>
554 [export] =>
555 [cost] => 25
556 [default_form] => standard
557 [prioritet] => 0
558 [parent] => 0
559 [visitors] => 2
560 ), ...
561 */
562 function wpbc_ajx_get_all_booking_resources_arr( ){
563
564 if ( ! class_exists( 'wpdev_bk_personal' ) ) {
565 return array();
566 }
567
568 $db_names = wpbc_get_db_names();
569
570 $sql = array();
571
572 $sql['select'] = "SELECT * FROM {$db_names['resources']} as bt";
573
574 $sql['where'] = " WHERE ( 1 = 1 )";
575
576 if ( class_exists( 'wpdev_bk_multiuser' ) ) { // MultiUser - only specific booking resources for specific Regular User in Admin panel.
577
578 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
579 if ( isset( $_REQUEST['wpbc_ajx_user_id'] ) ) {
580 $user_bk_id = intval( $_REQUEST['wpbc_ajx_user_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
581 } else {
582 $user_bk_id = wpbc_get_current_user_id();
583 }
584 $is_user_super_admin = apply_bk_filter( 'is_user_super_admin', $user_bk_id );
585
586 if ( ! $is_user_super_admin ) {
587 $sql['where'] .= 'AND users = ' . $user_bk_id . ' ';
588 }
589 }
590
591 // Order depends from version // FixIn: 9.9.0.23.
592 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
593 $sql['order'] = " ORDER BY parent, prioritet, title, booking_type_id";
594 } else {
595 $sql['order'] = " ORDER BY title, booking_type_id";
596 }
597
598 global $wpdb;
599 $sql_prepared = //$wpdb->prepare(
600 $sql['select']
601 . $sql['where']
602 . $sql['order'];
603 // , $sql['sql_args']
604 // );
605 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
606 $resources = $wpdb->get_results( $sql_prepared );
607
608 $resources_arr = array();
609
610 foreach ( $resources as $resource ) {
611 $resources_arr[ $resource->booking_type_id ] = get_object_vars( $resource );
612 }
613
614 return $resources_arr;
615 }
616
617
618 /**
619 * Get arranged / sorted booking resources arrays
620 *
621 * @param $resources_sql_arr array( ...
622 * [4] => Array (
623 [booking_type_id] => 4
624 [title] => Apartment#3
625 [users] => 1
626 [import] =>
627 [export] =>
628 [cost] => 270
629 [default_form] => standard
630 [prioritet] => 1
631 [parent] => 0
632 [visitors] => 1
633 )
634 [5] => Array (
635 [booking_type_id] => 5
636 [title] => Standard-1
637 [users] => 1
638 [import] =>
639 [export] =>
640 [cost] => 25
641 [default_form] => standard
642 [prioritet] => 1
643 [parent] => 1
644 [visitors] => 1
645 )
646 ...
647 */
648 function wpbc_ajx_arrange_booking_resources_arr( $all_resources ){
649
650 if ( count( $all_resources ) > 0 ) {
651
652 $resources = array();
653 $child_resources = array();
654 $parent_single_resources = array();
655
656 foreach ( $all_resources as $single_resources ) {
657
658 $single_resources = $single_resources ;
659 $single_resources['id'] = $single_resources['booking_type_id'];
660
661 // Child booking resource
662 if ( ( ! empty( $single_resources[ 'parent' ] ) )
663 ){ // Child
664
665 if ( ! isset( $child_resources[ $single_resources['parent'] ] ) )
666 $child_resources[ $single_resources['parent'] ] = array();
667
668 $child_resources[ $single_resources['parent'] ][ $single_resources['id'] ] = $single_resources;
669
670 } else { // Parent or Single
671
672 $parent_single_resources[ $single_resources['id'] ] = $single_resources;
673 }
674 // All resources
675 $resources[ $single_resources['id'] ] = $single_resources;
676 }
677
678
679 $final_resource_array = array();
680 foreach ( $parent_single_resources as $key => $res) {
681
682 // Calc Capacity
683 if ( isset( $child_resources[$res['id']] ) ) $res['count'] = count( $child_resources[$res['id']] ) + 1;
684 else $res['count'] = 1;
685
686 // Fill the parent resource
687 $final_resource_array[ $res['id'] ] = $res;
688
689 // Fill all child resources (its already sorted) - for having linear array with child resourecs.
690 if ( isset( $child_resources[ $res['id'] ] ) ) {
691 foreach ( $child_resources[ $res['id'] ] as $child_obj ) {
692 $child_obj['count'] = 1;
693 $final_resource_array[ $child_obj['id'] ] = $child_obj;
694 }
695 }
696 }
697
698 return array(
699 'linear_resources' => $final_resource_array
700 , 'single_or_parent' => $parent_single_resources
701 , 'child' => $child_resources
702 );
703 } else {
704 return false;
705 }
706 }
707
708
709 /**
710 * S Q L - B O O K I N G S - Get array of "Bookings" objects from DB
711 * based on request params
712 *
713 * @param array $request_params
714 *
715 * @return array of bookings sql objects
716 */
717 function wpbc_ajx_get__bookings_obj__sql( $request_params ) {
718
719 $defaults = wpbc_ajx_get__request_params__names_default( 'default' );
720
721 $params = wp_parse_args( $request_params, $defaults );
722
723 global $wpdb;
724 $db_names = wpbc_get_db_names();
725
726 $sql_args = array();
727 $sql = array();
728
729
730 $sql['start_select'] = " SELECT * ";
731 $sql['start_count'] = " SELECT COUNT(*) as count";
732 $sql['from'] = " FROM {$db_names['bookings']} as bk";
733
734 $sql['where'] = " WHERE ( 1 = 1 )";
735
736 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
737 // DATES
738 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
739 $sql['where'] .= " AND ( EXISTS (
740 SELECT *
741 FROM {$db_names['dates']} as dt
742 WHERE bk.booking_id = dt.booking_id ";
743
744 // W H E R E : Approved | Pending ----------------------------------------------------------------------
745 if ( $request_params['wh_approved'] !== '' ) {
746 $sql['where'] .= " AND approved = {$request_params['wh_approved']} ";
747 }
748
749 // W H E R E : D A T E S --------------------------------------------------------------------------------
750 if (1){
751 if ( is_array( $request_params['wh_booking_date'] ) ) {
752 $wh_booking_date = array_replace( array( '', '' ), $request_params['wh_booking_date'] ); // Always have minimum 2 values in arr
753 } else {
754 $wh_booking_date = array( '', '' );
755 }
756
757 if ( count( $wh_booking_date ) > 2 ) {
758 $removed_el = array_shift( $wh_booking_date ); // Remove an element off the beginning of array
759 }
760 }
761 $sql['where'] .= wpbc_ajx__sql_where_for_dates( (string) $wh_booking_date[0], (string) $wh_booking_date[1] );
762
763 $sql['where'] .= " )
764 )";
765 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
766
767
768 // W H E R E : M o d i f i c a t i o n D A T E S --------------------------------------------------
769 if (1){
770 if ( is_array( $request_params['wh_modification_date'] ) ) {
771 $wh_modification_date = array_replace( array( '', '' ), $request_params['wh_modification_date'] ); // Always have minimum 2 values in arr
772 } else {
773 $wh_modification_date = array( '', '' );
774 }
775
776 if ( count( $wh_modification_date ) > 2 ) {
777 $removed_el = array_shift( $wh_modification_date ); // Remove an element off the beginning of array
778 }
779 }
780 $sql['where'] .= wpbc_ajx__sql_where_for_modification_date( (string) $wh_modification_date[0], (string) $wh_modification_date[1] );
781
782
783
784 // W H E R E : Resources ------------------------------------------------------------------------------
785 if ( class_exists( 'wpdev_bk_personal' ) ) {
786
787 if ( ! empty( $request_params['wh_booking_type'] ) ) {
788
789 $sql['where'] .= wpbc_ajx__sql_where_for_resources(
790 $request_params['wh_booking_type'],
791 $request_params['wh_approved'],
792 (string) $wh_booking_date[0],
793 (string) $wh_booking_date[1]
794 );
795 }
796 }
797
798
799 // W H E R E : Payment Status -------------------------------------------------------------------------
800 if ( class_exists( 'wpdev_bk_biz_s' ) ) {
801
802 if ( ! empty( $request_params['wh_pay_status'] ) ) {
803
804 $sql_and_args = wpbc_ajx__sql_where_for_payment_status( $request_params['wh_pay_status'] );
805
806 $sql['where'] .= $sql_and_args[0];
807
808 if ( count( $sql_and_args[1] ) > 0 ) {
809 foreach ( $sql_and_args[1] as $my_arg ) {
810 $sql_args[] = $my_arg;
811 }
812 }
813
814 }
815 }
816
817
818 // W H E R E : C o s t Min - Max -------------------------------------------------------------------
819 if ( class_exists( 'wpdev_bk_biz_s' ) ) {
820
821 if ( ( isset( $request_params['wh_cost'] ) )
822 || ( isset( $request_params['wh_cost2'] ) ) ) {
823
824 $wh_cost_min = ( isset( $request_params['wh_cost'] ) ) ? $request_params['wh_cost'] : '';
825 $wh_cost_max = ( isset( $request_params['wh_cost2'] ) ) ? $request_params['wh_cost2'] : '';
826
827 $sql_and_args = wpbc_ajx__sql_where_cost_min_max( $wh_cost_min, $wh_cost_max );
828
829 $sql['where'] .= $sql_and_args[0];
830
831 if ( count( $sql_and_args[1] ) > 0 ) {
832 foreach ( $sql_and_args[1] as $my_arg ) {
833 $sql_args[] = $my_arg;
834 }
835 }
836
837 }
838 }
839
840
841
842 // W H E R E : Trash -----------------------------------------------------------------------------------
843 if ( isset( $request_params['wh_trash'] ) ) {
844
845 if ( '0' === $request_params['wh_trash'] ) { // Existing
846 $sql['where'] .= " AND bk.trash = 0 ";
847 }
848
849 if ( 'trash' === $request_params['wh_trash'] ) { // In trash
850 $sql['where'] .= " AND bk.trash = 1 ";
851 }
852
853 //if ( 'any' === $request_params['wh_trash'] ) { } // Any
854 }
855
856
857 // W H E R E : All bookings | New bookings | Imported bookings | Plugin bookings
858 if ( isset( $request_params['wh_what_bookings'] ) ) {
859
860 if ( 'any' === $request_params['wh_what_bookings'] ) {
861 //$sql['where'] .= " AND bk.is_new = 0 ";
862 }
863 if ( 'new' === $request_params['wh_what_bookings'] ) {
864 $sql['where'] .= " AND bk.is_new = 1";
865 }
866 if ( 'imported' === $request_params['wh_what_bookings'] ) {
867 $sql['where'] .= " AND bk.sync_gid != '' ";
868 }
869 if ( 'in_plugin' === $request_params['wh_what_bookings'] ) {
870 $sql['where'] .= " AND bk.sync_gid = '' ";
871 }
872 }
873
874
875 // W H E R E : K E Y W O R D
876 if ( ! empty( $params['keyword'] ) ) {
877 $sql['where'] .= " AND ( ";
878
879 /**
880 * Relative configuration of LIKE sanitization
881 * check at the bottom here https://code.tutsplus.com/articles/data-sanitization-and-validation-with-wordpress--wp-25536
882 *
883 * So this is a correct way:
884 *
885 * $sql['where'] .= "( bk.form LIKE %s ) ";
886 * $sql_args[] = '%' . $wpdb->esc_like( $params['keyword'] ) . '%';
887 *
888 */
889
890 $sql['where'] .= "( bk.form LIKE %s ) ";
891 $sql_args[] = '%' . $wpdb->esc_like( $params['keyword'] ) . '%';
892
893 if ( is_numeric( $params['keyword'] ) ) {
894 $sql['where'] .= " OR ( bk.booking_id = %d ) ";
895 $sql_args[] = intval( $params['keyword'] );
896 }
897
898 $sql['where'] .= " OR ( bk.sync_gid LIKE %s ) ";
899 $sql_args[] = '%' . $wpdb->esc_like( $params['keyword'] ) . '%';
900
901 if ( class_exists( 'wpdev_bk_personal' ) ) {
902 $sql['where'] .= " OR ( bk.remark LIKE %s ) ";
903 $sql_args[] = '%' . $wpdb->esc_like( $params['keyword'] ) . '%';
904
905 $sql['where'] .= " OR ( bk.hash LIKE %s ) ";
906 $sql_args[] = '%' . $wpdb->esc_like( $params['keyword'] ) . '%';
907 }
908
909 $sql['where'] .= " )";
910
911
912 // W H E R E : booking ID // FixIn: 9.4.3.9.
913 $is_id = strpos( trim( strtolower( $params['keyword'] ) ) , 'id:' ); // Keyword, like 'id:200' OR 'id:100,105'
914 if ( 0 === $is_id ){
915
916 $search_booking_id = substr( trim( $params['keyword'] ), 3 );
917 $search_booking_id_arr = explode( ',', $search_booking_id ); // Get array of booking ID: from 'id:200,201,15' we get [200,201,15]
918
919 $sql_where_arr = array();
920 $sql_args = array(); // It's last WHERE in a list so all previous arguments ($sql_args) we are resetting
921
922 foreach ( $search_booking_id_arr as $bk_id ) {
923
924 $sql_where_arr[] = ' bk.booking_id = %d ';
925 $sql_args[] = intval( $bk_id );
926 }
927
928 $sql['where'] = " WHERE ( " . implode( ' OR ', $sql_where_arr ) . ") ";
929
930 $sql['where'] = apply_bk_filter('update_where_sql_for_getting_bookings_in_multiuser', $sql['where'] ); // Add 'AND bk.booking_type IN ( $user_resources )' to the end of Where
931 }
932 }
933
934 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
935
936 /**
937 * Filter the prepared Booking Listing WHERE fragment and its placeholders.
938 *
939 * The base query has already applied dates, resources, MultiUser ownership,
940 * status, cost, and keyword rules. Additions must return the same two keys.
941 *
942 * @param array{where:string,args:array<int,mixed>} $query_parts WHERE SQL and prepare arguments.
943 * @param array<string,mixed> $request_params Sanitized listing request.
944 * @param array<string,mixed> $params Request merged with defaults.
945 */
946 $query_parts = apply_filters(
947 'wpbc_booking_listing_sql_query_parts',
948 array(
949 'where' => $sql['where'],
950 'args' => $sql_args,
951 ),
952 $request_params,
953 $params
954 );
955 if ( is_array( $query_parts ) && isset( $query_parts['where'], $query_parts['args'] ) && is_string( $query_parts['where'] ) && is_array( $query_parts['args'] ) ) {
956 $sql['where'] = $query_parts['where'];
957 $sql_args = $query_parts['args'];
958 }
959
960
961 switch ( $params['wh_sort'] ) {
962 case 'booking_id__asc':
963 $order_by = 'booking_id ASC ';
964 break;
965 case 'booking_id__desc':
966 $order_by = 'booking_id DESC ';
967 break;
968 case 'dates__asc':
969 $order_by = 'sort_date ASC ';
970 break;
971 case 'dates__desc':
972 $order_by = 'sort_date DESC ';
973 break;
974 case 'resource__asc':
975 $order_by = 'booking_type ASC ';
976 break;
977 case 'resource__desc':
978 $order_by = 'booking_type DESC ';
979 break;
980 case 'cost__asc':
981 $order_by = 'cost ASC ';
982 break;
983 case 'cost__desc':
984 $order_by = 'cost DESC ';
985 break;
986 default:
987 $order_by = 'booking_id ASC ';
988 }
989 $sql['order'] = " ORDER BY bk." . $order_by; // $sql['order'] = " ORDER BY bk." . esc_sql( $params['sort'] ) . ( ( 'DESC' == $params['sort_type'] ) ? " DESC " : " ASC " );
990
991 $sql_args_count = $sql_args; // For SELECT COUNT(*) as count we do not need other parameters
992
993 $sql['limit'] = " LIMIT %d, %d ";
994
995 $sql_args[] = ( $params['page_num'] - 1 ) * $params['page_items_count'];
996 $sql_args[] = $params['page_items_count'];
997
998
999
1000 /**
1001 * Good Practice: https://blog.ircmaxell.com/2017/10/disclosure-wordpress-wpdb-sql-injection-technical.html
1002 * fixed in WordPress 4.8.3
1003 *
1004 $where = "WHERE foo = %s";
1005 $args = [$_GET['data']];
1006 $args[] = 1;
1007 $args[] = 2;
1008 $query = $wpdb->prepare("SELECT * FROM something $where LIMIT %d, %d", $args);
1009 *
1010 */
1011
1012 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
1013 // SELECT at this specific PAGE /////////////////////////////////////////////////////////////////
1014 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
1015 /* phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */
1016 $sql_prepared = $wpdb->prepare( $sql['start_select'] . $sql['from'] . $sql['where'] . $sql['order'] . $sql['limit'], $sql_args );
1017 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
1018 $bookings_sql_obj = $wpdb->get_results( $sql_prepared );
1019
1020
1021 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
1022 // COUNT of items with this WHERE ///////////////////////////////////////////////////////////////////
1023 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
1024 $sql_for_listing_count = $sql['start_count']
1025 . $sql['from']
1026 . $sql['where'];
1027
1028 if ( false === strpos( $sql_for_listing_count, '%' ) ) {
1029
1030 $sql_prepared = $sql_for_listing_count;
1031
1032 } else {
1033 /* phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare */
1034 $sql_prepared = $wpdb->prepare( $sql_for_listing_count, $sql_args_count );
1035 }
1036 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
1037 $bookings_count = $wpdb->get_results( $sql_prepared );
1038 $bookings_count = ( ( count( $bookings_count ) > 0 ) ? $bookings_count[0]->count : 0 );
1039
1040 return array(
1041 'count' => $bookings_count
1042 , 'bookings' => $bookings_sql_obj
1043 );
1044 }
1045
1046 // W H E R E C O N D I T I O N S
1047
1048 /**
1049 * Get SQL W H E R E conditions for D a t e s of bookings
1050 *
1051 * @param string $wh_booking_date - Parameter from Booking Listing request (usually its number)
1052 * @param string $wh_booking_date2 - Parameter from Booking Listing request (usually its number)
1053 * @param string $pref - Optional. Prefix for table.
1054 * @return string - WHERE conditions for SQL
1055 */
1056 function wpbc_ajx__sql_where_for_dates( $wh_booking_date, $wh_booking_date2, $pref = 'dt.' ) {
1057
1058 $wh_booking_date = (string) $wh_booking_date;
1059 $wh_booking_date2 = (string) $wh_booking_date2;
1060
1061 $sql_where= '';
1062 if ($pref == 'dt.') { $and_pre = ' AND '; $and_suf = ''; }
1063 else { $and_pre = ''; $and_suf = ' AND '; }
1064
1065 // Actual
1066 if ( ( ( $wh_booking_date === '' ) && ( $wh_booking_date2 === '' ) ) || ($wh_booking_date === '0') ) {
1067 $sql_where = $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL '00:00:01' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.5.2.14.
1068
1069 } else if ($wh_booking_date === '1') { // Today // FixIn: 7.1.2.8.
1070 $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL '23:59:59' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ;
1071 $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL '00:00:01' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.4.7.21.
1072
1073
1074 } else if ($wh_booking_date === '2') { // Previous
1075 $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL '00:00:01' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.5.2.16.
1076
1077 } else if ($wh_booking_date === '3') { // All
1078 $sql_where = '';
1079
1080 } else if ($wh_booking_date === '4') { // Next
1081 $wh_booking_date2 = intval( $wh_booking_date2 ); // FixIn: 10.14.16.1.
1082 $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL ". $wh_booking_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ;
1083 // $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1084 $sql_where .= $and_pre."( ".$pref."booking_date > ( " . wpbc_sql_date_math_expr_explicit('', 'curdate') . " ) ) ".$and_suf ; // FixIn: 8.0.1.1.
1085
1086 } else if ($wh_booking_date === '5') { // Prior
1087 $wh_booking_date2 = str_replace('-', '', $wh_booking_date2);
1088 $wh_booking_date2 = intval( $wh_booking_date2 ); // FixIn: 10.14.16.1.
1089 $sql_where = $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL ". $wh_booking_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ;
1090 $sql_where .= $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1091
1092 } else if ($wh_booking_date === '7') { // Check In date - Today/Tomorrow
1093 $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL '47:59:59' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ;
1094 $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1095
1096 } else if ($wh_booking_date === '8') { // Check Out date - Tomorrow
1097 $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL '47:59:59' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ;
1098 $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1099
1100 } else if ( ( $wh_booking_date === '9' ) || ( $wh_booking_date === '10' ) || ( $wh_booking_date === '11' ) ) { // Today check in/out
1101 $sql_where = $and_pre."( ".$pref."booking_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1102 $sql_where .= $and_pre."( ".$pref."booking_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1103
1104 } else { // Fixed
1105
1106 $wh_booking_date = wpbc_sanitize_date( $wh_booking_date );
1107 $wh_booking_date2 = wpbc_sanitize_date( $wh_booking_date2 );
1108
1109 /*
1110 if ( $wh_booking_date !== '' ){
1111 $sql_where .= $and_pre . "( " . $pref . "booking_date >= ( '" . $wh_booking_date . "' - INTERVAL '00:00:01' HOUR_SECOND ) ) " . $and_suf;
1112 }
1113 if ( $wh_booking_date2 !== '' ) {
1114 $sql_where .= $and_pre . "( " . $pref . "booking_date <= ( '" . $wh_booking_date2 . "' + INTERVAL '23:59:59' HOUR_SECOND ) ) " . $and_suf;
1115 }
1116 */
1117
1118 if ( $wh_booking_date !== '' ) {
1119 if ( strpos( $wh_booking_date, ':' ) === false ) {
1120 $sql_where .= $and_pre . "( " . $pref . "booking_date >= '" . $wh_booking_date . " 00:00:00' ) " . $and_suf;
1121 } else {
1122 $sql_where .= $and_pre . "( " . $pref . "booking_date >= '" . $wh_booking_date . "' ) " . $and_suf;
1123 }
1124 }
1125
1126 if ( $wh_booking_date2 !== '' ) {
1127 if ( strpos( $wh_booking_date2, ':' ) === false ) {
1128 $sql_where .= $and_pre . "( " . $pref . "booking_date <= '" . $wh_booking_date2 . " 23:59:59' ) " . $and_suf;
1129 } else {
1130 $sql_where .= $and_pre . "( " . $pref . "booking_date <= '" . $wh_booking_date2 . "' ) " . $and_suf;
1131 }
1132 }
1133
1134
1135 }
1136
1137 return $sql_where;
1138 }
1139
1140
1141 /**
1142 * Get SQL W H E R E conditions for M o d i f i c a t i o n D a t e of bookings
1143 *
1144 * @param string $wh_modification_date - Parameter from Booking Listing request (usually its number)
1145 * @param string $wh_modification_date2 - Parameter from Booking Listing request (usually its number)
1146 * @param string $pref - Optional. Prefix for table.
1147 * @return string - WHERE conditions for SQL
1148 */
1149 function wpbc_ajx__sql_where_for_modification_date( $wh_modification_date, $wh_modification_date2, $pref = 'bk.' ) {
1150
1151 $sql_where = '';
1152
1153 if ($pref == 'bk.') { $and_pre = ' AND '; $and_suf = ''; }
1154 else { $and_pre = ''; $and_suf = ' AND '; }
1155
1156 if ($wh_modification_date === '1') { // Today
1157 $sql_where = $and_pre."( ".$pref."modification_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL '23:59:59' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.4.7.22.
1158 $sql_where .= $and_pre."( ".$pref."modification_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL '00:00:01' HOUR_SECOND", 'curdate' ) . ") ) ".$and_suf ; // FixIn: 8.4.7.22.
1159
1160 } else if ($wh_modification_date === '3') { // All
1161 $sql_where = '';
1162
1163 } else if ($wh_modification_date === '5') { // Prior
1164 $wh_modification_date2 = str_replace('-', '', $wh_modification_date2);
1165 $wh_modification_date2 = intval( $wh_modification_date2 ); // FixIn: 10.14.16.1.
1166 $sql_where = $and_pre."( ".$pref."modification_date >= (" . wpbc_sql_date_math_expr_explicit( "- INTERVAL ". $wh_modification_date2 . " DAY", 'curdate' ) . ") ) ".$and_suf ;
1167 $sql_where .= $and_pre."( ".$pref."modification_date <= (" . wpbc_sql_date_math_expr_explicit( "+ INTERVAL 1 DAY", 'curdate' ) . ") ) ".$and_suf ;
1168
1169 } else { // Fixed
1170
1171 $wh_modification_date = wpbc_sanitize_date( $wh_modification_date ); // FixIn: 9.4.4.1.
1172 $wh_modification_date2 = wpbc_sanitize_date( $wh_modification_date2 );
1173
1174 if ( $wh_modification_date !== '' )
1175 $sql_where.= $and_pre."( ".$pref."modification_date >= ( '" . $wh_modification_date . "' - INTERVAL '00:00:01' HOUR_SECOND ) ) ".$and_suf;
1176
1177 if ( $wh_modification_date2 !== '' )
1178 $sql_where.= $and_pre."( ".$pref."modification_date <= ( '" . $wh_modification_date2 . "' + INTERVAL '23:59:59' HOUR_SECOND ) ) ".$and_suf;
1179 }
1180
1181 return $sql_where;
1182 }
1183
1184
1185 /**
1186 * Get SQL W H E R E conditions for B o o k i n g R e s o u r c e s
1187 *
1188 * @param $wh_booking_type
1189 * @param $wh_approved
1190 * @param $wh_booking_date
1191 * @param $wh_booking_date2
1192 *
1193 * @return string - SQL
1194 */
1195 function wpbc_ajx__sql_where_for_resources( $wh_booking_type, $wh_approved, $wh_booking_date, $wh_booking_date2 ){
1196 global $wpdb;
1197
1198 if ( ! class_exists( 'wpdev_bk_personal' ) ) {
1199 return '';
1200 }
1201
1202 if ( is_array( $wh_booking_type ) ) {
1203 $wh_booking_type = implode( ',', $wh_booking_type );
1204 }
1205
1206 $sql_where = '';
1207
1208 if ( '0' === $wh_booking_type ) { // All booking resources
1209 // Get all booking resources of this user
1210 $resources_sql_arr = wpbc_ajx_get_all_booking_resources_arr();
1211 $wh_booking_type = implode( ',', array_keys( $resources_sql_arr ) );
1212 //$resources_arr = wpbc_ajx_arrange_booking_resources_arr( $resources_sql_arr );
1213 }
1214
1215 if ( '-1' === $wh_booking_type ) { // Lost booking resources
1216
1217 $is_show_lost = true;
1218
1219 if ( class_exists( 'wpdev_bk_multiuser' ) ) { // MultiUser - Only for super booking admin user
1220
1221 $user_bk_id = ( isset( $_REQUEST['wpbc_ajx_user_id'] ) ) ? intval( $_REQUEST['wpbc_ajx_user_id'] ) : wpbc_get_current_user_id(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
1222
1223 $is_user_super_admin = apply_bk_filter( 'is_user_super_admin', $user_bk_id );
1224
1225 if ( ! $is_user_super_admin ) {
1226 $is_show_lost = false; // For regular user show all bookings from the booking resources that belong to this user.
1227 $sql_where .= " AND bk.booking_type IN ( SELECT DISTINCT booking_type_id FROM {$wpdb->prefix}bookingtypes WHERE users = " . $user_bk_id . " ) ";
1228 }
1229 }
1230
1231 // "Lost" bookings in deleted booking resources
1232 if ( $is_show_lost ) {
1233 $sql_where .= " AND bk.booking_type NOT IN ( SELECT DISTINCT booking_type_id FROM {$wpdb->prefix}bookingtypes ) ";
1234 }
1235
1236 } else if ( ! empty( $wh_booking_type ) ) {
1237 // P
1238 $sql_where .= " AND ( ";
1239 $sql_where .= " ( bk.booking_type IN ( " . $wh_booking_type . " ) ) ";
1240
1241 // BL - Show bookings from child booking resources, if was selected only parent booking resource
1242 $is_show_bookings_for_child_resources = true;
1243 if ( $is_show_bookings_for_child_resources ) {
1244 $sql_where .= wpbc_ajx__sql_where_for_resources_bl( $wh_booking_type, $wh_approved, $wh_booking_date, $wh_booking_date2 );
1245 }
1246
1247 // P
1248 $sql_where .= " ) ";
1249
1250 // MU - Check if searching bookings are belongs to specific user in Booking Calendar MultiUser version
1251 $sql_where = apply_bk_filter( 'update_where_sql_for_getting_bookings_in_multiuser', $sql_where );
1252 }
1253
1254 return $sql_where;
1255 }
1256
1257
1258 /**
1259 * Get SQL W H E R E conditions for B o o k i n g R e s o u r c e s BL - Capacity
1260 *
1261 * @param $wh_booking_type
1262 * @param $wh_approved
1263 * @param $wh_booking_date
1264 * @param $wh_booking_date2
1265 *
1266 * @return string - SQL
1267 */
1268 function wpbc_ajx__sql_where_for_resources_bl( $wh_booking_type, $wh_approved, $wh_booking_date, $wh_booking_date2 ){
1269
1270 if ( ! class_exists( 'wpdev_bk_biz_l' ) ) {
1271 return '';
1272 }
1273
1274 global $wpdb;
1275 $sql_where = '';
1276
1277 // BL // Childs in dif sub resources
1278 $sql_where.= " OR ( bk.booking_id IN (
1279 SELECT DISTINCT booking_id
1280 FROM {$wpdb->prefix}bookingdates as dtt
1281 WHERE " ;
1282 if ($wh_approved !== '')
1283 $sql_where.= " dtt.approved = $wh_approved AND " ;
1284 $sql_where .= wpbc_ajx__sql_where_for_dates( $wh_booking_date, $wh_booking_date2, 'dtt.' );
1285
1286 $sql_where.= " (
1287 dtt.type_id IN ( ". $wh_booking_type ." )
1288 OR dtt.type_id IN (
1289 SELECT booking_type_id
1290 FROM {$wpdb->prefix}bookingtypes as bt
1291 WHERE bt.parent IN ( ". $wh_booking_type ." )
1292 )
1293 )
1294 )
1295 ) " ;
1296
1297 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
1298 if ( ( isset($_REQUEST['tab']) ) && ( $_REQUEST['tab']== 'vm_calendar' ) ) {
1299
1300 // Skip the bookings from the children resources, if we are in the Calendar view mode at the admin panel
1301
1302 } else {
1303 // BL // Just children booking resources
1304 $sql_where .= " OR ( bk.booking_type IN (
1305 SELECT booking_type_id
1306 FROM {$wpdb->prefix}bookingtypes as bt
1307 WHERE bt.parent IN ( " . $wh_booking_type . " )
1308 )
1309 )";
1310 }
1311
1312 return $sql_where;
1313 }
1314
1315
1316 /**
1317 * Get SQL W H E R E conditions for P a y m e n t S t a t u s
1318 *
1319 * @param $wh_pay_status [ 'any ' ] | ['group_ok'] | ['group_unknown' ] | ['group_pending'] | ['group_failed'] | [ 'user_entered', 'myCustom status' ]
1320 *
1321 * @return array [ string SQL, array ARGS ]
1322 */
1323 function wpbc_ajx__sql_where_for_payment_status( $wh_pay_status_arr ){
1324
1325 // [ 'any ' ] | ['group_ok'] | ['group_unknown' ] | ['group_pending'] | ['group_failed'] | [ 'user_entered', 'myCustom status' ]
1326
1327 $wh_pay_status_custom = '';
1328 $wh_pay_status = '';
1329
1330 if ( ! empty( $wh_pay_status_arr ) ) {
1331
1332 if ( count( $wh_pay_status_arr ) > 1 ) {
1333 $wh_pay_status_custom = $wh_pay_status_arr[1];
1334 }
1335 $wh_pay_status = $wh_pay_status_arr[0];
1336 }
1337
1338 $sql_where = '';
1339 $sql_args = array();
1340
1341 if ( ( '' != $wh_pay_status ) && ( 'all' != $wh_pay_status ) ) {
1342
1343 $sql_where .= " AND ( ";
1344
1345 // Check firstly if we are selected some goup of payment status
1346 if ( $wh_pay_status == 'group_ok' ) { // SUCCESS
1347
1348 $payment_status = wpbc_get_payment_status_ok();
1349
1350 foreach ( $payment_status as $label ) {
1351 $sql_where .= " ( bk.pay_status = '" . $label . "' ) OR";
1352 }
1353 $sql_where = substr( $sql_where, 0, - 2 );
1354
1355 } else if ( ( $wh_pay_status == 'group_unknown' ) || ( is_numeric( $wh_pay_status_custom ) ) ) { // UNKNOWN
1356
1357 $payment_status = wpbc_get_payment_status_unknown();
1358 foreach ( $payment_status as $label ) {
1359 $sql_where .= " ( bk.pay_status = '" . $label . "' ) OR";
1360 }
1361 //$sql_where = substr($sql_where, 0, -2);
1362 $sql_where .= " ( bk.pay_status = '' ) OR ( bk.pay_status regexp '^[0-9]') ";
1363
1364 } else if ( $wh_pay_status == 'group_pending' ) { // Pending
1365
1366 $payment_status = wpbc_get_payment_status_pending();
1367 foreach ( $payment_status as $label ) {
1368 $sql_where .= " ( bk.pay_status = '" . $label . "' ) OR";
1369 }
1370 $sql_where = substr( $sql_where, 0, - 2 );
1371
1372 } else if ( $wh_pay_status == 'group_failed' ) { // Failed
1373
1374 $payment_status = wpbc_get_payment_status_error();
1375 foreach ( $payment_status as $label ) {
1376 $sql_where .= " ( bk.pay_status = '" . $label . "' ) OR";
1377 }
1378 $sql_where = substr( $sql_where, 0, - 2 );
1379
1380 } else { // CUSTOM Payment Status
1381 $sql_where .= " bk.pay_status = %s ";
1382
1383 // $wh_pay_status_custom = htmlspecialchars_decode( $wh_pay_status_custom ); // ? Convert special HTML entities back to characters: "&#60; - &#62;" to "< - >"
1384 $sql_args[] = $wh_pay_status_custom;
1385 }
1386
1387 $sql_where .= " ) ";
1388 }
1389
1390 return array( $sql_where, $sql_args );
1391 }
1392
1393
1394 /**
1395 * Get SQL W H E R E conditions for C o s t Min - Max
1396 *
1397 * @param $wh_cost_min '' or number
1398 * @param $wh_cost_max '' or number
1399 *
1400 * @return array [ string SQL, array ARGS ]
1401 */
1402 function wpbc_ajx__sql_where_cost_min_max( $wh_cost_min, $wh_cost_max ) {
1403
1404 $sql_where = '';
1405 $sql_args = array();
1406
1407 if ( $wh_cost_min !== '' ) {
1408 $sql_where .= " AND ( bk.cost >= %f ) ";
1409 $sql_args[] = $wh_cost_min;
1410 }
1411 if ( $wh_cost_max !== '' ) {
1412 $sql_where .= " AND ( bk.cost <= %f ) ";
1413 $sql_args[] = $wh_cost_max;
1414 }
1415
1416 return array( $sql_where, $sql_args );
1417
1418 }
1419
1420
1421 /**
1422 * D A T E S - Get array of "Booking Dates" objects from DB
1423 * relative to specific bookings - array of Bookings objects from DB
1424 *
1425 * @param array of object $bookings_sql_obj
1426 *
1427 * @return array of booking dates sql objects
1428 */
1429 function wpbc_ajx_get__booking_dates_obj__sql( $bookings_sql_obj ){
1430
1431 global $wpdb;
1432 $db_names = wpbc_get_db_names();
1433
1434 // Get list of booking ID from bookings obj ///////////////////////////////////////////////////////////////
1435 $booking_id_list = array();
1436 foreach ( $bookings_sql_obj as $booking ) {
1437 $booking_id_list[] = intval( $booking->booking_id );
1438 }
1439 $booking_id_list = array_unique( $booking_id_list ); // remove duplicates
1440 $booking_id_list = implode( ",", $booking_id_list );
1441 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
1442
1443
1444 if ( ! empty( $booking_id_list ) ) { // Get Dates for all our Bookings
1445
1446 $sql = "SELECT *
1447 FROM {$db_names['dates']} as dt
1448 WHERE dt.booking_id in ( {$booking_id_list} ) ";
1449
1450 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
1451 $sql .= " ORDER BY booking_id, type_id, booking_date ";
1452 } else {
1453 $sql .= " ORDER BY booking_id, booking_date ";
1454 }
1455 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
1456 $booking_dates_sql_obj = $wpdb->get_results( $sql );
1457 } else {
1458 $booking_dates_sql_obj = array();
1459 }
1460
1461 return $booking_dates_sql_obj;
1462 }
1463
1464
1465 /**
1466 * S Q L - B O O K I N G S - Get array of "Bookings" objects from DB
1467 * based on request params
1468 *
1469 * @param array $request_params
1470 * @param array of object $bookings_sql_obj
1471 *
1472 * @return array of array( booking dates, $bookings_count) array( sql objects, int )
1473 */
1474 function wpbc_ajx_get__remove_bookings__where_dates_outside($request_params, $bookings_obj, $bookings_count){
1475
1476 $is_id = strpos( trim( strtolower( $request_params['keyword'] ) ) , 'id:' );
1477 if ( false !== $is_id ) {
1478 return array( $bookings_obj, $bookings_count );
1479 }
1480 // W H E R E : D A T E S --------------------------------------------------------------------------------
1481 if (1){
1482 if ( is_array( $request_params['wh_booking_date'] ) ) {
1483 $wh_booking_date_arr = array_replace( array( '', '' ), $request_params['wh_booking_date'] ); // Always have minimum 2 values in arr
1484 } else {
1485 $wh_booking_date_arr = array( '', '' );
1486 }
1487
1488 if ( count( $wh_booking_date_arr ) > 2 ) {
1489 $removed_el = array_shift( $wh_booking_date_arr ); // Remove an element off the beginning of array
1490 }
1491 }
1492
1493 $wh_booking_date = (string) $wh_booking_date_arr[0];
1494 $wh_booking_date2 =(string) $wh_booking_date_arr[1];
1495
1496 // Check In date - Tomorrow
1497 if ( $wh_booking_date === '7' ) {
1498
1499 $today_mysql_format = date_i18n( 'Y-m-d', time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) + DAY_IN_SECONDS ); // Tommorow day with gmt offset
1500 foreach ( $bookings_obj as $bc_id => $bc_value ) {
1501 $check_in_date = $bc_value->short_dates[0];
1502 $check_in_date = explode( ' ', $check_in_date );
1503 $check_in_date = $check_in_date[0]; // 2014-02-25
1504 if ( $today_mysql_format != $check_in_date ) {
1505 unset( $bookings_obj[ $bc_id ] );
1506 $bookings_count--;
1507 }
1508 }
1509 }
1510
1511 // Check Out date - Tomorrow
1512 if ( $wh_booking_date === '8' ) {
1513
1514 $tomorrow_mysql_format = date_i18n( 'Y-m-d', time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) + DAY_IN_SECONDS ); // Tommorow day with gmt offset
1515 foreach ( $bookings_obj as $bc_id => $bc_value ) {
1516 if ( 1 == count( $bc_value->short_dates ) ) {
1517 $check_out_date = $bc_value->short_dates[0];
1518 } else {
1519 $check_out_date = $bc_value->short_dates[2];
1520 }
1521 $check_out_date = explode( ' ', $check_out_date );
1522 $check_out_date = $check_out_date[0]; // 2014-02-25
1523 if ( $tomorrow_mysql_format != $check_out_date ) {
1524 unset( $bookings_obj[ $bc_id ] );
1525 $bookings_count --;
1526 }
1527 }
1528 }
1529
1530 // Today == check in/out | Today = Check in | Today = Check out
1531 if ( ( $wh_booking_date === '9' ) || ( $wh_booking_date === '10' ) || ( $wh_booking_date === '11' ) ) {
1532
1533 $today_mysql_format = date_i18n( 'Y-m-d', time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) + 0 * DAY_IN_SECONDS ); // Today day with gmt offset
1534
1535 foreach ( $bookings_obj as $bc_id => $bc_value ) {
1536
1537 $check_in_date = $bc_value->short_dates[0];
1538 $check_in_date = explode( ' ', $check_in_date );
1539 $check_in_date = $check_in_date[0]; // 2014-02-25
1540
1541 if ( count( $bc_value->short_dates ) == 1 ) {
1542 $check_out_date = $bc_value->short_dates[0];
1543 } else {
1544 $check_out_date = $bc_value->short_dates[2];
1545 }
1546 $check_out_date = explode( ' ', $check_out_date );
1547 $check_out_date = $check_out_date[0]; // 2014-02-25
1548
1549 // Check In
1550 if ( $wh_booking_date === '10' ) {
1551 if ( $today_mysql_format != $check_in_date ) {
1552 unset( $bookings_obj[ $bc_id ] );
1553 $bookings_count --;
1554 }
1555 }
1556 // Check out
1557 if ( $wh_booking_date === '11' ) {
1558 if ( $today_mysql_format != $check_out_date ) {
1559 unset( $bookings_obj[ $bc_id ] );
1560 $bookings_count --;
1561 }
1562 }
1563 // Check In | Check out // FixIn: 9.6.3.12.
1564 if ( $wh_booking_date === '9' ) {
1565 if ( ( $today_mysql_format != $check_in_date ) && ( $today_mysql_format != $check_out_date ) ) {
1566 unset( $bookings_obj[ $bc_id ] );
1567 $bookings_count --;
1568 }
1569 }
1570
1571 }
1572 }
1573
1574 return array( $bookings_obj, $bookings_count );
1575 }
1576
1577 /**
1578 * Get array of bookings with dates (wide and short dates view)
1579 * after inserting dates into the bookings
1580 *
1581 * @param $bookings_obj Array (
1582 [0] => stdClass Object (
1583 [booking_id] => 182
1584 [trash] => 0
1585 [sync_gid] =>
1586 [is_new] => 1
1587 [status] =>
1588 [sort_date] => 2023-01-23 10:00:01
1589 [modification_date] => 2022-04-18 12:23:30
1590 [form] => selectbox-one^rangetime2^10:00 - 12:00~text^name2^rr~text^secondname2^hjk~email^email2^hyui@nbco.csdf~text^phone2^h~text^address2^khj~text^city2^e~text^postcode2^hj~selectbox-one^country2^HT~selectbox-one^visitors2^1~selectbox-one^children2^0~textarea^details2^djkh~checkbox^term_and_condition2[]^I Accept term and conditions
1591 [hash] => a1ae510d8fee961b7f8ae53101632151
1592 [booking_type] => 2
1593 [remark] =>
1594 [cost] => 75.00
1595 [pay_status] => 165028101080.84
1596 [pay_request] => 0
1597 )
1598 [1] => stdClass Object, ....
1599 * @param $booking_dates_obj Array (
1600 [0] => stdClass Object (
1601 [booking_dates_id] => 294
1602 [booking_id] => 147
1603 [booking_date] => 2022-06-27 12:00:01
1604 [approved] => 0
1605 [type_id] =>
1606 )
1607 [1] => stdClass Object, ...
1608 *
1609 * @return array Array (
1610 * [182] => stdClass Object (
1611 * ... many other props ....
1612 * [id] => 182
1613 * [approved] => 0
1614 * [dates] => Array (
1615 * [0] => 2023-01-23 10:00:01
1616 * [1] => 2023-01-25 00:00:00
1617 * [2] => 2023-01-27 12:00:02
1618 * )
1619 * [child_id] => Array (
1620 * [0] =>
1621 * [1] =>
1622 * [2] =>
1623 * )
1624 * [short_dates] => Array (
1625 * [0] => 2023-01-23 10:00:01
1626 * [1] => ,
1627 * [2] => 2023-01-25 00:00:00
1628 * [3] => ,
1629 * [4] => 2023-01-27 12:00:02
1630 * )
1631 * [short_dates_child_id] => Array (
1632 * [0] =>
1633 * [1] =>
1634 * [2] =>
1635 * [3] =>
1636 * [4] =>
1637 * )
1638 * )
1639 * [181] => stdClass Object (
1640 * ....
1641 */
1642 function wpbc_ajx_include_bookingdates_in_the_bookings( $bookings_obj, $booking_dates_obj ){
1643
1644 $bookings_arr = array();
1645 foreach ( $bookings_obj as $booking ) {
1646
1647 $bookings_arr[$booking->booking_id] = new StdClass;
1648 $bookings_arr[$booking->booking_id]->booking_db = $booking;
1649 $bookings_arr[$booking->booking_id]->id = $booking->booking_id;
1650 $bookings_arr[$booking->booking_id]->approved = 0;
1651 $bookings_arr[$booking->booking_id]->dates = array();
1652 $bookings_arr[$booking->booking_id]->child_id = array();
1653 /*
1654 $resource_id = (isset( $booking->booking_type )) ? $booking->booking_type : '1';
1655
1656 // booking Form parse can be here
1657
1658
1659 if ( ( isset( $booking->sync_gid ) ) && (!empty( $booking->sync_gid )) ) {
1660 $booking->form .= "~text^sync_gid{$booking->booking_type}^{$booking->sync_gid}";
1661 }
1662
1663 $cont = wpbc__legacy__get_form_content_arr( $booking->form
1664 , $resource_id
1665 , ''
1666 , array(
1667 'booking_id' => $booking->booking_id
1668 , 'resource_title' => (isset( $booking_types[$booking->booking_type] )) ? $booking_types[$booking->booking_type] : ''
1669 )
1670 );
1671 $search = array( "'(<br[ ]?[/]?>)+'si", "'(<[/]?p[ ]?>)+'si" );
1672 $replace = array( "&nbsp;&nbsp;", " &nbsp; ", " &nbsp; " );
1673 $cont['content'] = preg_replace( $search, $replace, $cont['content'] );
1674 //debuge( htmlentities( $cont['content'] ) );die;
1675 $bookings_arr[$booking->booking_id]->form_show = $cont['content'];
1676 unset( $cont['content'] );
1677 $bookings_arr[$booking->booking_id]->form_data = $cont;
1678
1679 /**/
1680 }
1681
1682 // Wide dates in bookings
1683 foreach ( $booking_dates_obj as $date ) {
1684 $bookings_arr[ $date->booking_id ]->approved = $date->approved;
1685
1686 $bookings_arr[ $date->booking_id ]->dates[] = $date->booking_date;
1687 $bookings_arr[ $date->booking_id ]->child_id[] = ( isset( $date->type_id ) ) ? $date->type_id : '';
1688 }
1689
1690 // Short dates
1691 foreach ( $bookings_arr as $booking_id => $booking ) {
1692
1693 if ( count( $booking->dates ) == 0 ) { continue; } // If no dates, then skip
1694
1695 $bookings_arr[ $booking_id ]->short_dates = array( $booking->dates[0] ); // First Day
1696 $bookings_arr[ $booking_id ]->short_dates_child_id = array( $bookings_arr[ $booking_id ]->child_id[0] );
1697 $previous = array(
1698 'date' => $booking->dates[0],
1699 'date_index' => 0,
1700 'separator' => false
1701 );
1702
1703 if ( count( $booking->dates ) == 1 ) { continue; } // if 1 date, then skip
1704
1705
1706 for ( $date_indx = 1; $date_indx < ( count( $booking->dates ) ); $date_indx ++ ) { // Start from 2nd day
1707
1708 $date = $booking->dates[ $date_indx ];
1709
1710 // if ( wpbc_is_next_day( $date, $previous['date'] ) ) {
1711 $next_day_if__check_in__then__check_out = true;
1712 if ( wpbc_is_less_than_next_day( $date, $previous['date'], $next_day_if__check_in__then__check_out ) ) {
1713
1714 if ( '-' != $previous['separator'] ) {
1715 $bookings_arr[ $booking_id ]->short_dates[] = '-';
1716 $bookings_arr[ $booking_id ]->short_dates_child_id[] = '';
1717 }
1718 $previous['separator'] = '-';
1719
1720 } else {
1721
1722 if ( '-' == $previous['separator'] ) {
1723
1724 $bookings_arr[ $booking_id ]->short_dates[] = $previous['date'];
1725 $bookings_arr[ $booking_id ]->short_dates_child_id[] = $bookings_arr[ $booking_id ]->child_id[ $previous['date_index'] ];
1726 }
1727 $bookings_arr[ $booking_id ]->short_dates[] = ',';
1728 $bookings_arr[ $booking_id ]->short_dates_child_id[] = '';
1729
1730 $bookings_arr[ $booking_id ]->short_dates[] = $date;
1731 $bookings_arr[ $booking_id ]->short_dates_child_id[] = $bookings_arr[ $booking_id ]->child_id[ $date_indx ];
1732
1733 $previous['separator'] = ',';
1734 }
1735
1736 $previous['date'] = $date;
1737 $previous['date_index'] = $date_indx;
1738
1739 } // dates loop: $date_indx => $date
1740
1741 if ( '-' == $previous['separator'] ) {
1742 $bookings_arr[ $booking_id ]->short_dates[] = $previous['date'];
1743 $bookings_arr[ $booking_id ]->short_dates_child_id[] = $bookings_arr[ $booking_id ]->child_id[ $previous['date_index'] ];
1744 }
1745
1746 } // bookings loop: $booking_id => $booking
1747
1748 return $bookings_arr;
1749 }
1750
1751
1752 /**
1753 * Build an empty Booking Listing Resource-allocation DTO.
1754 *
1755 * A stable empty shape keeps the browser template data-only and avoids
1756 * edition-specific checks in the presentation layer.
1757 *
1758 * @return array<string,mixed> Empty Resource-allocation DTO.
1759 */
1760 function wpbc_booking_listing_get_empty_resource_allocation() {
1761
1762 return array(
1763 'is_multiple_resources' => false,
1764 'resource_count' => 0,
1765 'resource_count_label' => '',
1766 'date_summary_label' => '',
1767 'segment_count' => 0,
1768 'segments' => array(),
1769 );
1770 }
1771
1772
1773 /**
1774 * Return a localized time label for one allocation day.
1775 *
1776 * Duplicate timestamps are expected when a quantity booking reserves
1777 * several Resources. Midnight represents a full day and is omitted. When
1778 * two or more non-midnight values exist, the first and last values describe
1779 * the booked time interval without repeating it for every Resource.
1780 *
1781 * @param array<string,mixed> $allocation_day Normalized day record.
1782 *
1783 * @return string Localized time or time-range label. Empty for full days.
1784 */
1785 function wpbc_booking_listing_get_allocation_day_time_label( $allocation_day ) {
1786
1787 if ( empty( $allocation_day['times'] ) || ! is_array( $allocation_day['times'] ) ) {
1788 return '';
1789 }
1790
1791 $sql_times = array_values( array_unique( array_filter( array_map( 'strval', $allocation_day['times'] ) ) ) );
1792 sort( $sql_times, SORT_STRING );
1793
1794 $formatted_times = array();
1795 foreach ( $sql_times as $sql_time ) {
1796 if ( '00:00:00' === $sql_time ) {
1797 continue;
1798 }
1799
1800 list( , $formatted_time ) = wpbc_get_date_in_correct_format( $allocation_day['date'] . ' ' . $sql_time );
1801 $formatted_time = trim( $formatted_time );
1802 if ( '' !== $formatted_time ) {
1803 $formatted_times[] = $formatted_time;
1804 }
1805 }
1806
1807 $formatted_times = array_values( array_unique( $formatted_times ) );
1808 if ( empty( $formatted_times ) ) {
1809 return '';
1810 }
1811
1812 if ( 1 === count( $formatted_times ) ) {
1813 return $formatted_times[0];
1814 }
1815
1816 return $formatted_times[0] . ' – ' . $formatted_times[ count( $formatted_times ) - 1 ];
1817 }
1818
1819
1820 /**
1821 * Format one chronological Resource-allocation period.
1822 *
1823 * Common recurrent times are shown once after the date range. Check-in and
1824 * check-out times that differ between the first and final day stay attached
1825 * to their respective dates. Full-day periods contain dates only.
1826 *
1827 * @param string $start_date First date in Y-m-d format.
1828 * @param string $end_date Final date in Y-m-d format.
1829 * @param array<string,array> $allocation_days Normalized days keyed by Y-m-d.
1830 *
1831 * @return string Localized period label.
1832 */
1833 function wpbc_booking_listing_format_allocation_period_label( $start_date, $end_date, $allocation_days ) {
1834
1835 list( $start_date_label ) = wpbc_get_date_in_correct_format( $start_date . ' 00:00:00' );
1836 list( $end_date_label ) = wpbc_get_date_in_correct_format( $end_date . ' 00:00:00' );
1837
1838 $period_days = array();
1839 foreach ( $allocation_days as $date_key => $allocation_day ) {
1840 if ( $date_key >= $start_date && $date_key <= $end_date ) {
1841 $period_days[ $date_key ] = $allocation_day;
1842 }
1843 }
1844
1845 $day_time_labels = array();
1846 foreach ( $period_days as $date_key => $allocation_day ) {
1847 $day_time_labels[ $date_key ] = wpbc_booking_listing_get_allocation_day_time_label( $allocation_day );
1848 }
1849
1850 if ( $start_date === $end_date ) {
1851 $time_label = isset( $day_time_labels[ $start_date ] ) ? $day_time_labels[ $start_date ] : '';
1852
1853 return '' !== $time_label ? $start_date_label . ', ' . $time_label : $start_date_label;
1854 }
1855
1856 $non_empty_time_labels = array_values( array_filter( $day_time_labels ) );
1857 $unique_time_labels = array_values( array_unique( $non_empty_time_labels ) );
1858 if ( count( $non_empty_time_labels ) === count( $period_days ) && 1 === count( $unique_time_labels ) ) {
1859 return $start_date_label . ' – ' . $end_date_label . ', ' . $unique_time_labels[0];
1860 }
1861
1862 $start_time_label = isset( $day_time_labels[ $start_date ] ) ? $day_time_labels[ $start_date ] : '';
1863 $end_time_label = isset( $day_time_labels[ $end_date ] ) ? $day_time_labels[ $end_date ] : '';
1864 if ( '' !== $start_time_label ) {
1865 $start_date_label .= ', ' . $start_time_label;
1866 }
1867 if ( '' !== $end_time_label ) {
1868 $end_date_label .= ', ' . $end_time_label;
1869 }
1870
1871 return $start_date_label . ' – ' . $end_date_label;
1872 }
1873
1874
1875 /**
1876 * Resolve authorized Resource presentation records for an allocation set.
1877 *
1878 * Only titles already present in the owner-filtered Booking Listing Resource
1879 * collection are exposed. Missing or deleted Resources receive the existing
1880 * neutral fallback instead of leaking an unavailable title.
1881 *
1882 * @param array<int> $resource_ids Resource IDs in display order.
1883 * @param array<int,array> $booking_resources_arr Owner-filtered Resource records.
1884 *
1885 * @return array<int,array<string,mixed>> JSON-safe Resource presentation records.
1886 */
1887 function wpbc_booking_listing_get_allocation_resource_records( $resource_ids, $booking_resources_arr ) {
1888
1889 $resource_records = array();
1890 foreach ( $resource_ids as $resource_id ) {
1891 $resource_id = absint( $resource_id );
1892 $resource_title = isset( $booking_resources_arr[ $resource_id ]['title'] )
1893 ? wp_strip_all_tags( wpbc_lang( $booking_resources_arr[ $resource_id ]['title'] ) )
1894 : __( 'Resource not exist', 'booking' );
1895
1896 $resource_records[] = array(
1897 'resource_id' => $resource_id,
1898 'resource_title' => $resource_title,
1899 'is_missing' => ! isset( $booking_resources_arr[ $resource_id ] ),
1900 );
1901 }
1902
1903 return $resource_records;
1904 }
1905
1906
1907 /**
1908 * Group normalized allocation days into chronological Resource-set segments.
1909 *
1910 * Consecutive dates are merged only while their complete Resource set stays
1911 * identical. This represents both a booking that moves between Resources and
1912 * a quantity booking that reserves several Resources for the same period.
1913 *
1914 * @param array<string,array> $allocation_days Normalized days keyed by Y-m-d.
1915 * @param array<int,array> $booking_resources_arr Owner-filtered Resource records.
1916 *
1917 * @return array<int,array<string,mixed>> Ordered allocation segments.
1918 */
1919 function wpbc_booking_listing_group_allocation_days( $allocation_days, $booking_resources_arr ) {
1920
1921 $segments = array();
1922 $current_segment = array();
1923
1924 foreach ( $allocation_days as $date_key => $allocation_day ) {
1925 $resource_ids = array_values( array_unique( array_map( 'absint', array_keys( $allocation_day['resources'] ) ) ) );
1926 sort( $resource_ids, SORT_NUMERIC );
1927 $resource_signature = implode( ',', $resource_ids );
1928
1929 $is_same_segment = ! empty( $current_segment )
1930 && $resource_signature === $current_segment['resource_signature']
1931 && wpbc_is_next_day( $date_key, $current_segment['end_date'] );
1932
1933 if ( ! $is_same_segment ) {
1934 if ( ! empty( $current_segment ) ) {
1935 $current_segment['period_label'] = wpbc_booking_listing_format_allocation_period_label(
1936 $current_segment['start_date'],
1937 $current_segment['end_date'],
1938 $allocation_days
1939 );
1940 $current_segment['resources'] = wpbc_booking_listing_get_allocation_resource_records( $current_segment['resource_ids'], $booking_resources_arr );
1941 unset( $current_segment['resource_signature'], $current_segment['resource_ids'] );
1942 $segments[] = $current_segment;
1943 }
1944
1945 $current_segment = array(
1946 'start_date' => $date_key,
1947 'end_date' => $date_key,
1948 'day_count' => 1,
1949 'resource_signature' => $resource_signature,
1950 'resource_ids' => $resource_ids,
1951 );
1952 continue;
1953 }
1954
1955 $current_segment['end_date'] = $date_key;
1956 ++$current_segment['day_count'];
1957 }
1958
1959 if ( ! empty( $current_segment ) ) {
1960 $current_segment['period_label'] = wpbc_booking_listing_format_allocation_period_label(
1961 $current_segment['start_date'],
1962 $current_segment['end_date'],
1963 $allocation_days
1964 );
1965 $current_segment['resources'] = wpbc_booking_listing_get_allocation_resource_records( $current_segment['resource_ids'], $booking_resources_arr );
1966 unset( $current_segment['resource_signature'], $current_segment['resource_ids'] );
1967 $segments[] = $current_segment;
1968 }
1969
1970 return $segments;
1971 }
1972
1973
1974 /**
1975 * Build compact chronological date periods independently of Resource changes.
1976 *
1977 * This summary is used in the narrow date column. It avoids repeating dates
1978 * for quantity bookings while preserving gaps between non-consecutive dates.
1979 *
1980 * @param array<string,array> $allocation_days Normalized days keyed by Y-m-d.
1981 *
1982 * @return array<int,string> Localized date-period labels.
1983 */
1984 function wpbc_booking_listing_get_allocation_date_period_labels( $allocation_days ) {
1985
1986 $period_labels = array();
1987 $start_date = '';
1988 $end_date = '';
1989
1990 foreach ( array_keys( $allocation_days ) as $date_key ) {
1991 if ( '' === $start_date ) {
1992 $start_date = $date_key;
1993 $end_date = $date_key;
1994 continue;
1995 }
1996
1997 if ( wpbc_is_next_day( $date_key, $end_date ) ) {
1998 $end_date = $date_key;
1999 continue;
2000 }
2001
2002 $period_labels[] = wpbc_booking_listing_format_allocation_period_label( $start_date, $end_date, $allocation_days );
2003 $start_date = $date_key;
2004 $end_date = $date_key;
2005 }
2006
2007 if ( '' !== $start_date ) {
2008 $period_labels[] = wpbc_booking_listing_format_allocation_period_label( $start_date, $end_date, $allocation_days );
2009 }
2010
2011 return $period_labels;
2012 }
2013
2014
2015 /**
2016 * Build the Booking Listing Resource-allocation DTO from saved date rows.
2017 *
2018 * Business Large stores the booking's main Resource in `booking.booking_type`.
2019 * A date on that Resource has an empty `bookingdates.type_id`; only dates on
2020 * another Resource contain `type_id`. Normalizing that fallback before
2021 * counting or grouping prevents both missing labels and repeated per-date
2022 * child labels.
2023 *
2024 * @param object $booking Booking with `booking_db`, `dates`, and `child_id` values.
2025 * @param array<int,array> $booking_resources_arr Owner-filtered Resource records.
2026 *
2027 * @return array<string,mixed> JSON-safe Resource-allocation DTO.
2028 */
2029 function wpbc_booking_listing_build_resource_allocation( $booking, $booking_resources_arr ) {
2030
2031 $resource_allocation = wpbc_booking_listing_get_empty_resource_allocation();
2032 if (
2033 empty( $booking->booking_db->booking_type )
2034 || empty( $booking->dates )
2035 || ! is_array( $booking->dates )
2036 ) {
2037 return $resource_allocation;
2038 }
2039
2040 $main_resource_id = absint( $booking->booking_db->booking_type );
2041 $allocation_days = array();
2042 $all_resource_ids = array();
2043
2044 foreach ( $booking->dates as $date_index => $sql_booking_date ) {
2045 $sql_booking_date = is_scalar( $sql_booking_date ) ? trim( (string) $sql_booking_date ) : '';
2046 if ( ! preg_match( '/^(\d{4})-(\d{2})-(\d{2})(?:\s+(\d{2}):(\d{2}):(\d{2}))?$/', $sql_booking_date, $date_parts ) ) {
2047 continue;
2048 }
2049
2050 $year = (int) $date_parts[1];
2051 $month = (int) $date_parts[2];
2052 $day = (int) $date_parts[3];
2053 $hour = isset( $date_parts[4] ) ? (int) $date_parts[4] : 0;
2054 $minute = isset( $date_parts[5] ) ? (int) $date_parts[5] : 0;
2055 $second = isset( $date_parts[6] ) ? (int) $date_parts[6] : 0;
2056 if (
2057 ! checkdate( $month, $day, $year )
2058 || $hour > 23
2059 || $minute > 59
2060 || $second > 59
2061 ) {
2062 continue;
2063 }
2064
2065 $date_key = sprintf( '%04d-%02d-%02d', $year, $month, $day );
2066 $sql_time = isset( $date_parts[4], $date_parts[5], $date_parts[6] )
2067 ? sprintf( '%02d:%02d:%02d', $hour, $minute, $second )
2068 : '00:00:00';
2069 $date_resource_id = isset( $booking->child_id[ $date_index ] ) && ! empty( $booking->child_id[ $date_index ] )
2070 ? absint( $booking->child_id[ $date_index ] )
2071 : $main_resource_id;
2072
2073 if ( empty( $date_resource_id ) ) {
2074 continue;
2075 }
2076
2077 if ( ! isset( $allocation_days[ $date_key ] ) ) {
2078 $allocation_days[ $date_key ] = array(
2079 'date' => $date_key,
2080 'times' => array(),
2081 'resources' => array(),
2082 );
2083 }
2084
2085 $allocation_days[ $date_key ]['times'][] = $sql_time;
2086 $allocation_days[ $date_key ]['resources'][ $date_resource_id ] = true;
2087 $all_resource_ids[ $date_resource_id ] = true;
2088 }
2089
2090 if ( empty( $allocation_days ) ) {
2091 return $resource_allocation;
2092 }
2093
2094 ksort( $allocation_days, SORT_STRING );
2095 $resource_count = count( $all_resource_ids );
2096 $period_labels = wpbc_booking_listing_get_allocation_date_period_labels( $allocation_days );
2097 $segments = wpbc_booking_listing_group_allocation_days( $allocation_days, $booking_resources_arr );
2098
2099 $resource_allocation['is_multiple_resources'] = ( $resource_count > 1 );
2100 $resource_allocation['resource_count'] = $resource_count;
2101 $resource_allocation['resource_count_label'] = sprintf(
2102 /* translators: %d: Number of booking Resources reserved by one booking. */
2103 _n( '%d booking resource', '%d booking resources', $resource_count, 'booking' ),
2104 $resource_count
2105 );
2106 $resource_allocation['date_summary_label'] = implode( ', ', $period_labels );
2107 $resource_allocation['segment_count'] = count( $segments );
2108 $resource_allocation['segments'] = $segments;
2109
2110 return $resource_allocation;
2111 }
2112
2113
2114 function wpbc_ajx_parse_bookings( $bookings_arr, $resources_arr ) {
2115
2116 $user_id = ( isset( $_REQUEST['wpbc_ajx_user_id'] ) ) ? intval( $_REQUEST['wpbc_ajx_user_id'] ) : wpbc_get_current_user_id(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
2117
2118 foreach ( $bookings_arr as $booking_id => $booking ) {
2119
2120 // Booking resource ------------------------------------------------------------------------------------
2121 $resource_id = ( isset( $booking->booking_db->booking_type ) ) ? $booking->booking_db->booking_type : '1';
2122 $resource_title = '';
2123 $resource_owner_user = $user_id;
2124
2125 if ( class_exists( 'wpdev_bk_personal' ) ) {
2126 $resource_title = ( isset( $resources_arr[ $resource_id ] ) ) ? $resources_arr[ $resource_id ]['title'] : __( 'Resource not exist', 'booking' );
2127 $resource_title = wpbc_lang( $resource_title );
2128 }
2129 if ( class_exists( 'wpdev_bk_multiuser' ) ) {
2130 $resource_owner_user = ( isset( $resources_arr[ $resource_id ] ) ) ? $resources_arr[ $resource_id ]['users'] : $user_id;
2131 }
2132
2133 $resource_title_listing = $resource_title;
2134 $resource_id_listing = $resource_id;
2135 $child_resource_id_arr = array();
2136 if ( ( class_exists( 'wpdev_bk_biz_l' ) ) && ( ! empty( $booking->child_id ) ) && ( is_array( $booking->child_id ) ) ) {
2137 foreach ( $booking->child_id as $child_resource_id ) {
2138 if ( ! empty( $child_resource_id ) ) {
2139 $child_resource_id_arr[] = (int) $child_resource_id;
2140 }
2141 }
2142 $child_resource_id_arr = array_values( array_unique( $child_resource_id_arr ) );
2143
2144 if ( ( 1 === count( $child_resource_id_arr ) ) && ( isset( $resources_arr[ $child_resource_id_arr[0] ] ) ) ) {
2145 $resource_id_listing = $child_resource_id_arr[0];
2146 $resource_title_listing = wpbc_lang( $resources_arr[ $child_resource_id_arr[0] ]['title'] );
2147 }
2148 }
2149 $resource_allocation = class_exists( 'wpdev_bk_biz_l' )
2150 ? wpbc_booking_listing_build_resource_allocation( $booking, $resources_arr )
2151 : wpbc_booking_listing_get_empty_resource_allocation();
2152
2153 // Parse form fields only from $booking->booking_db->form ------------------------------------------
2154 $booking_data_arr = wpbc_parse_booking_data_fields( $booking->booking_db->form,
2155 array( 'resource_id' => $resource_id )
2156 );
2157
2158
2159 foreach ( $booking_data_arr as $booking_data_arr_key => $booking_data_arr_value ) {
2160 // Booking Listing escaping
2161 $booking_data_arr[$booking_data_arr_key] = wpbc_string__escape__then_convert__n_amp__html( $booking_data_arr_value );
2162 }
2163
2164 // Add system keys to data fields arr, like ( 'booking_id', 'trash', 'sync_gid'... ---------------------
2165 $booking_data_arr = wpbc_add_system_booking_data_fields(
2166 $booking_data_arr,
2167 array_merge(
2168 get_object_vars( $booking->booking_db ),
2169 array( 'id' => $booking->id,
2170 'approved' => $booking->approved,
2171 'wpbc_custom_booking_form' => '' //FixIn: 9.4.3.12 // FixIn: 9.4.4.9.
2172 )
2173 )
2174 , array(
2175 'booking_id',
2176 'trash',
2177 'sync_gid',
2178 'is_new',
2179 'status',
2180 'sort_date',
2181 'modification_date',
2182 'creation_date',
2183 'hash',
2184 'booking_type',
2185 'remark',
2186 'cost',
2187 'pay_status',
2188 'pay_request',
2189 'id',
2190 'approved',
2191 'booking_options',
2192 'wpbc_custom_booking_form', // FixIn: 9.4.3.12.
2193 )
2194 );
2195
2196 // Set dates and times in correct format ---------------------------------------------------------------
2197 $booking_data_arr = wpbc_parse_booking_data_fields_formats( $booking_data_arr );
2198
2199 // Get SHORT / WIDE Dates showing data -----------------------------------------------------------------
2200 $dates_attr = array(
2201 'date_html_tag' => 'span',
2202 'show_child_resource_in_dates' => false,
2203 );
2204 $short_dates_content = wpbc_get_formated_dates__short( $booking->short_dates, (bool) $booking->approved, $booking->short_dates_child_id, $resources_arr, $dates_attr );
2205 $wide_dates_content = wpbc_get_formated_dates__wide( $booking->dates, (bool) $booking->approved, $booking->child_id, $resources_arr, $dates_attr );
2206
2207 //------------------------------------------------------------------------------------------------------
2208 // Payment Status
2209 //------------------------------------------------------------------------------------------------------
2210 if ( 1 ) {
2211 $booking_data_arr['is_paid'] = 0; // 0 | 1
2212 $booking_data_arr['pay_print_status'] = ''; // "Unknown" | "Stripe_v3:OK"
2213 // $booking_data_arr['pay_status'] // "165458416073.66" | "Stripe_v3:OK" | "PayPal:Ok"
2214
2215 if ( class_exists( 'wpdev_bk_biz_s' ) ) {
2216
2217 if ( wpbc_is_payment_status_ok( trim( $booking_data_arr['pay_status'] ) ) ) {
2218 $booking_data_arr['is_paid'] = 1;
2219 }
2220
2221 $payment_status_titles = get_payment_status_titles();
2222
2223 $current_payment_status_title = array_search( $booking_data_arr['pay_status'], $payment_status_titles );
2224
2225 if ( $current_payment_status_title === false ) {
2226 $current_payment_status_title = $booking_data_arr['pay_status'];
2227 }
2228
2229 if ( $booking_data_arr['is_paid'] ) {
2230 $booking_data_arr['pay_print_status'] = $booking_data_arr['pay_status'];
2231 if ( $current_payment_status_title == 'Completed' ) {
2232 $booking_data_arr['pay_print_status'] = $current_payment_status_title;
2233 }
2234 } else if ( ( is_numeric( $booking_data_arr['pay_status'] ) ) || ( $booking_data_arr['pay_status'] == '' ) ) {
2235 $booking_data_arr['pay_print_status'] = __( 'Unknown', 'booking' );
2236 } else {
2237 $booking_data_arr['pay_print_status'] = $current_payment_status_title;
2238 }
2239 ////////////////////////////////////////////////////////////////////////////////////////////////////
2240
2241 if ( $booking_data_arr['pay_print_status'] == 'Completed' ) { // FixIn: 8.4.7.11.
2242 $booking_data_arr['pay_print_status'] = __( 'Completed', 'booking' );
2243 }
2244 $real_payment_css = empty( $booking_data_arr['pay_status'] ) ? $current_payment_status_title : $booking_data_arr['pay_status']; // FixIn: 8.7.7.13.
2245 $css_payment_label = 'wpbc_label_payment_status_' . wpbc_check_payment_status( $real_payment_css ); // 'success' | 'pending' | 'unknown' | 'error' // FixIn: 8.7.7.13.
2246
2247 if ( $booking_data_arr['is_paid'] ) {
2248 $css_payment_label .= ' wpbc_label_payment_status_success';
2249 }
2250 $payment_label_template = '<span class="wpbc_label wpbc_label_payment_status ' . $css_payment_label . '">'
2251 . '<span style="font-size:07px;padding: 0 1em 0 0;line-height: 2em;">'
2252 . __( 'Payment', 'booking' )
2253 . '</span> '
2254 . '<span>'
2255 . $booking_data_arr['pay_print_status']
2256 . '</span> '
2257 . '</span>';
2258 } else {
2259 $payment_label_template = '';
2260 }
2261 }
2262
2263 //------------------------------------------------------------------------------------------------------
2264 // Currency
2265 //------------------------------------------------------------------------------------------------------
2266 if ( class_exists( 'wpdev_bk_biz_s' ) ) {
2267 $currency_symbol = wpbc_get_currency_symbol_for_user( $resource_id );
2268 $booking_data_arr['currency_symbol'] = $currency_symbol;
2269 }
2270
2271 //------------------------------------------------------------------------------------------------------
2272 // Add some fields to [ 'parsed_fields' ]
2273 //------------------------------------------------------------------------------------------------------
2274 $booking_data_arr['resource_title'] = $resource_title;
2275 $booking_data_arr['resource_id'] = $resource_id;
2276 $booking_data_arr['resource_title_listing'] = $resource_title_listing;
2277 $booking_data_arr['resource_id_listing'] = $resource_id_listing;
2278 $booking_data_arr['resource_owner_user'] = $resource_owner_user;
2279 //$booking_data_arr['short_dates_content'] = $short_dates_content;
2280 //$booking_data_arr['wide_dates_content'] = $wide_dates_content;
2281
2282 //------------------------------------------------------------------------------------------------------
2283 // Form Show - "Content of booking fields data" form
2284 //------------------------------------------------------------------------------------------------------
2285
2286 $custom_booking_form_name = ( ! empty( $booking_data_arr['wpbc_custom_booking_form'] ) ) ? $booking_data_arr['wpbc_custom_booking_form'] : ''; // FixIn: 9.4.3.12.
2287 $booking_data_arr['admin_edit_url'] = wpbc_get_booking_admin_edit_url(
2288 $resource_id,
2289 isset( $booking_data_arr['hash'] ) ? $booking_data_arr['hash'] : '',
2290 $custom_booking_form_name
2291 );
2292 $form_show_template = wpbc_get_content_booking_form_show( $resource_id , $custom_booking_form_name ); // <strong>First Name</strong>:<span class="fieldvalue">[name]</span>&nbsp;&nbsp; ...
2293 $parsed_form_show = wpbc_get_parsed_content_booking_form_show( $booking_data_arr, $form_show_template ); // <strong>First Name</strong>:<span class="fieldvalue">John</span>&nbsp;&nbsp; ...
2294
2295 //------------------------------------------------------------------------------------------------------
2296 // Google Calendar link
2297 //------------------------------------------------------------------------------------------------------
2298 $booking_data_arr['google_calendar_link'] = wpbc_booking_do_action__get_google_calendar_link( array(
2299 'form_data' => $booking_data_arr,
2300 'form_show' => $parsed_form_show, //wp_strip_all_tags( $parsed_form_show ),
2301 'dates_short' => $booking->short_dates
2302 ) );
2303 $booking_data_arr['visitorbookingpayurl'] = ( class_exists( 'wpdev_bk_biz_s' ) )
2304 ? apply_bk_filter( 'wpdev_booking_set_booking_edit_link_at_email', '[visitorbookingpayurl]', $booking_id )
2305 : '';
2306 // =====================================================================================================
2307 $booking_data_arr = apply_filters( 'wpbc_booking_listing_parsed_fields', $booking_data_arr, $booking_id, $booking );
2308 $bookings_arr[ $booking_id ]->parsed_fields = $booking_data_arr;
2309 $bookings_arr[ $booking_id ]->resource_allocation = $resource_allocation;
2310
2311
2312 // =====================================================================================================
2313 $bookings_arr[ $booking_id ]->templates = array(
2314 'form_show' => $parsed_form_show,
2315 'form_show_simple' => wp_kses( trim( stripslashes( $parsed_form_show ) ),
2316 // array_merge(
2317 array(
2318 'span' => array( 'style'=>true , 'class'=>true , 'id'=>true ),
2319 'b' => array( 'style'=>true , 'class'=>true , 'id'=>true ),
2320 'strong' => array( 'style'=>true , 'class'=>true , 'id'=>true ),
2321 'i' => array( 'style'=>true , 'class'=>true , 'id'=>true ),
2322 'class' => array(),
2323 'style' => array()
2324 )
2325 // , wp_kses_allowed_html( 'post' ) )
2326 ),
2327 'form_show_nohtml' => wp_strip_all_tags( $parsed_form_show ),
2328 'short_dates_content' => $short_dates_content,
2329 'wide_dates_content' => $wide_dates_content,
2330 'payment_label_template' => $payment_label_template
2331 );
2332 }
2333
2334 return $bookings_arr;
2335 }
2336
2337
2338 //TODO: Refactor this function to make this simpler, for prevent of issues in future.
2339 /**
2340 * Get SHORT Dates showing data
2341 *
2342 * @param array $short_dates_arr - Array of dates.
2343 * @param bool $is_approved - true or false
2344 * @param $dates_type_id_arr
2345 * @param $booking_resources_arr
2346 * @param array $attr - [ 'date_html_tag' => 'a' ] .
2347 *
2348 * @return string
2349 */
2350 function wpbc_get_formated_dates__short( $short_dates_arr, $is_approved = false, $dates_type_id_arr = array(), $booking_resources_arr = array(), $attr = array() ) {
2351
2352 $defaults = array(
2353 'date_html_tag' => 'a',
2354 'show_child_resource_in_dates' => true,
2355 );
2356 $params = wp_parse_args( $attr, $defaults );
2357
2358 $css_class_approved = ( $is_approved ) ? 'approved' : '';
2359 $short_dates_content = '';
2360 $short_dates_content_arr = array();
2361 $date_number = 0;
2362 $previous_formatted_date = '';
2363 $previous_short_dates_content_sup;
2364 $previous_sql_date = '';
2365 $previous_short_date_item = '';
2366 foreach ( $short_dates_arr as $dt ) {
2367
2368 if ( '-' === $dt ) {
2369 $short_dates_content_arr[] = '<span class="date_tire"> - </span>';
2370 } elseif ( ',' === $dt ) {
2371 $short_dates_content_arr[] = '<span class="date_tire date_comma">, </span>';
2372 } else {
2373
2374 // Separate recurrent time slots: previous end (...02) followed by the next start (...01).
2375 $is_next_time_slot = (
2376 ( ! empty( $previous_sql_date ) )
2377 && ( '02' === substr( trim( $previous_sql_date ), -2 ) )
2378 && ( '01' === substr( trim( $dt ), -2 ) )
2379 );
2380 if ( $is_next_time_slot && ( ',' !== $previous_short_date_item ) ) {
2381 if ( '-' === $previous_short_date_item ) {
2382 array_pop( $short_dates_content_arr );
2383 }
2384 $short_dates_content_arr[] = '<span class="date_tire date_comma">, </span>'; // FixIn: 11.4.2.
2385 }
2386
2387 list( $formatted_date, $formatted_time ) = wpbc_get_date_in_correct_format( $dt );
2388
2389 $short_dates_content = '';
2390 $short_dates_content_sup = ''; // Times and booking resources.
2391
2392 if ( 'a' === $params['date_html_tag'] ) {
2393 $short_dates_content .= '<a href="javascript:void(0)" onclick="javascript:wpbc_ajx_click_on_dates_toggle(this);" ';
2394 } else {
2395 $short_dates_content .= '<' . $params['date_html_tag'];
2396 }
2397 $short_dates_content .= ' class="wpbc_label wpbc_label_booking_dates ' . $css_class_approved . '">';
2398
2399 $short_dates_content .= '<span>';
2400
2401 if ( $previous_formatted_date !== $formatted_date ) {
2402 $short_dates_content .= $formatted_date;
2403 $short_dates_content_sup .= '<sup class="field-booking-time">' . $formatted_time . '</sup>';
2404 } else {
2405 // same date (probaly it is one date) !
2406 if ( count( $short_dates_content_arr ) > 0 ) {
2407 // Unset tire: '-'.
2408 array_pop( $short_dates_content_arr );
2409 if ( ! empty( wp_strip_all_tags( $previous_short_dates_content_sup ) ) ) {
2410 $tag_closed_span_and_a = array_pop( $short_dates_content_arr );
2411 array_pop( $short_dates_content_arr ); // Unset time_sup.
2412 $short_dates_content_arr[] = $tag_closed_span_and_a; // FixIn: 11.4.2.
2413 }
2414 $short_dates_content_sup .= '<sup class="field-booking-time"> '
2415 . trim( wp_strip_all_tags( $previous_short_dates_content_sup ) )
2416 . ' - '
2417 . trim( $formatted_time )
2418 . '</sup>'; // FixIn: 11.4.2.
2419 }
2420 }
2421
2422 // BL.
2423 if (
2424 ( class_exists( 'wpdev_bk_biz_l' ) )
2425 && ( $params['show_child_resource_in_dates'] )
2426 && ( ! empty( $dates_type_id_arr[ $date_number ] ) )
2427 && ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
2428 ){
2429
2430 $resource_title = ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
2431 ? $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ]['title']
2432 : __( 'Resource not exist', 'booking' );
2433 $resource_title = wpbc_lang( $resource_title );
2434
2435 if ( strlen( $resource_title ) > 19 ) {
2436 $resource_title = substr( $resource_title, 0, 13 ) . '...' . substr( $resource_title, - 3 );
2437 }
2438
2439 $short_dates_content_sup .= '<sup class="field-booking-time date_from_dif_type"> ' . $resource_title . '</sup>';
2440 }
2441
2442 $short_dates_content_arr[] = $short_dates_content;
2443 $short_dates_content_arr[] = $short_dates_content_sup;
2444 $short_dates_content_arr[] = '</span></' . $params['date_html_tag'] . '>';
2445
2446
2447
2448 $previous_short_dates_content_sup = $short_dates_content_sup;
2449 $previous_formatted_date = $formatted_date;
2450 $previous_sql_date = $dt;
2451 }
2452 $previous_short_date_item = $dt;
2453 $date_number++;
2454 }
2455
2456 $short_dates_content = implode( '', $short_dates_content_arr );
2457
2458 return $short_dates_content;
2459 }
2460
2461
2462 /**
2463 * Get Wide Dates showing data
2464 *
2465 * @param array $dates_arr - array of dates in sql string format
2466 * @param bool $is_approved - is approved (true) or pending (false)
2467 * @param array $dates_type_id_arr - array of $date->type_id from the dates SQL object
2468 * @param type $booking_resources_arr - array of booking resources objects
2469 *
2470 * @return string
2471 */
2472 function wpbc_get_formated_dates__wide( $dates_arr, $is_approved = false, $dates_type_id_arr = array(), $booking_resources_arr = array(), $attr = array() ) {
2473
2474 $defaults = array(
2475 'date_html_tag' => 'a',
2476 'show_child_resource_in_dates' => true,
2477 );
2478 $params = wp_parse_args( $attr, $defaults );
2479
2480 $wide_dates_arr = array();
2481
2482 $css_class_approved = ( $is_approved ) ? 'approved' : '';
2483
2484 foreach ( $dates_arr as $date_number => $sql_booking_date ) {
2485
2486 list( $formatted_date, $formatted_time ) = wpbc_get_date_in_correct_format( $sql_booking_date );
2487
2488 $wide_date = '';
2489 if ( 'a' === $params['date_html_tag'] ) {
2490 $wide_date .= '<a href="javascript:void(0)" onclick="javascript:wpbc_ajx_click_on_dates_toggle(this);" ';
2491 } else {
2492 $wide_date .= '<' . $params['date_html_tag'];
2493 }
2494 $wide_date .= ' class="wpbc_label wpbc_label_booking_dates ' . $css_class_approved . '">';
2495 $wide_date .= '<span>';
2496
2497 $wide_date .= $formatted_date;
2498 $wide_date .= '<sup class="field-booking-time">' . $formatted_time . '</sup>';
2499
2500 // BL
2501 if (
2502 ( class_exists( 'wpdev_bk_biz_l' ) )
2503 && ( $params['show_child_resource_in_dates'] )
2504 && ( '' != $dates_type_id_arr[ $date_number ] )
2505 && ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
2506 ){
2507 $resource_title = ( isset( $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ] ) )
2508 ? $booking_resources_arr[ $dates_type_id_arr[ $date_number ] ]['title']
2509 : __( 'Resource not exist', 'booking' );
2510 $resource_title = wpbc_lang( $resource_title );
2511
2512 if ( strlen( $resource_title ) > 19 ) {
2513 $resource_title = substr( $resource_title, 0, 13 ) . '...' . substr( $resource_title, - 3 );
2514 }
2515 $wide_date .= '<sup class="field-booking-time date_from_dif_type"> ' . $resource_title . '</sup>';
2516 }
2517
2518 $wide_date .= '</span></' . $params['date_html_tag'] . '>';
2519
2520 $wide_dates_arr[] = $wide_date;
2521 }
2522
2523 $wide_dates_content = implode( '<span class="date_tire date_comma">, </span>' , $wide_dates_arr );
2524
2525 return $wide_dates_content;
2526 }
2527
2528
2529 /**
2530 * Parse booking "data field" and get array
2531 *
2532 * @param string $data - "id^2~booking_type^Standard~status^Approved~dates^2019-09-18 00:00:00 - 2019-09-20 00:00:00 , 2019-09-18 00:00:00 (Standard-1) - 2019-09-20 00:00:00 (Standard-1)~modification_date^2019-09-05 10:50:04~cost^100.00~pay_status^156766972609.7~selected_short_timedates_hint^09/18/2019 - 09/20/2019~nights_number_hint^2~cost_hint^$75.00~name^John test~secondname^Smith~email^user@beta.com~phone^~visitors^4~children^~details^~term_and_condition^~user^Support A~wpbc_other_action^~rangetime^~other_email^~visitorsselector^~visitors_fee^~visitors_fee_hint^~trash^~remark^Approved by:John Smith (user@beta.com) [2019-09-11 09:30] Declined by:John Smith (user@beta.com) [2019-09-11 09:30]"
2533 * @param array $attr - array( 'r_separator' => '~', 'f_separator' => '^' )
2534 *
2535 * @return array - Array (
2536 [id] => 2
2537 [booking_type] => Standard
2538 [status] => Approved
2539 ... )
2540 */
2541 function wpbc_parse_booking_data_fields( $data , $attr = array() ){
2542
2543 $defaults = array(
2544 'r_separator' => '~' ,
2545 'f_separator' => '^' ,
2546 'resource_id' => '1' ,
2547 'system_fields' => array(
2548 'booking_id',
2549 'trash',
2550 //'sync_gid',
2551 'is_new',
2552 'status',
2553 'sort_date',
2554 'modification_date',
2555 'hash',
2556 'booking_type',
2557 'remark',
2558 'cost',
2559 'pay_status',
2560 'pay_request',
2561 'id',
2562 'approved'
2563 )
2564 );
2565 $attr = wp_parse_args( $attr, $defaults );
2566
2567 $data_arr = array();
2568
2569 if ( ! empty( $data ) ) {
2570
2571 $data = explode( $attr['r_separator'] , $data ); // ~
2572
2573 foreach ( $data as $data_rows ) {
2574
2575 $data_rows = explode( $attr['f_separator'] , $data_rows ); // ^
2576
2577 $data_field = array( 'type' => $data_rows[0], 'name' => $data_rows[1], 'value' => $data_rows[2] );
2578
2579 // remove checkboxes suffix []
2580 $data_field['name'] = str_replace( '[]', '', $data_field['name'] );
2581
2582 // remove booking resource ID suffix
2583 $data_field['name'] = substr( $data_field['name'], 0, - 1 * strlen( strval( $attr['resource_id'] ) ) );
2584
2585 // System fields - adjust fields with same name
2586 if ( in_array( $data_field['name'], $attr['system_fields'] ) ) {
2587 $data_field['name'] .= '_data';
2588 }
2589
2590 //Checkboxes
2591 if ( ( 'checkbox' == $data_field['type'] ) && ( empty( $data_field['value'] ) ) ) {
2592 continue;
2593 }
2594 if ( ( 'checkbox' == $data_field['type'] ) && ( ! is_array( $data_field['value'] ) ) ) {
2595 $data_field['value'] = str_replace( array( 'true', 'false' ), array(
2596 strtolower( __( 'Yes', 'booking' ) ),
2597 strtolower( __( 'No', 'booking' ) )
2598 ), $data_field['value'] );
2599 }
2600
2601 // Several items with same name - multi checkboxes
2602 if ( ! isset( $data_arr[ $data_field['name'] ] ) ) {
2603 $data_arr[ $data_field['name'] ] = $data_field['value'];
2604 } else {
2605 if ( is_array( $data_arr[ $data_field['name'] ] ) ) {
2606 $data_arr[ $data_field['name'] ][] = $data_field['value'];
2607 } else {
2608 $data_arr[ $data_field['name'] ] = array( $data_arr[ $data_field['name'] ], $data_field['value'] );
2609 }
2610 }
2611
2612 }
2613 }
2614
2615 foreach ( $data_arr as $key => $value ) {
2616
2617 // Multi checkboxes: [9] => checkbox^my_multi_checkbx4[]^1 [10] => checkbox^my_multi_checkbx4[]^ [11] => checkbox^my_multi_checkbx4[]^3
2618 if ( is_array( $value ) ) {
2619 $value = implode( ',', $value );
2620 $data_arr[$key] = $value;
2621 }
2622 }
2623
2624 return $data_arr;
2625 }
2626
2627
2628 /**
2629 * Add system fields to Booking fields array and get final array of fields
2630 * @param array $booking_data_arr Original array of form fields from DB
2631 Array (
2632 [selected_short_dates_hint] => March 5, 2023
2633 [days_number_hint] => 1
2634 [cost_hint] => &amp;#36;95
2635 [rangetime] => 10:00 AM - 12:00 PM
2636 [name] => test
2637 [email] => test@wpbookingcalendar.com
2638 ...
2639 )
2640
2641 * @param array $booking_system_arr array of system fields from DB
2642 Array ( [booking_id] => 188
2643 [trash] => 0
2644 ...
2645 [cost] => 95.00
2646 [pay_status] => 165036591118.88
2647 [pay_request] => 0
2648 [id] => 188
2649 [approved] => 0
2650 )
2651
2652 * @param array $system_keys_arr system fields keys that need to be added, like this:
2653 Array ( booking_id, trash, sync_gid, is_new, status
2654 , sort_date, modification_date, hash, booking_type
2655 , remark, cost, pay_status, pay_request, id, approved )
2656
2657 * @return array array of form fields with system fields
2658 */
2659 function wpbc_add_system_booking_data_fields( $booking_data_arr, $booking_system_arr, $system_keys_arr ){
2660
2661 foreach ( $system_keys_arr as $key ) {
2662
2663 if (
2664 ( ! isset( $booking_system_arr[ $key ] ) )
2665 || ( is_null( $booking_system_arr[ $key ] ) )
2666 ) {
2667 $booking_system_arr[ $key ] = ''; //Some fields, like remark or booking_options can be null, so we define them as ''
2668 }
2669
2670 if ( isset( $booking_system_arr[ $key ] ) ) {
2671
2672 if ( ! isset( $booking_data_arr[ $key ] ) ) {
2673 $booking_data_arr[ $key ] = maybe_unserialize( $booking_system_arr[ $key ] );
2674 } else {
2675 $booking_data_arr[ $key . '_system' ] = maybe_unserialize( $booking_system_arr[ $key ] );
2676 }
2677 }
2678
2679 }
2680 return $booking_data_arr;
2681 }
2682
2683
2684 /**
2685 * Parse booking form fields format - for example: time fields in specific format
2686 * @param $data_arr
2687 *
2688 * @return array
2689 */
2690 function wpbc_parse_booking_data_fields_formats( $data_arr ){
2691
2692 foreach ( $data_arr as $key => $value ) {
2693
2694 if ( 'rangetime' == $key ) {
2695 $data_arr[$key] = wpbc_time_slot_in_format( $value );
2696 $data_arr[ $key . '_in_24_hour' ] = $value; // FixIn: 10.0.0.52.
2697 }
2698
2699 if ( in_array( $key, array( 'starttime', 'endtime' ) ) ) {
2700 $data_arr[$key] = wpbc_time_in_format( $value );
2701 $data_arr[ $key . '_in_24_hour' ] = $value; // FixIn: 10.0.0.52.
2702 }
2703
2704 if ( in_array( $key, array( 'modification_date', 'creation_date' ) ) ) {
2705
2706 //$data_arr[$key] = wpbc_get_dates_comma_string_localized( $value );
2707
2708
2709 // This date $values in GMT date/Time format. So we need to switch to WordPress locale with TIME sum of actual GMT date/time value + shift of timezone from WordPress.
2710 $is_add_wp_timezone = true;
2711 $its_for_default_datetime_format = '';
2712 $data_arr[ $key ] = wpbc_datetime_localized( $value, $its_for_default_datetime_format, $is_add_wp_timezone );
2713 $data_arr[ $key . '_in_24_hour' ] = $value; // FixIn: 10.0.0.52.
2714 }
2715
2716 if ( ( 'hash' === $key ) && ( empty( $value ) ) ) { //FixIn: 9.2.3.4 // FixIn: 9.4.3.10.
2717 // Update booking Hash if it was empty
2718 wpbc_hash__update_booking_hash( $data_arr['id'], $data_arr['booking_type'] );
2719 // Get new booking hash
2720 $hash__arr = wpbc_hash__get_booking_hash__resource_id( $data_arr['id'] );
2721 if ( ! empty( $hash__arr ) ) {
2722 $data_arr[ $key ] = $hash__arr[0];
2723 }
2724 }
2725 }
2726 return $data_arr;
2727 }
2728
2729
2730 /**
2731 * Get pure "Content of booking fields data" with shortcodes inside.
2732 * Can depend on booking resource (BM) or resource owner (MU).
2733 * Now also supports BFB DB resolver (published/preview-aware).
2734 *
2735 * @param int $resource_id
2736 * @param string $custom_booking_form_name Optional. Force this custom form if possible.
2737 *
2738 * @return string
2739 */
2740 function wpbc_get_content_booking_form_show( $resource_id, $custom_booking_form_name = '' ) { // FixIn: 9.4.3.12.
2741
2742 static $wpbc__form_show_cache = array();
2743
2744 $resource_id = (int) $resource_id;
2745 $custom_booking_form_name = (string) $custom_booking_form_name;
2746
2747 if ( - 1 === $resource_id ) {
2748 if ( function_exists( 'get__default_type' ) ) {
2749 $resource_id = (int) get__default_type();
2750 } else {
2751 $resource_id = 1;
2752 }
2753 }
2754
2755 // ------------------------------------------------------------
2756 // Determine a stable form slug early (avoid undefined var).
2757 // This is used for cache key and for resolver path.
2758 // ------------------------------------------------------------
2759 $my_booking_form_name = ( '' !== $custom_booking_form_name ) ? $custom_booking_form_name : 'standard';
2760
2761 // Preview-aware context (optional; usually "published" in Booking Listing).
2762 $ctx = array();
2763 if ( function_exists( 'wpbc_get_request_form_context' ) ) {
2764 $ctx = wpbc_get_request_form_context();
2765 }
2766 $form_status = ( isset( $ctx['form_status'] ) ) ? sanitize_key( $ctx['form_status'] ) : 'published';
2767 if ( in_array( $form_status, array( 'publish', 'published' ), true ) ) {
2768 $form_status = 'published';
2769 }
2770 if ( 'preview' !== $form_status ) {
2771 $form_status = 'published';
2772 }
2773
2774 // Cache key (important: this function is called per booking row).
2775 $cache_key = get_locale() . '|' . $form_status . '|' . $resource_id . '|' . $my_booking_form_name;
2776 if ( isset( $wpbc__form_show_cache[ $cache_key ] ) ) {
2777 return $wpbc__form_show_cache[ $cache_key ];
2778 }
2779
2780 if ( '' === $custom_booking_form_name ) {
2781 $default_form_name = apply_bk_filter( 'wpbc_get_default_custom_form', 'standard', $resource_id );
2782 if ( ! empty( $default_form_name ) ) {
2783 $my_booking_form_name = $default_form_name;
2784 }
2785 }
2786
2787 $booking_form_show = '';
2788
2789 if ( class_exists( 'WPBC_FE_Form_Source_Resolver' ) && class_exists( 'WPBC_BFB_Form_Loader' ) ) {
2790
2791 $req = array(
2792 'resource_id' => (int) $resource_id,
2793 'form_slug' => (string) $my_booking_form_name,
2794 'form_status' => $form_status,
2795 'custom_params' => array(),
2796 'ctx' => ( is_array( $ctx ) ? $ctx : array() ),
2797 );
2798
2799 $resolved = WPBC_FE_Form_Source_Resolver::resolve( $req );
2800
2801 // If preview requested but not found, try published as fallback.
2802 if ( ( empty( $resolved['engine'] ) || ( 'bfb_db' !== $resolved['engine'] ) ) && ( 'preview' === $form_status ) ) {
2803 $req['form_status'] = 'published';
2804 $resolved = WPBC_FE_Form_Source_Resolver::resolve( $req );
2805 }
2806
2807 if ( ! empty( $resolved['engine'] ) && ( 'bfb_db' === $resolved['engine'] ) ) {
2808
2809 $bfb_loader_args = array();
2810 if ( ! empty( $resolved['bfb_loader_args'] ) && is_array( $resolved['bfb_loader_args'] ) ) {
2811 $bfb_loader_args = $resolved['bfb_loader_args'];
2812 }
2813
2814 // We need "content_form" template for booking fields output.
2815 $bfb_loader_args['return'] = 'content_form';
2816
2817 $bfb_pair = wpbc_bfb_get_booking_form_pair( $bfb_loader_args );
2818
2819 $content_form = '';
2820 if ( is_array( $bfb_pair ) && isset( $bfb_pair['content'] ) ) {
2821 $content_form = (string) $bfb_pair['content'];
2822 }
2823
2824 if ( '' !== trim( $content_form ) ) {
2825 $booking_form_show = wpbc_bf__replace_custom_html_shortcodes( $content_form );
2826 }
2827 }
2828 }
2829
2830 // ------------------------------------------------------------
2831 // Language + cleanup (keep old behavior).
2832 // ------------------------------------------------------------
2833 $booking_form_show = wpbc_lang( $booking_form_show );
2834
2835 $search = array( "'(<br[ ]?[/]?>)+'si", "'(<[/]?p[ ]?>)+'si" );
2836 $replace = array( "&nbsp;&nbsp;", " &nbsp; ", " &nbsp; " );
2837 $booking_form_show = preg_replace( $search, $replace, $booking_form_show );
2838
2839 // Store cache by final slug (slug may have changed in BM branch).
2840 $final_cache_key = get_locale() . '|' . $form_status . '|' . $resource_id . '|' . $my_booking_form_name;
2841 $wpbc__form_show_cache[ $final_cache_key ] = $booking_form_show;
2842
2843 return $booking_form_show;
2844 }
2845
2846
2847
2848 /**
2849 * Get parsed "Content of booking fields data" - Shortcodes replaced by Values
2850 *
2851 * @param array $booking_data_arr
2852 * @param string $booking_form_show
2853 *
2854 * @return string
2855 */
2856 function wpbc_get_parsed_content_booking_form_show( $booking_data_arr, $booking_form_show ){
2857
2858 foreach ( $booking_data_arr as $key_param => $value_param ) {
2859 if ( ( gettype ( $value_param ) != 'array' )
2860 && ( gettype ( $value_param ) != 'object' )
2861 ) {
2862 $booking_form_show = str_replace( '['. $key_param .']', $value_param ,$booking_form_show);
2863 }
2864 }
2865 // Remove all shortcodes, which have not replaced early.
2866 $booking_form_show = preg_replace ('/[\s]{0,}\[[a-zA-Z0-9.,-_]{0,}\][\s]{0,}/', '', $booking_form_show);
2867
2868 $booking_form_show = str_replace( "&amp;", '&', $booking_form_show );
2869
2870 return $booking_form_show;
2871 }
2872
2873 // </editor-fold>
2874
2875
2876 // <editor-fold defaultstate="collapsed" desc=" F u n c t i o n s f o r C l e a n i ng s " >
2877
2878 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2879 // Escaping
2880 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2881
2882 /**
2883 * Escaping for inline JavaScript.
2884 * Based on WordPress esc_js()
2885 * plus removing \n in the code
2886 * and back converting escaped single quotes from \' to '
2887 *
2888 * This function has to be used in the code marked with double quote symbols, not single.
2889 * Example: onclick="javascript:<?php
2890 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2891 echo wpbc_esc_js( $item_params['action'] ); ?>"
2892 *
2893 * @param $text
2894 *
2895 * @return string
2896 */
2897 function wpbc_esc_js( $text ) {
2898
2899 $text = str_replace( "\n", '', $text ); // removing \n in the code
2900
2901 //$safe_text = esc_js( $text ); // js
2902
2903 // This code get from esc_js() and modified for correct working with (' symbols) in translations
2904 $safe_text = wp_check_invalid_utf8( $text );
2905 $safe_text = _wp_specialchars( $safe_text, ENT_COMPAT );
2906 $safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "\'", stripslashes( $safe_text ) );
2907 $safe_text = str_replace( "\r", '', $safe_text );
2908 $safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) );
2909
2910 $safe_text = str_replace( "\'", "'", $safe_text ); // back converting escaped single quotes from \' to '
2911 $safe_text = str_replace( "\\\'", "\'", $safe_text ); // back converting escaped single quotes from \' to '
2912
2913 return $safe_text;
2914 }
2915
2916
2917 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2918 // DB
2919 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2920
2921 /**
2922 * Check $value for injections. Basically can be used in Requests params checking.
2923 *
2924 * @param type $value
2925 *
2926 * @return type
2927 */
2928 function wpbc_esc_clean_parameter( $value ) {
2929
2930 $value = preg_replace( '/<[^>]*>/', '', $value ); // clean any tags
2931 $value = str_replace( '<', ' ', $value );
2932 $value = str_replace( '>', ' ', $value );
2933 $value = wp_strip_all_tags( $value ); // Strip HTML and PHP tags from a string
2934
2935 // Clean SQL injection
2936 $value = esc_sql( $value );
2937 $value = esc_textarea( $value ); // FixIn: 7.1.1.2.
2938
2939 return $value;
2940 }
2941
2942
2943 function wpbc_esc_sql_like( $value_trimmed ) {
2944
2945 // check here https://code.tutsplus.com/articles/data-sanitization-and-validation-with-wordpress--wp-25536
2946
2947 global $wpdb;
2948 if ( method_exists( $wpdb ,'esc_like' ) )
2949 return $wpdb->esc_like( $value_trimmed ); // Its require minimum WP 4.0.0
2950 else
2951 return addcslashes( $value_trimmed, '_%\\' ); // Direct implementation from $wpdb->esc_like(
2952 }
2953
2954
2955 /**
2956 * Clean user string for using in SQL LIKE statement - append to LIKE sql
2957 *
2958 * @param string $value - to clean
2959 *
2960 * @return string - escaped
2961 * Exmaple:
2962 * $search_escaped_like_title = wpbc_esc_clean_like_string_for_append_in_sql_for_db( $input_var );
2963 *
2964 * $where_sql = " WHERE title LIKE ". $search_escaped_like_title ." ";
2965 */
2966 function wpbc_esc_clean_like_string_for_append_in_sql_for_db( $value ) {
2967
2968 // check here https://code.tutsplus.com/articles/data-sanitization-and-validation-with-wordpress--wp-25536
2969
2970 global $wpdb;
2971
2972 $value_trimmed = trim( stripslashes( $value ) );
2973
2974 $wild = '%';
2975 $like = $wild . wpbc_esc_sql_like( $value_trimmed ) . $wild;
2976
2977 /* phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder */
2978 $sql = $wpdb->prepare( "'%s'", $like );
2979
2980 return $sql;
2981
2982
2983 /* Help:
2984 * First half of escaping for LIKE special characters % and _ before preparing for MySQL.
2985 * Use this only before wpdb::prepare() or esc_sql(). Reversing the order is very bad for security.
2986 *
2987 * Example Prepared Statement:
2988 *
2989 * $wild = '%';
2990 * $find = 'only 43% of planets';
2991 * $like = $wild . wpbc_esc_sql_like( $find ) . $wild;
2992 * $sql = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE '%s'", $like );
2993 *
2994 * Example Escape Chain:
2995 *
2996 * $sql = esc_sql( wpbc_esc_sql_like( $input ) );
2997 */
2998
2999 }
3000
3001
3002 /**
3003 * Clean string for using in SQL LIKE requests inside single quotes: WHERE title LIKE '%". $escaped_search_title ."%'
3004 * Replaced _ to \_ % to \% \ to \\
3005 *
3006 * @param string $value - to clean
3007 *
3008 * @return string - escaped
3009 * Exmaple:
3010 * $search_escaped_like_title = wpbc_esc_clean_like_string_for_db( $input_var );
3011 *
3012 * $where_sql = " WHERE title LIKE '%". $search_escaped_like_title ."%' ";
3013 *
3014 * Important! Use SINGLE quotes after in SQL query: LIKE '%".$data."%'
3015 */
3016 function wpbc_esc_clean_like_string_for_db( $value ){
3017
3018 // check here https://code.tutsplus.com/articles/data-sanitization-and-validation-with-wordpress--wp-25536
3019
3020 global $wpdb;
3021
3022 $value_trimmed = trim( stripslashes( $value ) );
3023
3024 $value_trimmed = wpbc_esc_sql_like( $value_trimmed );
3025
3026 /* phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder */
3027 $value = trim( $wpdb->prepare( "'%s'", $value_trimmed ) , "'" );
3028
3029 return $value;
3030
3031 /* Help:
3032 * First half of escaping for LIKE special characters % and _ before preparing for MySQL.
3033 * Use this only before wpdb::prepare() or esc_sql(). Reversing the order is very bad for security.
3034 *
3035 * Example Prepared Statement:
3036 *
3037 * $wild = '%';
3038 * $find = 'only 43% of planets';
3039 * $like = $wild . wpbc_esc_sql_like( $find ) . $wild;
3040 * $sql = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE '%s'", $like );
3041 *
3042 * Example Escape Chain:
3043 *
3044 * $sql = esc_sql( wpbc_esc_sql_like( $input ) );
3045 */
3046 }
3047
3048
3049 // </editor-fold>
3050
3051
3052 // <editor-fold defaultstate="collapsed" desc=" D B " >
3053
3054 /***
3055 * Get list of DB of this plugin
3056 * @return array
3057 */
3058 function wpbc_get_db_names(){
3059
3060 global $wpdb;
3061
3062 $db_names = array(
3063 'bookings' => $wpdb->prefix . 'booking',
3064 'dates' => $wpdb->prefix . 'bookingdates',
3065 'resources' => $wpdb->prefix . 'bookingtypes',
3066 'resources_meta' => $wpdb->prefix . 'booking_types_meta',
3067 'seasons' => $wpdb->prefix . 'booking_seasons',
3068 'coupons' => $wpdb->prefix . 'booking_coupons'
3069 );
3070
3071 return $db_names;
3072 }
3073
3074 // </editor-fold>
3075
3076
3077 // <editor-fold defaultstate="collapsed" desc=" E r r o r s H a n d l i n g " >
3078
3079 /**
3080 * PHP Fatal Error! Display expanded error info at Booking Listing page
3081 *
3082 * @param $message
3083 * @param $error
3084 *
3085 * @return mixed|string
3086 */
3087 function wpbc_php_error_message( $message, $error ) {
3088
3089 // Check to show this error, only from Booking Listing page, checking secure parameters from wpbc_ajx_booking_listing in ..{Booking Calendar Folder}/includes/page-bookings/_src/ajx_booking_listing.js
3090 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
3091 if ( ! ( ! isset( $_POST['search_params'] ) || empty( $_POST['search_params'] ) ) ) {
3092 // Security ----------------------------------------------------------------------------------------------- // in Ajax Post: 'nonce': wpbc_ajx_booking_listing.get_secure_param( 'nonce' ),
3093 $action_name = 'wpbc_ajx_booking_listing_ajx' . '_wpbcnonce';
3094 $nonce_post_key = 'nonce';
3095 // $result_check = check_ajax_referer( $action_name, $nonce_post_key );
3096 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
3097 if ( isset( $_REQUEST[ $nonce_post_key ] ) ) {
3098 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
3099 $nonce_request = $_REQUEST[ $nonce_post_key ];
3100
3101 $result_verify_nonce = wp_verify_nonce( $nonce_request, $action_name );
3102
3103 if ( false !== $result_verify_nonce ) {
3104 if ( ( ! empty( $error ) ) && ( ! empty( $error['message'] ) ) ) {
3105 $message .= '<br>' . $error['message'];
3106 }
3107 }
3108 }
3109 }
3110
3111 return $message;
3112 }
3113 add_filter( 'wp_php_error_message', 'wpbc_php_error_message', 2 , 10 );
3114
3115
3116 /**
3117 * Nonce Error! Error Handing for not passed nonce, in booking Listing page.
3118 * Probably nonce was expired (more than 24 hours)
3119 *
3120 * @param $action
3121 * @param $result - 1 Good ( 0-12 hours ago ) , 2 Good ( 12-24 hours ago ) , false - Error ( > 24 hours - nonce is invalid )
3122 */
3123 function wpbc_check_ajax_referer__for_booking_listing( $action, $result ){
3124 if (
3125 ( false === $result )
3126 && ( 'wpbc_ajx_booking_listing_ajx' . '_wpbcnonce' === $action )
3127 && ( wp_doing_ajax() )
3128 ) {
3129 die( '<strong>Error!</strong> Probably nonce for this page has been expired. Please <a href="javascript:void(0)" onclick="javascript:location.reload();">reload the page</a>.' );
3130 }
3131 }
3132 add_action( 'check_ajax_referer', 'wpbc_check_ajax_referer__for_booking_listing', 2, 10 );
3133 // </editor-fold>
3134