PluginProbe
Booking Calendar / 11.4.3
Booking Calendar v11.4.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 / _capacity / calendar_load.php

calendar_load.php in Booking Calendar 11.4.3, at includes/_capacity/calendar_load.php

530 lines 31.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @file: wp-content/plugins/booking/includes/_capacity/calendar_load.php
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly // FixIn: 9.8.0.4.
7
8 /**
9 * Define parameters for calendar -- required for JS calendar show
10 *
11 * @param array $params
12 *
13 * @return string JS code body (no <script> wrapper)
14 */
15 function wpbc__calendar__set_js_params__before_show( $params ) {
16
17 $start_script_code = '';
18
19 // Server Balancer.
20 $balancer_max_threads = intval( get_bk_option( 'booking_load_balancer_max_threads' ) );
21 $balancer_max_threads = ( empty( $balancer_max_threads ) ) ? 1 : $balancer_max_threads;
22 $start_script_code .= " _wpbc.balancer__set_max_threads( " . $balancer_max_threads . " ); ";
23
24 $resource_id = isset( $params['resource_id'] ) ? absint( $params['resource_id'] ) : 1;
25
26 if ( function_exists( 'wpbc_is_booking_used_check_in_out_time' ) ) {
27 $is_enabled_change_over = wpbc_is_booking_used_check_in_out_time( false, $resource_id );
28 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'is_enabled_change_over' , " . ( $is_enabled_change_over ? 'true' : 'false' ) . " ); ";
29 $start_script_code .= " _wpbc.set_other_param( 'is_enabled_change_over', " . ( $is_enabled_change_over ? 'true' : 'false' ) . " ); ";
30 }
31
32 // Start Month (require [year,month]).
33 $calendar_scroll_to = 'false';
34 if (
35 isset( $params['start_month_calendar'] )
36 && is_array( $params['start_month_calendar'] )
37 && ( count( $params['start_month_calendar'] ) > 1 )
38 ) {
39 $y = intval( $params['start_month_calendar'][0] );
40 $m = intval( $params['start_month_calendar'][1] );
41 if ( ( $y > 0 ) && ( $m > 0 ) ) {
42 $calendar_scroll_to = "[ " . (string) $y . "," . (string) $m . " ]";
43 }
44 }
45 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'calendar_scroll_to' , " . $calendar_scroll_to . " ); ";
46
47 // Set Start / End Date in Calendar (JSON encode => safe quotes).
48 $params['calendar_dates_start'] = ( empty( $params['calendar_dates_start'] ) ) ? '' : (string) $params['calendar_dates_start'];
49 $params['calendar_dates_end'] = ( empty( $params['calendar_dates_end'] ) ) ? '' : (string) $params['calendar_dates_end'];
50
51 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'calendar_dates_start' , " . wp_json_encode( $params['calendar_dates_start'] ) . " ); ";
52 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'calendar_dates_end' , " . wp_json_encode( $params['calendar_dates_end'] ) . " ); ";
53
54 if ( ( '' !== $params['calendar_dates_start'] ) || ( '' !== $params['calendar_dates_end'] ) ) {
55 $start_script_code .= wpbc_get_localized_js__time_local( $params['calendar_dates_start'] );
56 }
57
58 // Max months to scroll.
59 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_max_monthes_in_calendar' , " . wp_json_encode( (string) get_bk_option( 'booking_max_monthes_in_calendar' ) ) . " ); ";
60
61 // Start of week day.
62 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_start_day_weeek' , " . wp_json_encode( (string) get_bk_option( 'booking_start_day_weeek' ) ) . " ); ";
63
64 // Number of visible months.
65 $months_num = isset( $params['calendar_number_of_months'] ) ? (int) $params['calendar_number_of_months'] : 1;
66 $months_num = max( 1, min( 36, $months_num ) );
67 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'calendar_number_of_months' , " . wp_json_encode( (string) $months_num ) . " ); ";
68
69 // Days Selection.
70 $days_selection_arr = wpbc__calendar__js_params__get_days_selection_arr();
71
72 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'days_select_mode', " . wp_json_encode( (string) $days_selection_arr['days_select_mode'] ) . " ); ";
73 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'fixed__days_num', " . intval( $days_selection_arr['fixed__days_num'] ) . " ); ";
74
75 // Keep legacy: these are stored as comma lists like "-1" or "0,1".
76 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'fixed__week_days__start', [" . $days_selection_arr['fixed__week_days__start'] . "] ); ";
77 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'dynamic__days_min', " . intval( $days_selection_arr['dynamic__days_min'] ) . " ); ";
78 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'dynamic__days_max', " . intval( $days_selection_arr['dynamic__days_max'] ) . " ); ";
79 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'dynamic__days_specific', [" . $days_selection_arr['dynamic__days_specific'] . "] ); ";
80 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'dynamic__week_days__start', [" . $days_selection_arr['dynamic__week_days__start'] . "] ); ";
81
82 // Informational help shown between the first and second clicks in range mode.
83 // Integrations can disable it per calendar/resource without changing the selection engine.
84 /**
85 * Filters whether the two-click range-selection guidance is shown for a calendar.
86 *
87 * @param bool $is_enabled Whether guidance is enabled.
88 * @param int $resource_id Booking resource ID.
89 * @param array $params Calendar shortcode/render parameters.
90 */
91 $range_selection_guidance_default = function_exists( 'wpbc_frontend_messages__is_enabled' )
92 ? wpbc_frontend_messages__is_enabled( 'message_range_selection_click_last_date' )
93 : true;
94 $range_selection_guidance_is_enabled = (bool) apply_filters(
95 'wpbc_calendar_range_selection_guidance_is_enabled',
96 $range_selection_guidance_default,
97 $resource_id,
98 $params
99 );
100 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'range_selection_guidance_is_enabled', " . ( $range_selection_guidance_is_enabled ? 'true' : 'false' ) . " ); ";
101
102 // Date / Time formats.
103 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'booking_date_format', " . wp_json_encode( (string) get_bk_option( 'booking_date_format' ) ) . " ); ";
104 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'booking_time_format', " . wp_json_encode( (string) get_bk_option( 'booking_time_format' ) ) . " ); ";
105
106 // Capacity | availability.
107 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
108 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'is_parent_resource' , " . ( wpbc_get_child_resources_number( $resource_id ) ? 1 : 0 ) . " ); ";
109 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_capacity_field' , " . wp_json_encode( (string) wpbc_get__booking_capacity_field__name() ) . " ); ";
110 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_is_dissbale_booking_for_different_sub_resources' , " . wp_json_encode( (string) get_bk_option( 'booking_is_dissbale_booking_for_different_sub_resources' ) ) . " ); ";
111 }
112 if ( class_exists( 'wpdev_bk_biz_s' ) ) {
113 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . " , 'booking_recurrent_time' , " . wp_json_encode( (string) get_bk_option( 'booking_recurrent_time' ) ) . " ); ";
114 }
115
116 // Save initial values of days selection for later use in conditional day logic.
117 $start_script_code .= " if ( 'function' === typeof ( wpbc__conditions__SAVE_INITIAL__days_selection_params__bm ) ) { wpbc__conditions__SAVE_INITIAL__days_selection_params__bm( " . $resource_id . " ); } ";
118
119 if (
120 ( ! empty( $params['shortcode_options'] ) )
121 && ( function_exists( 'wpbc_parse_shortcode_option__set_days_selection_conditions' ) )
122 ) {
123 $days_selection_conditions = wpbc_parse_shortcode_option__set_days_selection_conditions( $resource_id, $params['shortcode_options'] );
124
125 if ( ! empty( $days_selection_conditions ) ) {
126 $start_script_code .= " _wpbc.calendar__set_param_value( " . $resource_id . ", 'conditions', " . wp_json_encode( $days_selection_conditions['conditions'] ) . " ); ";
127 $start_script_code .= " _wpbc.seasons__set( " . $resource_id . ", " . wp_json_encode( $days_selection_conditions['seasons'] ) . " ); ";
128 }
129 }
130
131 return $start_script_code;
132 }
133
134
135 /**
136 * Get days selection parameters, which saved in database
137 *
138 * @return array
139 */
140 function wpbc__calendar__js_params__get_days_selection_arr(){
141
142 $specific_days_selection = ( function_exists( 'wpbc_get_specific_range_dates__as_comma_list' ) )
143 ? wpbc_get_specific_range_dates__as_comma_list( get_bk_option( 'booking_range_selection_days_specific_num_dynamic' ) )
144 : '';
145 $data_arr = array();
146 // Modes :: Selection of Days.
147 $day_selection_type = get_bk_option( 'booking_type_of_day_selections' );
148 if ( 'range' === $day_selection_type ) {
149 // Free/Personal use the unrestricted two-click range. Business Small+ can apply its saved range subtype/rules.
150 $data_arr['days_select_mode'] = class_exists( 'wpdev_bk_biz_s' )
151 ? get_bk_option( 'booking_range_selection_type' )
152 : 'dynamic';
153 } else {
154 $data_arr['days_select_mode'] = $day_selection_type;
155 }
156 $fixed_days_num = absint( get_bk_option( 'booking_range_selection_days_count' ) );
157 $data_arr['fixed__days_num'] = ( 0 < $fixed_days_num ) ? min( 180, $fixed_days_num ) : 3; /* Number of days selection with 1 mouse click */
158 $data_arr['fixed__week_days__start'] = get_bk_option( 'booking_range_start_day' ); /* { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat } */
159 $data_arr['dynamic__days_min'] = intval( get_bk_option( 'booking_range_selection_days_count_dynamic' ) ); /* Min. Number of days selection with 2 mouse clicks */
160 $data_arr['dynamic__days_max'] = intval( get_bk_option( 'booking_range_selection_days_max_count_dynamic' ) ); /* Max. Number of days selection with 2 mouse clicks */
161 $data_arr['dynamic__days_specific'] = $specific_days_selection; /* Example: '5,7' */
162 $data_arr['dynamic__week_days__start'] = get_bk_option( 'booking_range_start_day_dynamic' ); /* { -1 - Any | 0 - Su, 1 - Mo, 2 - Tu, 3 - We, 4 - Th, 5 - Fr, 6 - Sat } */
163
164 // A fixed one-click range remains Business Small+. On downgrade, preserve the Range choice but use Free's unrestricted two-click mode.
165 if ( ( ! class_exists( 'wpdev_bk_biz_s' ) ) && ( in_array( $data_arr['days_select_mode'], array( 'dynamic', 'fixed' ), true ) ) ) {
166 $data_arr['days_select_mode'] = 'dynamic';
167 $data_arr['dynamic__days_min'] = 1;
168 $data_arr['dynamic__days_specific'] = '';
169 $data_arr['dynamic__week_days__start'] = '-1';
170 }
171
172 return $data_arr;
173 }
174
175
176
177 /**
178 * Get JavaScript for Calendar Loading:
179 * 1) Show Calendar
180 * 2) Send Ajax to load bookings / availability / data for calendar
181 *
182 * @param array $params
183 *
184 * @return string Either '' (when collected to footer) OR legacy <script>...</script> fallback.
185 */
186 function wpbc__calendar__load( $params = array() ) {
187
188 $defaults = array(
189 'resource_id' => '1',
190 'aggregate_resource_id_arr' => array(),
191 'selected_dates_without_calendar' => '',
192 'calendar_number_of_months' => 1,
193 'start_month_calendar' => false,
194 'shortcode_options' => '',
195 'custom_form' => 'standard',
196 'calendar_dates_start' => '',
197 'calendar_dates_end' => '',
198 'skip_general_availability' => 0,
199 'calendar_request_overrides' => array(),
200 );
201 $params = wp_parse_args( $params, $defaults );
202
203 // Resource ID.
204 $params['resource_id'] = absint( $params['resource_id'] );
205
206 // Build JS BODY (no <script>, no ready wrapper).
207 $js_body = '';
208
209 $js_body .= wpbc__calendar__set_js_params__before_show( $params );
210
211 // Show calendar.
212 $js_body .= " wpbc_calendar_show(" . wp_json_encode( (string) $params['resource_id'] ) . "); ";
213
214 // Security params.
215 $js_body .= " _wpbc.set_secure_param('nonce', " . wp_json_encode( wp_create_nonce( 'wpbc_calendar_load_ajx' . '_wpbcnonce' ) ) . "); ";
216 $js_body .= " _wpbc.set_secure_param('user_id', " . wp_json_encode( (string) wpbc_get_current_user_id() ) . "); ";
217 $js_body .= " _wpbc.set_secure_param('locale', " . wp_json_encode( (string) get_user_locale() ) . "); ";
218
219 // booking_hash (keep legacy GET behavior, sanitized).
220 $get_booking_hash = '';
221 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
222 if ( isset( $_GET['booking_hash'] ) ) {
223 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
224 $raw_hash = wp_unslash( $_GET['booking_hash'] );
225 if ( ! is_array( $raw_hash ) ) {
226 $get_booking_hash = sanitize_text_field( (string) $raw_hash );
227 }
228 }
229
230 // Aggregate type.
231 $aggregate_type = 'all';
232 if (
233 ( ! empty( $params['shortcode_options'] ) )
234 && function_exists( 'wpbc_parse_calendar_options__aggregate_param' )
235 ) {
236 $aggregate_type_res = wpbc_parse_calendar_options__aggregate_param( $params['shortcode_options'] );
237 if ( ( ! empty( $aggregate_type_res ) ) && ( ! empty( $aggregate_type_res['type'] ) ) ) {
238 $aggregate_type = (string) $aggregate_type_res['type'];
239 }
240 }
241
242 // request_uri captured on front-end (legacy rationale).
243 $server_request_uri = '';
244 // phpcs:ignore WordPress.Security.NonceVerification.Missing
245 if ( isset( $_SERVER['REQUEST_URI'] ) ) {
246 // phpcs:ignore WordPress.Security.NonceVerification.Missing
247 $server_request_uri = sanitize_text_field( wp_unslash( (string) $_SERVER['REQUEST_URI'] ) );
248 }
249
250 $params_for_request = array(
251 'resource_id' => $params['resource_id'],
252 'booking_hash' => $get_booking_hash,
253 'request_uri' => $server_request_uri,
254 'custom_form' => (string) $params['custom_form'],
255 'aggregate_resource_id_str' => implode( ',', (array) $params['aggregate_resource_id_arr'] ),
256 'aggregate_type' => (string) $aggregate_type,
257 'skip_general_availability' => (int) $params['skip_general_availability'],
258 );
259
260 if ( ! empty( $params['calendar_request_overrides'] ) && is_array( $params['calendar_request_overrides'] ) ) {
261 foreach ( $params['calendar_request_overrides'] as $override_key => $override_value ) {
262 if ( 0 === strpos( (string) $override_key, 'wpbc_settings_calendar_preview' ) ) {
263 $params_for_request[ $override_key ] = $override_value;
264 }
265 }
266 }
267
268 // Send Ajax request to load bookings.
269 $js_body .= " wpbc_calendar__load_data__ajx(" . wp_json_encode( $params_for_request ) . "); ";
270
271 // ---------------------------------------------------------------------
272 // Elementor-safe path: add inline via WP scripts (footer-safe, not in content). // FixIn: 10.14.13.2.
273 // ---------------------------------------------------------------------
274 $can_use_wp_inline = ( ! wp_doing_ajax() );
275
276 if ( $can_use_wp_inline && class_exists( 'WPBC_FE_Assets' ) ) {
277
278 $assets_key = 'wpbc:cal-load:' . intval( $params['resource_id'] ) . ':' . md5( wp_json_encode( $params_for_request ) );
279
280 // Try after main client script first (best), fallback to wpbc_all if needed.
281 $added = WPBC_FE_Assets::add_jq_ready_js_to_wp_script( 'wpbc-main-client', $js_body, $assets_key );
282 if ( ! $added ) {
283 $added = WPBC_FE_Assets::add_jq_ready_js_to_wp_script( 'wpbc_all', $js_body, $assets_key );
284 }
285
286 if ( $added ) {
287 return ''; // Important: nothing inline in the content.
288 }
289 }
290
291 // ---------------------------------------------------------------------
292 // Legacy fallback: return inline <script>...</script> (Works in rare contexts without wp_footer / without assets manager).
293 // ---------------------------------------------------------------------
294 $start_script_code = '<script type="text/javascript"> ' . wpbc_jq_ready_start() . $js_body . wpbc_jq_ready_end() . '</script>';
295
296 return $start_script_code;
297 }
298
299
300 /**
301 * Get Booking Calendar option names that belong to General Availability rules.
302 *
303 * @return array
304 */
305 function wpbc__calendar__get_general_availability_option_names() {
306
307 $option_names = array(
308 'booking_unavailable_days_num_from_today',
309 'booking_available_days_num_from_today',
310 'booking_unavailable_extra_in_out',
311 'booking_unavailable_extra_minutes_in',
312 'booking_unavailable_extra_minutes_out',
313 'booking_unavailable_extra_days_in',
314 'booking_unavailable_extra_days_out',
315 );
316
317 foreach ( range( 0, 6 ) as $week_day_num ) {
318 $option_names[] = 'booking_unavailable_day' . $week_day_num;
319 }
320
321 return $option_names;
322 }
323
324
325
326 /**
327 * Response to Ajax request, about loading calendar data
328 *
329 * @return void
330 */
331 function ajax_WPBC_AJX_CALENDAR_LOAD() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
332
333 // Security ------------------------------------------------------------------------------------------------------ // in Ajax Post: 'nonce': _wpbc.get_secure_param( 'nonce' ),
334 $action_name = 'wpbc_calendar_load_ajx' . '_wpbcnonce';
335 $nonce_post_key = 'nonce';
336 if ( wpbc_is_use_nonce_at_front_end() ) { // FixIn: 10.1.1.2.
337 $result_check = check_ajax_referer( $action_name, $nonce_post_key );
338 }
339
340 $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
341
342 /**
343 * SQL ---------------------------------------------------------------------------
344 *
345 * in Ajax Post: 'search_params': _wpbc.search_get_all_params()
346 *
347 * Use prefix "search_params", if Ajax sent - $_REQUEST['search_params']['page_num'], $_REQUEST['search_params']['page_items_count'], ...
348 */
349
350 /**
351 * Using this class here only for escaping variables
352 */
353 $user_request = new WPBC_AJX__REQUEST( array(
354 'db_option_name' => 'booking__wpbc_calendar_load__request_params',
355 'user_id' => $user_id,
356 'request_rules_structure' => array(
357 'resource_id' => array( 'validate' => 'd', 'default' => 1 ), // 'digit_or_csd'
358 'booking_hash' => array( 'validate' => 's', 'default' => '' ),
359 'request_uri' => array( 'validate' => 's', 'default' => '' ),
360 'custom_form' => array( 'validate' => 's', 'default' => 'standard' ),
361 'aggregate_resource_id_str' => array( 'validate' => 'digit_or_csd', 'default' => '' ), // Comma separated string of resource ID, which was used in 'aggregate' parameter.
362 'aggregate_type' => array( 'validate' => 's', 'default' => 'all' ), // 'all' | 'bookings_only' // FixIn: 9.8.15.10.
363 'dates_to_check' => array( 'validate' => 'array', 'default' => '' ), // 'all' | 'bookings_only' // FixIn: 9.8.15.10.
364 'skip_general_availability' => array( 'validate' => 'd', 'default' => 0 ),
365 'wpbc_settings_calendar_preview' => array( 'validate' => 'd', 'default' => 0 ),
366 'wpbc_settings_calendar_preview_changeover' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
367 'wpbc_settings_calendar_preview_triangles' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'On' ),
368 'wpbc_settings_calendar_preview_recurrent_time' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
369 'wpbc_settings_calendar_preview_last_checkout' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
370 'wpbc_settings_calendar_preview_excerpt_on_pages' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
371 'wpbc_settings_calendar_preview_excerpt_pages' => array( 'validate' => 's', 'default' => '' ),
372 'wpbc_settings_calendar_preview_excerpt_resources' => array( 'validate' => 's', 'default' => '' ),
373 'wpbc_settings_calendar_preview_show_legend' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
374 'wpbc_settings_calendar_preview_legend_show_numbers' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
375 'wpbc_settings_calendar_preview_legend_vertical' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
376 'wpbc_settings_calendar_preview_legend_show_available' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
377 'wpbc_settings_calendar_preview_legend_text_available' => array( 'validate' => 's', 'default' => '' ),
378 'wpbc_settings_calendar_preview_legend_show_pending' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
379 'wpbc_settings_calendar_preview_legend_text_pending' => array( 'validate' => 's', 'default' => '' ),
380 'wpbc_settings_calendar_preview_legend_show_approved' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
381 'wpbc_settings_calendar_preview_legend_text_approved' => array( 'validate' => 's', 'default' => '' ),
382 'wpbc_settings_calendar_preview_legend_show_partially' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
383 'wpbc_settings_calendar_preview_legend_text_partially' => array( 'validate' => 's', 'default' => '' ),
384 'wpbc_settings_calendar_preview_legend_show_unavailable' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
385 'wpbc_settings_calendar_preview_legend_text_unavailable' => array( 'validate' => 's', 'default' => '' ),
386 'wpbc_settings_calendar_preview_disable_timeslots_tooltip' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
387 'wpbc_settings_calendar_preview_timeslot_word' => array( 'validate' => 's', 'default' => '' ),
388 'wpbc_settings_calendar_preview_show_availability_tooltip' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
389 'wpbc_settings_calendar_preview_availability_word' => array( 'validate' => 's', 'default' => '' ),
390 'wpbc_settings_calendar_preview_show_availability_cell' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
391 'wpbc_settings_calendar_preview_availability_cell_word' => array( 'validate' => 's', 'default' => '' ),
392 'wpbc_settings_calendar_preview_show_cost_tooltip' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
393 'wpbc_settings_calendar_preview_cost_word' => array( 'validate' => 's', 'default' => '' ),
394 'wpbc_settings_calendar_preview_show_cost_cell' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
395 'wpbc_settings_calendar_preview_cost_currency' => array( 'validate' => 's', 'default' => '' ),
396 'wpbc_settings_calendar_preview_show_booked_details' => array( 'validate' => array( 'On', 'Off' ), 'default' => 'Off' ),
397 'wpbc_settings_calendar_preview_booked_details' => array( 'validate' => 's', 'default' => '' ),
398 )
399 )
400 );
401 $request_prefix = 'calendar_request_params';
402 $request_params = $user_request->get_sanitized__in_request__value_or_default( $request_prefix ); // NOT Direct: $_REQUEST['search_params']['resource_id']
403
404 if ( ! empty( $request_params['skip_general_availability'] ) ) {
405 $can_skip_general_availability = (
406 function_exists( 'wpbc_availability_general__get_manage_cap' )
407 && function_exists( 'wpbc_is_mu_user_can_be_here' )
408 && wpbc_is_mu_user_can_be_here( 'only_super_admin' )
409 && current_user_can( wpbc_availability_general__get_manage_cap() )
410 );
411
412 if ( ! $can_skip_general_availability ) {
413 $request_params['skip_general_availability'] = 0;
414 }
415 }
416
417
418 // Do Job here !! -------------------------------------------------------------------------------------------------
419
420 make_bk_action( 'check_pending_unpaid_bookings__do_auto_cancel', $request_params['resource_id'] );
421
422 $skip_booking_id = wpbc_get_booking_id__from_hash_in_url( $request_params['booking_hash'] ); // Booking ID ( like 1101 ) to skip in calendar
423 $max_days_count = wpbc_get_max_visible_days_in_calendar(); // 365 - number of visible days
424 // Resource ID from aggregate parameter in booking shortcode!
425 $aggregate_resource_id_arr = explode( ',', $request_params['aggregate_resource_id_str'] );
426 $aggregate_resource_id_arr = array_filter( $aggregate_resource_id_arr ); // All entries of array equal to FALSE (0, '', '0' ) will be removed.
427 $aggregate_resource_id_arr = array_unique( $aggregate_resource_id_arr ); // Remove duplicates // FixIn: 9.8.15.10.
428 if ( ( $resource_id_key = array_search( $request_params['resource_id'], $aggregate_resource_id_arr ) ) !== false ) {
429 unset( $aggregate_resource_id_arr[ $resource_id_key ] ); // Remove source booking resource from aggregate ARR. // FixIn: 9.8.15.10.
430 }
431 $aggregate_resource_id_arr = array_values($aggregate_resource_id_arr); // Reset keys
432
433 $availability_per_days__params = array(
434 'resource_id' => $request_params['resource_id'],
435 'max_days_count' => $max_days_count,
436 'skip_booking_id' => $skip_booking_id,
437 'request_uri' => $request_params['request_uri'], // It different in Ajax requests than $server_request_uri . It's used for change-over days to detect for exception at specific pages
438 'custom_form' => $request_params['custom_form']
439 , 'additional_bk_types' => $aggregate_resource_id_arr // It is array of booking resources from aggregate parameter() // arrays | CSD | int // OPTIONAL
440 , 'aggregate_type' => $request_params['aggregate_type'] // It is string: 'all' | 'bookings_only' // OPTIONAL
441 , 'skip_general_availability' => $request_params['skip_general_availability']
442 // , 'as_single_resource' => true // get dates as for 'single resource' or 'parent' resource including bookings in all 'child booking resources'
443 // , 'max_days_count' => wpbc_get_max_visible_days_in_calendar() // 365
444 // , 'timeslots_to_check_intersect' => $timeslots_to_check_intersect //TODO 2023-10-25: delete it, because we get it in wpbc_get_availability_per_days_arr() //array( '12:20 - 12:55', '13:00 - 14:00' )
445 );
446
447 if ( ! empty( $request_params['dates_to_check'] ) ) {
448 $availability_per_days__params['dates_to_check'] = $request_params['dates_to_check']; // Usually if defined it is: [ '2025-01-01', '2025-12-31' ], because of shortcode [booking resource_id=4 calendar_dates_start='2025-01-01' calendar_dates_end='2025-12-31' ...]
449 }
450
451 // If in Booking > Add booking page we use in URL .../wp-admin/admin.php?page=wpbc&tab=add-booking&booking_type=2&as_single_resource=1 then get availability only for single resource.
452 if (
453 ( ! empty( $request_params['request_uri'] ) )
454 && ( strpos( $request_params['request_uri'], 'as_single_resource=1' ) !== false )
455 ){
456 $availability_per_days__params['as_single_resource'] = true;
457 }
458
459 /**
460 * Tricks:
461 * if ( wpbc_is_new_booking_page_url( $request_params['request_uri'] ) ) { $availability_per_days__params['is_days_always_available'] = true; }
462 *
463 * // Set dates in calendar always available only for specific resources with specific ID
464 * if ( in_array( $request_params['resource_id'], array( 12, 15, 17 ) ) ) { $availability_per_days__params['is_days_always_available'] = true; }
465 */
466
467 // Get unavailable dates for calendar
468 // $availability_per_days__params['dates_to_check'] = array( '2025-01-01', '2025-12-31' ); // FixIn: 10.13.1.4.
469 global $wpbc__skip_get_bk_options;
470
471 $previous_skip_get_bk_options = $wpbc__skip_get_bk_options;
472 $previous_settings_calendar_preview_options = null;
473 $is_settings_calendar_preview = (
474 function_exists( 'wpbc_settings_calendar__is_calendar_load_preview_request_allowed' )
475 && wpbc_settings_calendar__is_calendar_load_preview_request_allowed( $request_params )
476 );
477 if ( ! empty( $availability_per_days__params['skip_general_availability'] ) ) {
478 $wpbc__skip_get_bk_options = array_unique(
479 array_merge(
480 (array) $wpbc__skip_get_bk_options,
481 wpbc__calendar__get_general_availability_option_names()
482 )
483 );
484 }
485 if ( $is_settings_calendar_preview ) {
486 $previous_settings_calendar_preview_options = wpbc_settings_calendar__preview_options_push(
487 wpbc_settings_calendar__get_calendar_load_preview_options( $request_params )
488 );
489 }
490
491 $availability_per_days_arr = wpbc_get_availability_per_days_arr( $availability_per_days__params );
492 $wpbc__skip_get_bk_options = $previous_skip_get_bk_options;
493 if ( $is_settings_calendar_preview ) {
494 wpbc_settings_calendar__preview_options_pop( $previous_settings_calendar_preview_options );
495 }
496
497
498 $ajx_data_arr = array( /**
499 * Send JSON. It will make "wp_json_encode" - so pass only array, and This function call wp_die( '', '', array( 'response' => null, ) ) .
500 * Pass JS OBJ: response_data in "jQuery.post( " function on success.
501 */
502 'ajx_data' => $availability_per_days_arr,
503 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
504 'ajx_search_params' => $_REQUEST[ $request_prefix ],
505 'ajx_cleaned_params' => $request_params,
506 'resource_id' => $request_params['resource_id'],
507 );
508
509 // FixIn: 10.12.4.6.
510 if ( ! in_array( $request_params['resource_id'], $availability_per_days_arr['resources_id_arr__in_dates'] ) ) {
511 $ajx_data_arr['ajx_data']['ajx_after_action_message'] = 'Wrong ID of booking resource. Probably calendar (booking resource) with ID = ' . intval( $request_params['resource_id'] ) . ' not exists. Please check resource_id parameter in the Booking Calendar shortcode.';
512 }
513
514
515
516 // Show message under calendar, if needed.
517 //$availability_per_days_arr['ajx_after_action_message'] = 'Ta Da :))';
518 //$availability_per_days_arr['ajx_after_action_message_status'] = 'warning';
519
520 // Ajax ------------------------------------------------------------------------------------------------------------
521 wp_send_json( $ajx_data_arr );
522
523 }
524
525 if ( is_admin() && ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) {
526 add_action( 'wp_ajax_nopriv_' . 'WPBC_AJX_CALENDAR_LOAD', 'ajax_' . 'WPBC_AJX_CALENDAR_LOAD' ); // Client (not logged in)
527 add_action( 'wp_ajax_' . 'WPBC_AJX_CALENDAR_LOAD', 'ajax_' . 'WPBC_AJX_CALENDAR_LOAD' ); // Logged In users (or admin panel)
528 }
529
530