PluginProbe
Booking Calendar / 11.3
Booking Calendar v11.3
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 10.11.3 10.11.4 10.12.0 10.12.1 All 199 releases
booking / includes / _functions / calendar_scripts.php

calendar_scripts.php in Booking Calendar 11.3, at includes/_functions/calendar_scripts.php

305 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @version 1.0
4 * @package Booking Calendar
5 * @subpackage Calendar Scripts
6 * @category Functions
7 *
8 * @author wpdevelop
9 * @link https://wpbookingcalendar.com/
10 * @email info@wpbookingcalendar.com
11 *
12 * @modified 2025-07-19
13 * @file: ../includes/_functions/calendar_scripts.php
14 */
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit; // Exit if accessed directly.
18 }
19
20 // =====================================================================================================================
21 // == Calendar functions ==
22 // =====================================================================================================================
23 /**
24 * Print the critical inline CSS exactly once per page.
25 * - In Elementor-safe mode, collect CSS into WPBC_FE_Assets (head if possible, else footer).
26 * - Legacy fallback: echo <style> in place.
27 */
28 function wpbc_print_loader_inline_css_once() {
29
30 static $printed = false;
31 if ( $printed ) {
32 return;
33 }
34 $printed = true;
35
36 $css = "
37 /* Critical loader styles (scoped by class names) */
38 .calendar_loader_frame {
39 width: calc(341px * var(--wpbc-loader-cols, 1));
40 max-width: 100%;
41 height: 307px;
42 display: flex;
43 flex-flow: column nowrap;
44 align-items: center;
45 justify-content: center;
46 border-radius: 5px;
47 box-shadow: 0 0 2px #ccc;
48 gap: 15px;
49 /* Calendar variables (safe fallbacks) */
50 color: var(--wpbc_cal-available-text-color, #2c3e50);
51 background: rgb(from var(--wpbc_cal-available-day-color, #e6f2ff) r g b / var(--wpbc_cal-day-bg-color-opacity, 1));
52 border: var(--wpbc_cal-day-cell-border-width, 1px) solid var(--wpbc_cal-available-day-color, #aacbeb);
53 }
54 .calendar_loader_text {
55 font-size: 18px;
56 text-align: center;
57 }
58 .calendar_loader_frame__progress_line_container {
59 width: 50%;
60 height: 3px;
61 margin-top: 7px;
62 overflow: hidden;
63 background: #202020;
64 border-radius: 30px;
65 }
66 .calendar_loader_frame__progress_line {
67 width: 0%;
68 height: 3px;
69 background: #8ECE01;
70 border-radius: 30px;
71 animation: calendar_loader_bar_progress 3s infinite linear;
72 }
73 @keyframes calendar_loader_bar_progress { to { width: 100%; } }
74 @media (prefers-reduced-motion: reduce) {
75 .calendar_loader_frame__progress_line { animation: none; width: 50%; }
76 }
77 ";
78
79 // Elementor-safe path: attach CSS to an enqueued WPBC stylesheet.
80 if ( class_exists( 'WPBC_FE_Assets' ) ) {
81
82 // Ensure the target style is enqueued (safe-check anyway).
83 if ( function_exists( 'wp_enqueue_style' ) ) {
84 wp_enqueue_style( 'wpbc-ui-both', wpbc_plugin_url( '/css/wpbc_ui_both.css' ), array(), WP_BK_VERSION_NUM ); // FixIn: 10.0.0.25.
85 }
86 // FixIn: 10.14.14.1.
87 $added = WPBC_FE_Assets::add_inline_css_to_wp_style( 'wpbc-ui-both', $css, 'wpbc:calendar-loader-css' );
88
89 if ( $added ) {
90 return; // Do NOT print <style> inside content.
91 }
92 }
93
94 // Legacy fallback (only when WP inline style cannot be attached).
95 echo "\n" . '<style id="wpbc_calendar_loader_inline_css">' . "\n" . $css . "\n" . '</style>' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
96 }
97
98
99
100 /**
101 * Output a single calendar loader block (no inline <script>, includes inline CSS once).
102 *
103 * How it works:
104 * - The external JS (enqueued here) auto-detects this block and manages the loader lifecycle.
105 * - Multiple instances on the same page are supported, even with duplicate RIDs.
106 * - Critical CSS is printed inline once, so loaders render correctly immediately.
107 *
108 * @param int $resource_id Booking resource ID for this calendar.
109 * @param int $months_number Number of months in calendar view (affects width).
110 * @param int $grace_ms Grace time in ms before showing helpful messages (default 8000).
111 *
112 * @return string HTML markup for the loader.
113 */
114 function wpbc_get_calendar_loader_animation( $resource_id = 1, $months_number = 1, $grace_ms = 8000 ) {
115
116 ob_start();
117
118 $rid = (int) $resource_id;
119 $cols = max( 1, (int) $months_number );
120 $grace = max( 1, (int) $grace_ms );
121
122 // Print the inline CSS once.
123 wpbc_print_loader_inline_css_once();
124 ?>
125 <div class="calendar_loader_frame calendar_loader_frame<?php echo esc_attr( $rid ); ?>"
126 data-wpbc-rid="<?php echo esc_attr( $rid ); ?>"
127 data-wpbc-grace="<?php echo esc_attr( $grace ); ?>"
128 style="--wpbc-loader-cols: <?php echo esc_attr( $cols ); ?>;"
129 >
130 <div class="calendar_loader_text"><?php esc_html_e( 'Loading', 'booking' ); ?>...</div>
131 <div class="calendar_loader_frame__progress_line_container">
132 <div class="calendar_loader_frame__progress_line"></div>
133 </div>
134 </div>
135 <?php
136
137 return ob_get_clean();
138 }
139
140 // FixIn: 10.14.6.1.
141 /**
142 * Keep Cloudflare Rocket Loader ON, but exclude key scripts it must not defer.
143 * Prevents "jQuery is not defined" / "_wpbc is undefined" races.
144 */
145 function wpbc_disable_cloudflare_on_calendar_script( $tag, $handle, $src = '' ) {
146
147 // 1) Handles to exclude (extendable via filter)
148 $exclude_handles = [
149 // WordPress core libs:
150 'jquery', 'jquery-core', 'jquery-migrate',
151 'jquery-ui-core', 'jquery-ui-datepicker',
152
153 // Booking Calendar (common handles; may vary by site):
154 'wpbc_all',
155 'wpbc-main-client',
156 'wpbc-datepick',
157 'wpbc-datepick-localize',
158 'wpbc-times',
159 'wpbc-time-selector',
160 'wpbc-timeline-flex',
161 'wpbc_capacity',
162 'wpbc-popper',
163 'wpbc-tipcy',
164 'wpbc-imask',
165 ];
166
167 $exclude_handles = apply_filters( 'wpbc_cloudflare_exclude_handles', $exclude_handles, $tag, $handle, $src );
168
169 // 2) Decide whether to exclude this script
170 $should_exclude = in_array( $handle, $exclude_handles, true );
171
172 // 3) Fallbacks by src path (covers all Booking Calendar assets)
173 if ( ! $should_exclude && is_string( $src ) ) {
174 if ( strpos( $src, '/wp-content/plugins/booking/' ) !== false ) {
175 $should_exclude = true;
176 }
177 if ( strpos( $src, '/wp-content/plugins/booking-calendar-com/' ) !== false ) {
178 $should_exclude = true;
179 }
180 }
181
182 if ( $should_exclude ) {
183 // Add data-cfasync="false" once (prevents Rocket Loader rewrite)
184 if ( strpos( $tag, 'data-cfasync=' ) === false ) {
185 $tag = preg_replace( '/^<script\b/i', '<script data-cfasync="false"', $tag, 1 );
186 }
187 // Remove async (keep defer)
188 $tag = preg_replace( '/\sasync(\s*=\s*([\'"][^\'"]*[\'"]|[^\s>]+))?/i', '', $tag );
189 }
190
191 return $tag;
192 }
193 // Use a later priority so we run after most tag modifiers.
194 add_filter( 'script_loader_tag', 'wpbc_disable_cloudflare_on_calendar_script', 100, 3 );
195
196
197
198 /**
199 * Get HTML for the initilizing inline calendars
200 *
201 * @param integer $resource_id - ID of booking resource.
202 * @param integer $cal_count - Number of months.
203 * @param array $shortcode_param__options - Options.
204 *
205 * @return string
206 */
207 function wpbc_pre_get_calendar_html( $resource_id = 1, $cal_count = 1, $shortcode_param__options = array() ) {
208
209 /**
210 * SHORTCODE: [booking type=56 form_type='standard' nummonths=4 options='{calendar months_num_in_row=2 width=682px cell_height=48px}'] .
211 * OPTIONS:
212 * [months_num_in_row] => 2
213 * [width] => 341px define: width: 100%; max-width:341px;
214 * [strong_width] => 341px define: width:341px;
215 * [cell_height] => 48px
216 */
217 $shortcode_param__options = wpbc_parse_calendar_options( $shortcode_param__options );
218
219 $width = '';
220 $months_num_in_row = '';
221 $cell_height = '';
222
223 if ( ! empty( $shortcode_param__options ) ) {
224
225 if ( isset( $shortcode_param__options['months_num_in_row'] ) ) {
226 $months_num_in_row = $shortcode_param__options['months_num_in_row'];
227 }
228
229 if ( isset( $shortcode_param__options['width'] ) ) {
230 $width = 'width:100%;max-width:' . $shortcode_param__options['width'] . ';'; // FixIn: 9.3.1.5.
231 }
232 if ( isset( $shortcode_param__options['strong_width'] ) ) {
233 $width .= 'width:' . $shortcode_param__options['strong_width'] . ';'; // FixIn: 9.3.1.6.
234 }
235
236 if ( isset( $shortcode_param__options['cell_height'] ) ) {
237 $cell_height = $shortcode_param__options['cell_height'];
238 }
239 if ( isset( $shortcode_param__options['strong_cell_height'] ) ) { // FixIn: 9.7.3.3.
240 $cell_height = $shortcode_param__options['strong_cell_height'] . '!important;';
241 }
242 }
243 /* FixIn: 9.7.3.4 */
244
245 if ( ! empty( $cell_height ) ) {
246 // FixIn: 10.13.1.3.
247 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
248 $style = '<style type="text/css" rel="stylesheet" >.hasDatepick .datepick-inline .datepick-title-row th,.hasDatepick .datepick-inline .datepick-days-cell,.hasDatepick .datepick-inline .wpbc-cell-box{ max-height: ' . $cell_height . '; }</style>'; // FixIn: 10.12.4.2.
249 } else {
250 $style = '';
251 }
252
253 $is_custom_width_css = ( empty( $width ) ) ? ' wpbc_no_custom_width ' : '';
254
255 $calendar = $style .
256 '<div class="wpbc_cal_container bk_calendar_frame' . $is_custom_width_css . ' months_num_in_row_' . $months_num_in_row . ' cal_month_num_' . $cal_count . '" style="' . $width . '">' .
257 '<div id="calendar_booking' . $resource_id . '" class="wpbc_calendar_id_' . $resource_id . '" >' .
258 wpbc_get_calendar_loader_animation( $resource_id, $cal_count ) .
259 '</div>' .
260 '</div>';
261
262 $booking_is_show_powered_by_notice = get_bk_option( 'booking_is_show_powered_by_notice' );
263 if ( ( ! class_exists( 'wpdev_bk_personal' ) ) && ( 'On' === $booking_is_show_powered_by_notice ) ) {
264 $calendar .= '<div style="font-size:7px;text-align:left;margin:0 0 10px;text-shadow: none;">Powered by <a href="https://wpbookingcalendar.com" style="font-size:7px;" target="_blank" title="Booking Calendar plugin for WordPress">Booking Calendar</a></div>';
265 }
266
267 $calendar .= '<textarea id="date_booking' . $resource_id . '" name="date_booking' . $resource_id . '" autocomplete="off" style="display:none;"></textarea>'; // Calendar code.
268
269 $calendar .= wpbc_get_calendar_legend( $resource_id ); // FixIn: 9.4.3.6.
270
271 $calendar_css_class_outer = 'wpbc_calendar_wraper';
272
273 // FixIn: 7.0.1.24.
274 $is_booking_change_over_days_triangles = get_bk_option( 'booking_change_over_days_triangles' );
275 $is_booking_used_check_in_out_time = null;
276 if ( function_exists( 'wpbc_settings_calendar__preview_is_changeover_enabled' ) ) {
277 $is_booking_used_check_in_out_time = wpbc_settings_calendar__preview_is_changeover_enabled( $resource_id, false );
278 }
279 if ( null === $is_booking_used_check_in_out_time ) {
280 $is_booking_used_check_in_out_time = (
281 ( ! function_exists( 'wpbc_is_booking_used_check_in_out_time' ) )
282 || ( wpbc_is_booking_used_check_in_out_time( false, $resource_id ) )
283 );
284 }
285 if (
286 ( 'Off' !== $is_booking_change_over_days_triangles )
287 && $is_booking_used_check_in_out_time
288 ) {
289 $calendar_css_class_outer .= ' wpbc_change_over_triangle';
290 }
291
292 // filenames, such as 'multidays.css'.
293 $calendar_skin_name = basename( get_bk_option( 'booking_skin' ) );
294 if ( wpbc_is_calendar_skin_legacy( $calendar_skin_name ) ) {
295 $calendar_css_class_outer .= ' wpbc_calendar_skin_legacy';
296 }
297
298 $calendar = '<div class="' . esc_attr( $calendar_css_class_outer ) . '">' . $calendar . '</div>';
299
300 return $calendar;
301 }
302
303 // >=BM - Get script for calendar activation required only in the BM version for extra calendars.!
304 add_bk_filter( 'pre_get_calendar_html', 'wpbc_pre_get_calendar_html' );
305