| 1 |
<?php /** |
| 2 |
* @version 1.0 |
| 3 |
* @package Booking Calendar - JavaScript |
| 4 |
* @category Define JavaScript variables |
| 5 |
* @author wpdevelop |
| 6 |
* |
| 7 |
* @web-site https://wpbookingcalendar.com/ |
| 8 |
* @email info@wpbookingcalendar.com |
| 9 |
* |
| 10 |
* @modified 19.10.2015 |
| 11 |
*/ |
| 12 |
|
| 13 |
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly. |
| 14 |
|
| 15 |
/** |
| 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'] ) |
| 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 |
* |
| 20 |
* @return string |
| 21 |
*/ |
| 22 |
function wpbc_get_localized_js__time_local( $start_it = 'now' ) { |
| 23 |
|
| 24 |
$script = ''; |
| 25 |
// FixIn: 10.8.1.4. |
| 26 |
$gmt_time = gmdate( 'Y-m-d H:i:s', strtotime( $start_it ) ); |
| 27 |
|
| 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 |
} |
| 32 |
|
| 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' ); |
| 35 |
|
| 36 |
$gmt_arr = wpbc_csv_numbers_to_int_array( $gmt_csv ); |
| 37 |
$local_arr = wpbc_csv_numbers_to_int_array( $local_csv ); |
| 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 |
|
| 45 |
$unavailable_time_from_today = get_bk_option( 'booking_unavailable_days_num_from_today' ); |
| 46 |
|
| 47 |
if ( ! empty( $unavailable_time_from_today ) ) { |
| 48 |
if ( 'm' === substr( $unavailable_time_from_today, - 1 ) ) { |
| 49 |
|
| 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 |
} |
| 54 |
|
| 55 |
// Local timezone unavailable time. // FixIn: 10.9.6.3. |
| 56 |
$local_unavailable_datetime_ymdhis = wpbc_datetime_localized__use_wp_timezone( $gmt_time, 'Y-m-d H:i:s' ); // Local unavailable. |
| 57 |
// Local timezone Now time. |
| 58 |
$local_now_datetime_ymdhis = wpbc_datetime_localized__use_wp_timezone( strtotime( $start_it ), 'Y-m-d H:i:s' ); // Local Now. |
| 59 |
// Local timezone Today midnight time. |
| 60 |
$local_now_datetime_ymd000 = wpbc_datetime_localized__use_wp_timezone( strtotime( $start_it ), 'Y-m-d 00:00:00' ); // Local Midnight. |
| 61 |
|
| 62 |
// Check time from local MIDNIGHT to Unavailable. |
| 63 |
$days_number_shift = intval( ( strtotime( $local_unavailable_datetime_ymdhis ) - strtotime( $local_now_datetime_ymd000 ) ) / 86400 ); |
| 64 |
$unavailable_time_from_today = $days_number_shift; |
| 65 |
// $unavailable_time_from_today = '0'; // FixIn: 10.9.2.6. |
| 66 |
} |
| 67 |
} else { |
| 68 |
$unavailable_time_from_today = '0'; |
| 69 |
} |
| 70 |
|
| 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 ); |
| 73 |
|
| 74 |
$script .= "_wpbc.set_other_param( 'today_arr', " . wp_json_encode( $today_arr ) . " ); "; |
| 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 |
|
| 97 |
$script .= "_wpbc.set_other_param( 'url_plugin', '" . esc_url( plugins_url( '', WPBC_FILE ) ) . "' ); "; |
| 98 |
|
| 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 */ |
| 100 |
|
| 101 |
$script .= "_wpbc.set_other_param( 'this_page_booking_hash', '" . esc_js( $get_booking_hash ) . "' ); "; |
| 102 |
|
| 103 |
|
| 104 |
$script .= "_wpbc.set_other_param( 'calendars__on_this_page', [] ); "; |
| 105 |
|
| 106 |
$script .= "_wpbc.set_other_param( 'calendars__first_day', '" . intval( get_bk_option( 'booking_start_day_weeek' ) ) . "' ); "; //."\n"; |
| 107 |
$script .= "_wpbc.set_other_param( 'calendars__max_monthes_in_calendar', '" . esc_js( get_bk_option( 'booking_max_monthes_in_calendar' ) ) . "' ); "; |
| 108 |
if ( class_exists( 'wpdev_bk_biz_m' ) ) { |
| 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' |
| 110 |
} |
| 111 |
$script .= "_wpbc.set_other_param( 'availability__week_days_unavailable', [" |
| 112 |
. ( ( get_bk_option( 'booking_unavailable_day0') == 'On' ) ? '0,' : '' ) |
| 113 |
. ( ( get_bk_option( 'booking_unavailable_day1') == 'On' ) ? '1,' : '' ) |
| 114 |
. ( ( get_bk_option( 'booking_unavailable_day2') == 'On' ) ? '2,' : '' ) |
| 115 |
. ( ( get_bk_option( 'booking_unavailable_day3') == 'On' ) ? '3,' : '' ) |
| 116 |
. ( ( get_bk_option( 'booking_unavailable_day4') == 'On' ) ? '4,' : '' ) |
| 117 |
. ( ( get_bk_option( 'booking_unavailable_day5') == 'On' ) ? '5,' : '' ) |
| 118 |
. ( ( get_bk_option( 'booking_unavailable_day6') == 'On' ) ? '6,' : '' ) |
| 119 |
. "999] ); "; // 999 - blank day, which will not impact to the checking of the week days. Required for correct creation of this array. |
| 120 |
// General days selection. |
| 121 |
$days_selection_arr = wpbc__calendar__js_params__get_days_selection_arr(); |
| 122 |
|
| 123 |
$script .= "_wpbc.set_other_param( 'calendars__days_select_mode', '" . $days_selection_arr['days_select_mode'] . "' ); "; |
| 124 |
$script .= "_wpbc.set_other_param( 'calendars__fixed__days_num', " . $days_selection_arr['fixed__days_num'] . " ); "; |
| 125 |
$script .= "_wpbc.set_other_param( 'calendars__fixed__week_days__start', [" . $days_selection_arr['fixed__week_days__start'] . "] ); "; |
| 126 |
$script .= "_wpbc.set_other_param( 'calendars__dynamic__days_min', " . $days_selection_arr['dynamic__days_min'] . " ); "; |
| 127 |
$script .= "_wpbc.set_other_param( 'calendars__dynamic__days_max', " . $days_selection_arr['dynamic__days_max'] . " ); "; |
| 128 |
$script .= "_wpbc.set_other_param( 'calendars__dynamic__days_specific', [" . $days_selection_arr['dynamic__days_specific'] . "] ); "; |
| 129 |
$script .= "_wpbc.set_other_param( 'calendars__dynamic__week_days__start', [" . $days_selection_arr['dynamic__week_days__start'] . "] ); "; |
| 130 |
|
| 131 |
// FixIn: 10.3.0.9. |
| 132 |
if ( false !== strpos( get_bk_option( 'booking_skin' ), 'light__24_8' ) ) { |
| 133 |
$script .= "_wpbc.set_other_param( 'calendars__days_selection__middle_days_opacity', '0.5' ); "; |
| 134 |
} else { |
| 135 |
$script .= "_wpbc.set_other_param( 'calendars__days_selection__middle_days_opacity', '0.75' ); "; |
| 136 |
} |
| 137 |
|
| 138 |
|
| 139 |
// Defined in BS. |
| 140 |
$script .= "_wpbc.set_other_param( 'is_enabled_booking_recurrent_time', " . ( ( get_bk_option( 'booking_recurrent_time' ) !== 'On' ) ? 'false' : 'true' ) . " ); "; |
| 141 |
$script .= "_wpbc.set_other_param( 'is_allow_several_months_on_mobile', " . ( ( get_bk_option( 'booking_calendar_allow_several_months_on_mobile' ) !== 'On' ) ? 'false' : 'true' ) . " ); "; |
| 142 |
$script .= "_wpbc.set_other_param( 'is_enabled_change_over', " . ( |
| 143 |
( |
| 144 |
( function_exists( 'wpbc_is_booking_used_check_in_out_time' ) ) |
| 145 |
&& ( wpbc_is_booking_used_check_in_out_time() ) |
| 146 |
) ? 'true' : 'false' |
| 147 |
) . " ); "; |
| 148 |
|
| 149 |
$script .= "_wpbc.set_other_param( 'is_enabled_booking_timeslot_picker', " . ( ( 'On' === get_bk_option( 'booking_timeslot_picker' ) ) ? 'true' : 'false' ) . " ); "; |
| 150 |
|
| 151 |
if ( class_exists( 'wpdev_bk_biz_l' ) ) { |
| 152 |
$script .= "_wpbc.set_other_param( 'is_enabled_booking_search_results_days_select', '" . esc_js( get_bk_option( 'booking_search_results_days_select' ) ) . "' ); "; |
| 153 |
} |
| 154 |
|
| 155 |
$script .= "_wpbc.set_other_param( 'update', '" . esc_attr( WP_BK_VERSION_NUM ) . "' ); "; |
| 156 |
$script .= "_wpbc.set_other_param( 'version', '" . wpbc_get_version_type__and_mu() . "' ); "; |
| 157 |
|
| 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' ) ) . " ); "; |
| 169 |
|
| 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 ==' );"; |
| 172 |
return $script; |
| 173 |
} |
| 174 |
|
| 175 |
|
| 176 |
// FixIn: 10.14.4.2. (loader made cache-proof) |
| 177 |
/** |
| 178 |
* Print inline JS for Booking Calendar that initializes safely even with cache plugins (delay/defer/on-interaction). |
| 179 |
* |
| 180 |
* @param string $where_to_load 'both' by default. |
| 181 |
* |
| 182 |
* @return void |
| 183 |
*/ |
| 184 |
function wpbc_localize_js_vars( $where_to_load = 'both' ) { |
| 185 |
|
| 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;'; |
| 193 |
wp_add_inline_script( 'wpbc_all', $script_before, 'before' ); |
| 194 |
|
| 195 |
// 2) Existing payload (calls to _wpbc.set_other_param, _wpbc.set_message, …). |
| 196 |
$payload_js = wpbc_get_localized_js_vars(); |
| 197 |
|
| 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' ) ); |
| 203 |
|
| 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 ); |
| 253 |
} |
| 254 |
add_action( 'wpbc_enqueue_js_files', 'wpbc_localize_js_vars', 51 ); |
| 255 |
|