PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 All 204 releases
← All changes | core/wpbc-js-vars.php +135 -61 10.10.111.8.4 View file →
@@ -1,4 +1,4 @@
1 1 <?php /**
2 2 * @version 1.0
3 3 * @package Booking Calendar - JavaScript
4 4 * @category Define JavaScript variables
@@ -9,42 +9,56 @@
9 9 *
10 10 * @modified 19.10.2015
11 11 */
12 12
13 -if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
13 +if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly.
14 14
15 -
16 15 /**
17 - * Get script string for localised variables.
16 + * Set local today date ( can depend from the parameters in shortcode: [booking resource_id=1 calendar_dates_start='2025-01-01' calendar_dates_end='2025-12-31'] )
18 17 *
18 + * @param $start_it - default 'now', but you can pass date: '2024-07-26' (usually from the past to set ability to select the time slots in the past).
19 + *
19 20 * @return string
20 21 */
21 -function wpbc_get_localized_js_vars() {
22 +function wpbc_get_localized_js__time_local( $start_it = 'now' ) {
22 23
23 - // $script = 'var1 = '. wp_json_encode('var1') .'; '; // JSON.parse(wpbc_global_var); //.
24 + $script = '';
25 + // FixIn: 10.8.1.4.
26 + $gmt_time = gmdate( 'Y-m-d H:i:s', strtotime( $start_it ) );
24 27
25 - $script = '';
26 - $script .= "_wpbc.set_other_param( 'locale_active', '" . esc_js( wpbc_get_maybe_reloaded_booking_locale() ) . "' ); ";
28 + if ( ( isset( $_REQUEST['allow_past'] ) ) || ( wpbc_is_new_booking_page() && ( isset( $_GET['booking_hash'] ) ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
29 + // Get time in past. //FixIn: 10.10.3.2.
30 + $gmt_time = gmdate( 'Y-m-d H:i:s', strtotime( '-' . intval( wpbc_get_max_visible_days_in_calendar() ) . ' days' ) ); // - 365 days or more
31 + }
27 32
28 - // FixIn: 10.8.1.4.
29 - $gmt_time = gmdate( 'Y-m-d H:i:s', strtotime( 'now' ) );
33 + $gmt_csv = wpbc_datetime_localized__no_wp_timezone( $gmt_time, 'Y,m,d,H,i' );
34 + $local_csv = wpbc_datetime_localized__use_wp_timezone( $gmt_time, 'Y,m,d,H,i' );
30 35
31 - $script .= "_wpbc.set_other_param( 'time_gmt_arr', [" . wpbc_datetime_localized__no_wp_timezone( $gmt_time, 'Y,m,d,H,i' ) . '] ); ';
32 - $script .= "_wpbc.set_other_param( 'time_local_arr', [" . wpbc_datetime_localized__use_wp_timezone( $gmt_time, 'Y,m,d,H,i' ) . '] ); ';
36 + $gmt_arr = wpbc_csv_numbers_to_int_array( $gmt_csv );
37 + $local_arr = wpbc_csv_numbers_to_int_array( $local_csv );
33 38
39 + $script .= "_wpbc.set_other_param('time_gmt_arr', " . wp_json_encode( $gmt_arr ) . " ); ";
40 + $script .= "_wpbc.set_other_param('time_local_arr', " . wp_json_encode( $local_arr ) . " ); ";
41 +
42 +// $script .= "_wpbc.set_other_param( 'time_gmt_arr', [" . wpbc_set_csd_as_int( wpbc_datetime_localized__no_wp_timezone( $gmt_time, 'Y,m,d,H,i' ) ) . '] ); ';
43 +// $script .= "_wpbc.set_other_param( 'time_local_arr', [" . wpbc_set_csd_as_int( wpbc_datetime_localized__use_wp_timezone( $gmt_time, 'Y,m,d,H,i' ) ) . '] ); ';
44 +
34 45 $unavailable_time_from_today = get_bk_option( 'booking_unavailable_days_num_from_today' );
35 46
36 47 if ( ! empty( $unavailable_time_from_today ) ) {
37 48 if ( 'm' === substr( $unavailable_time_from_today, - 1 ) ) {
38 49
39 - $gmt_time = gmdate( 'Y-m-d H:i:s', strtotime( '+' . ( intval( $unavailable_time_from_today ) - 1 ) . ' minutes' ) );
50 + // Get time ONLY, if it is not in past. //FixIn: 10.10.3.2.
51 + if ( ( ! isset( $_REQUEST['allow_past'] ) ) && ( ! ( wpbc_is_new_booking_page() && ( isset( $_GET['booking_hash'] ) ) ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
52 + $gmt_time = gmdate( 'Y-m-d H:i:s', strtotime( '+' . ( intval( $unavailable_time_from_today ) - 1 ) . ' minutes' ) );
53 + }
40 54
41 55 // Local timezone unavailable time. // FixIn: 10.9.6.3.
42 56 $local_unavailable_datetime_ymdhis = wpbc_datetime_localized__use_wp_timezone( $gmt_time, 'Y-m-d H:i:s' ); // Local unavailable.
43 57 // Local timezone Now time.
44 - $local_now_datetime_ymdhis = wpbc_datetime_localized__use_wp_timezone( strtotime( 'now' ), 'Y-m-d H:i:s' ); // Local Now.
58 + $local_now_datetime_ymdhis = wpbc_datetime_localized__use_wp_timezone( strtotime( $start_it ), 'Y-m-d H:i:s' ); // Local Now.
45 59 // Local timezone Today midnight time.
46 - $local_now_datetime_ymd000 = wpbc_datetime_localized__use_wp_timezone( strtotime( 'now' ), 'Y-m-d 00:00:00' ); // Local Midnight.
60 + $local_now_datetime_ymd000 = wpbc_datetime_localized__use_wp_timezone( strtotime( $start_it ), 'Y-m-d 00:00:00' ); // Local Midnight.
47 61
48 62 // Check time from local MIDNIGHT to Unavailable.
49 63 $days_number_shift = intval( ( strtotime( $local_unavailable_datetime_ymdhis ) - strtotime( $local_now_datetime_ymd000 ) ) / 86400 );
50 64 $unavailable_time_from_today = $days_number_shift;
@@ -53,12 +67,34 @@
53 67 } else {
54 68 $unavailable_time_from_today = '0';
55 69 }
56 70
57 - $today_local = wpbc_datetime_localized__use_wp_timezone( $gmt_time, 'Y,m,d,H,i' );
71 + $today_local_csv = wpbc_datetime_localized__use_wp_timezone( $gmt_time, 'Y,m,d,H,i' );
72 + $today_arr = wpbc_csv_numbers_to_int_array( $today_local_csv );
58 73
59 - $script .= "_wpbc.set_other_param( 'today_arr', [" . $today_local . "] ); ";
74 + $script .= "_wpbc.set_other_param( 'today_arr', " . wp_json_encode( $today_arr ) . " ); ";
60 75
76 + // FixIn: 10.8.1.4.
77 + $script .= "_wpbc.set_other_param( 'availability__unavailable_from_today', '" . esc_js( $unavailable_time_from_today ) . "' ); "; //Default: 0 ' Old JS: block_some_dates_from_today' _wpbc.get_other_param( 'availability__unavailable_from_today' )
78 +
79 + return $script;
80 +}
81 +
82 +
83 +/**
84 + * Get script string for localised variables.
85 + *
86 + * @return string
87 + */
88 +function wpbc_get_localized_js_vars() {
89 +
90 + // $script = 'var1 = '. wp_json_encode('var1') .'; '; // JSON.parse(wpbc_global_var); //.
91 +
92 + $script = '';
93 + $script .= "_wpbc.set_other_param( 'locale_active', '" . esc_js( wpbc_get_maybe_reloaded_booking_locale() ) . "' ); ";
94 +
95 + $script .= wpbc_get_localized_js__time_local();
96 +
61 97 $script .= "_wpbc.set_other_param( 'url_plugin', '" . esc_url( plugins_url( '', WPBC_FILE ) ) . "' ); ";
62 98
63 99 $get_booking_hash = ( ( isset( $_GET['booking_hash'] ) ) ? sanitize_text_field( wp_unslash( $_GET['booking_hash'] ) ) : '' ); /* phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing */ /* FixIn: sanitize_unslash */
64 100
@@ -68,10 +104,8 @@
68 104 $script .= "_wpbc.set_other_param( 'calendars__on_this_page', [] ); ";
69 105
70 106 $script .= "_wpbc.set_other_param( 'calendars__first_day', '" . intval( get_bk_option( 'booking_start_day_weeek' ) ) . "' ); "; //."\n";
71 107 $script .= "_wpbc.set_other_param( 'calendars__max_monthes_in_calendar', '" . esc_js( get_bk_option( 'booking_max_monthes_in_calendar' ) ) . "' ); ";
72 - // FixIn: 10.8.1.4.
73 - $script .= "_wpbc.set_other_param( 'availability__unavailable_from_today', '" . esc_js( $unavailable_time_from_today ) . "' ); "; //Default: 0 ' Old JS: block_some_dates_from_today' _wpbc.get_other_param( 'availability__unavailable_from_today' )
74 108 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
75 109 $script .= "_wpbc.set_other_param( 'availability__available_from_today', '" . esc_js( get_bk_option( 'booking_available_days_num_from_today' ) ) . "' ); "; //Default '' - all days. Old JS: 'wpbc_available_days_num_from_today'
76 110 }
77 111 $script .= "_wpbc.set_other_param( 'availability__week_days_unavailable', ["
@@ -110,8 +144,11 @@
110 144 ( function_exists( 'wpbc_is_booking_used_check_in_out_time' ) )
111 145 && ( wpbc_is_booking_used_check_in_out_time() )
112 146 ) ? 'true' : 'false'
113 147 ) . " ); ";
148 +
149 + $script .= "_wpbc.set_other_param( 'is_enabled_booking_timeslot_picker', " . ( ( 'On' === get_bk_option( 'booking_timeslot_picker' ) ) ? 'true' : 'false' ) . " ); ";
150 +
114 151 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
115 152 $script .= "_wpbc.set_other_param( 'is_enabled_booking_search_results_days_select', '" . esc_js( get_bk_option( 'booking_search_results_days_select' ) ) . "' ); ";
116 153 }
117 154
@@ -117,64 +154,101 @@
117 154
118 155 $script .= "_wpbc.set_other_param( 'update', '" . esc_attr( WP_BK_VERSION_NUM ) . "' ); ";
119 156 $script .= "_wpbc.set_other_param( 'version', '" . wpbc_get_version_type__and_mu() . "' ); ";
120 157
121 - // Warning Messages.
122 - $script .= "_wpbc.set_message( 'message_dates_times_unavailable', " . wp_json_encode( __( 'These dates and times in this calendar are already booked or unavailable.', 'booking' ) ) . " ); ";
123 - $script .= "_wpbc.set_message( 'message_choose_alternative_dates', " . wp_json_encode( __( 'Please choose alternative date(s), times, or adjust the number of slots booked.', 'booking' ) ) . " ); ";
124 - $script .= "_wpbc.set_message( 'message_cannot_save_in_one_resource', " . wp_json_encode( __( 'It is not possible to store this sequence of the dates into the one same resource.', 'booking' ) ) . " ); ";
125 - $script .= "_wpbc.set_message( 'message_check_required', " . wp_json_encode( __( 'This field is required', 'booking' ) ) . " ); ";
126 - $script .= "_wpbc.set_message( 'message_check_required_for_check_box', " . wp_json_encode( __( 'This checkbox must be checked', 'booking' ) ) . " ); ";
127 - $script .= "_wpbc.set_message( 'message_check_required_for_radio_box', " . wp_json_encode( __( 'At least one option must be selected', 'booking' ) ) . " ); ";
128 - $script .= "_wpbc.set_message( 'message_check_email', " . wp_json_encode( __( 'Incorrect email address', 'booking' ) ) . " ); ";
129 - $script .= "_wpbc.set_message( 'message_check_same_email', " . wp_json_encode( __( 'Your emails do not match', 'booking' ) ) . " ); ";
130 - $script .= "_wpbc.set_message( 'message_check_no_selected_dates', " . wp_json_encode( __( 'Please, select booking date(s) at Calendar.', 'booking' ) ) . " ); ";
131 - $script .= "_wpbc.set_message( 'message_processing', " . wp_json_encode( __( 'Processing', 'booking' ) ) . " ); ";
132 - $script .= "_wpbc.set_message( 'message_deleting', " . wp_json_encode( __( 'Deleting', 'booking' ) ) . " ); ";
133 - $script .= "_wpbc.set_message( 'message_updating', " . wp_json_encode( __( 'Updating', 'booking' ) ) . " ); ";
134 - $script .= "_wpbc.set_message( 'message_saving', " . wp_json_encode( __( 'Saving', 'booking' ) ) . " ); ";
135 - $script .= "_wpbc.set_message( 'message_error_check_in_out_time', " . wp_json_encode( __( 'Error! Please reset your check-in/check-out dates above.', 'booking' ) ) . " ); ";
136 - $script .= "_wpbc.set_message( 'message_error_start_time', " . wp_json_encode( __( 'Start Time is invalid. The date or time may be booked, or already in the past! Please choose another date or time.', 'booking' ) ) . " ); ";
137 - $script .= "_wpbc.set_message( 'message_error_end_time', " . wp_json_encode( __( 'End Time is invalid. The date or time may be booked, or already in the past. The End Time may also be earlier that the start time, if only 1 day was selected! Please choose another date or time.', 'booking' ) ) . " ); ";
138 - $script .= "_wpbc.set_message( 'message_error_range_time', " . wp_json_encode( __( 'The time(s) may be booked, or already in the past!', 'booking' ) ) . " ); ";
139 - $script .= "_wpbc.set_message( 'message_error_duration_time', " . wp_json_encode( __( 'The time(s) may be booked, or already in the past!', 'booking' ) ) . " ); ";
158 + // Visitor-facing messages resolve through one multilingual, plain-text registry.
159 + foreach ( array_keys( wpbc_frontend_messages__get_registry() ) as $message_key ) {
160 + $script .= '_wpbc.set_message( ' . wp_json_encode( $message_key ) . ', ' . wp_json_encode( wpbc_frontend_messages__get( $message_key ) ) . ' ); ';
161 + }
162 +
163 + // Internal/admin progress messages remain gettext-controlled and cannot be customized from the booking-form page.
164 + $script .= "_wpbc.set_message( 'message_processing', " . wp_json_encode( __( 'Processing', 'booking' ) ) . " ); ";
165 + $script .= "_wpbc.set_message( 'message_deleting', " . wp_json_encode( __( 'Deleting', 'booking' ) ) . " ); ";
166 + $script .= "_wpbc.set_message( 'message_updating', " . wp_json_encode( __( 'Updating', 'booking' ) ) . " ); ";
167 + $script .= "_wpbc.set_message( 'message_saving', " . wp_json_encode( __( 'Saving', 'booking' ) ) . " ); ";
168 + $script .= "_wpbc.set_message( 'message_error_check_in_out_time', " . wp_json_encode( __( 'Error! Please reset your check-in/check-out dates above.', 'booking' ) ) . " ); ";
140 169
141 - $script .= "console.log( '== WPBC VARS " . esc_attr( WP_BK_VERSION_NUM ) . ' [' . wpbc_get_version_type__and_mu() . "] LOADED ==' );";
170 + // $script .= "console.log( '== WPBC VARS " . esc_attr( WP_BK_VERSION_NUM ) . ' [' . wpbc_get_version_type__and_mu() . "] LOADED ==' );";
171 + $script .= "console.log( '== WPBC VARS " . esc_attr( wpbc_get_wpbc_versions_numbers() ) . ' [' . wpbc_get_version_type__and_mu() . "] LOADED ==' );";
142 172 return $script;
143 173 }
144 174
145 175
176 +// FixIn: 10.14.4.2. (loader made cache-proof)
146 177 /**
147 - * Define General inline JavaScript variables for the Booking Calendar
148 - * This function run after ENQUEUE of WPBC JavaScript files
178 + * Print inline JS for Booking Calendar that initializes safely even with cache plugins (delay/defer/on-interaction).
149 179 *
150 - * @param string $where_to_load - 'both'.
180 + * @param string $where_to_load 'both' by default.
151 181 *
152 182 * @return void
153 183 */
154 184 function wpbc_localize_js_vars( $where_to_load = 'both' ) {
155 185
156 - $script_before = 'var wpbc_url_ajax =' . wp_json_encode( admin_url( 'admin-ajax.php' ) ) . ';';
186 + // Allow disabling, if needed.
187 + if ( apply_filters( 'wpbc_disable_inline_bootstrap', false, $where_to_load ) ) {
188 + return;
189 + }
190 +
191 + // 1) BEFORE: essentials used by inlines or deferred scripts. - Define both a global var and window property for maximum compatibility.
192 + $script_before = 'var wpbc_url_ajax = ' . wp_json_encode( admin_url( 'admin-ajax.php' ) ) . ';' . 'window.wpbc_url_ajax = wpbc_url_ajax;';
157 193 wp_add_inline_script( 'wpbc_all', $script_before, 'before' );
158 194
159 - $script = wpbc_get_localized_js_vars();
195 + // 2) Existing payload (calls to _wpbc.set_other_param, _wpbc.set_message, …).
196 + $payload_js = wpbc_get_localized_js_vars();
160 197
161 - // Load this _wpbc only after loading of all scripts // FixIn: 10.1.3.4.
162 - $script = ' function wpbc_init__head(){ ' . $script . ' } ';
163 - $script .= "( function() { if ( document.readyState === 'loading' ){ document.addEventListener( 'DOMContentLoaded', wpbc_init__head ); } else { wpbc_init__head(); } }() );";
198 + // 3) Robust bootstrap: runs payload only when _wpbc is ready.
199 + $max_wait_ms = (int) apply_filters( 'wpbc_js_bootstrap_max_wait_ms', 10000 ); // 10s cap
200 + $poll_interval_ms = (int) apply_filters( 'wpbc_js_bootstrap_poll_interval_ms', 50 ); // 50ms
201 + $custom_events = (array) apply_filters( 'wpbc_js_bootstrap_ready_events', array( 'wpbc-ready', 'wpbc:ready', 'wpbc_ready', 'wpbcReady' ) );
202 + $user_events = (array) apply_filters( 'wpbc_js_bootstrap_user_events', array( 'click', 'mousemove', 'touchstart', 'keydown', 'scroll' ) );
164 203
165 - wp_add_inline_script( 'wpbc_all', $script );
166 -
167 - /**
168 - * Help info. Order of JS events:
169 - *
170 - * window.addEventListener("load", (event) => { log.textContent += "load\n"; }); -> window.onload (which is implemented even in old browsers), which fires when the entire page loads (images, styles, etc.)
171 - * document.addEventListener("readystatechange", (event) => { log.textContent += `readystate: ${document.readyState}\n`; });
172 - * document.addEventListener("DOMContentLoaded", (event) => { log.textContent += "DOMContentLoaded\n"; }); -> newish event which fires when the document's DOM is loaded (which may be some time before the images, etc. are loaded);
173 - * ::
174 - * DOMContentLoaded
175 - * readystate: complete
176 - * load
177 - */
204 + $boot_js = '(function(){' . "\n" .
205 + '"use strict";' . "\n" .
206 + 'function wpbc_init__head(){' . $payload_js . '}' . "\n" .
207 + '(function(){' . "\n" .
208 + ' if (window.__wpbc_boot_done__ === true) return;' . "\n" .
209 + // global guard across duplicates.
210 + ' var started = false;' . "\n" .
211 + ' function run_once(){' . "\n" .
212 + ' if (started || window.__wpbc_boot_done__ === true) return true;' . "\n" .
213 + ' started = true;' . "\n" .
214 + ' try { wpbc_init__head(); window.__wpbc_boot_done__ = true; }' . "\n" .
215 + ' catch(e){ started = false; try{console.error("WPBC init failed:", e);}catch(_){} }' . "\n" .
216 + ' return (window.__wpbc_boot_done__ === true);' . "\n" .
217 + ' }' . "\n" .
218 + // Fast path.
219 + ' function is_ready(){ return !!(window._wpbc && typeof window._wpbc.set_other_param === "function"); }' . "\n" .
220 + ' if ( is_ready() && run_once() ) return;' . "\n" .
221 + // Polling fallback (covers delayed/deferred/on-interaction loaders).
222 + ' var waited = 0, max_ms = ' . $max_wait_ms . ', step = ' . $poll_interval_ms . ';' . "\n" .
223 + ' var timer = setInterval(function(){' . "\n" .
224 + ' if ( is_ready() && run_once() ) { clearInterval(timer); return; }' . "\n" .
225 + ' waited += step;' . "\n" .
226 + ' if ( waited >= max_ms ) {' . "\n" .
227 + ' clearInterval(timer);' . "\n" .
228 + ' // Switch to slow polling (1s) so we still init even without user interaction later.' . "\n" .
229 + ' var slow = setInterval(function(){ if ( is_ready() && run_once() ) clearInterval(slow); }, 1000);' . "\n" .
230 + ' try{console.warn("WPBC: _wpbc not detected within " + max_ms + "ms; using slow polling.");}catch(_){}' . "\n" .
231 + ' }' . "\n" .
232 + ' }, step);' . "\n" .
233 + // Listen for your custom ready events (emit from core once _wpbc is ready).
234 + ' var evs = ' . wp_json_encode( array_values( $custom_events ) ) . ';' . "\n" .
235 + ' evs.forEach(function(name){' . "\n" .
236 + ' document.addEventListener(name, function onready(){ if (is_ready() && run_once()) document.removeEventListener(name, onready); });' . "\n" .
237 + ' });' . "\n" .
238 + // Standard lifecycle events (covers DOMContentLoaded + load).
239 + ' if (document.readyState === "loading") {' . "\n" .
240 + ' document.addEventListener("DOMContentLoaded", function(){ if (is_ready()) run_once(); }, { once:true });' . "\n" .
241 + ' }' . "\n" .
242 + ' window.addEventListener("load", function(){ if (is_ready()) run_once(); }, { once:true });' . "\n" .
243 + ' window.addEventListener("pageshow", function(){ if (is_ready()) run_once(); }, { once:true });' . "\n" .
244 + ' document.addEventListener("visibilitychange", function(){ if (!document.hidden && is_ready()) run_once(); });' . "\n" .
245 + // User interaction hooks — some cache plugins load delayed JS only after interaction.
246 + ' var ui = ' . wp_json_encode( array_values( $user_events ) ) . ';' . "\n" .
247 + ' var ui_bailed = false;' . "\n" .
248 + ' function on_ui(){ if (ui_bailed) return; if (is_ready() && run_once()){ ui_bailed = true; ui.forEach(function(t){ document.removeEventListener(t, on_ui, true); }); } }' . "\n" .
249 + ' ui.forEach(function(t){ document.addEventListener(t, on_ui, true); });' . "\n" .
250 + '})();' . "\n" .
251 + '})();';
252 + wp_add_inline_script( 'wpbc_all', $boot_js );
178 253 }
179 -add_action( 'wpbc_enqueue_js_files', 'wpbc_localize_js_vars', 51 ); // Need to set here 51, because some JS has 50 priority, for example at WP Booking Calendar > Availability > Days Availability page -> This hook fired after ENQUEUE of WPBC JS - wp_enqueue_script
180 -
254 +add_action( 'wpbc_enqueue_js_files', 'wpbc_localize_js_vars', 51 );