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
booking / includes / page-settings-calendar / settings_calendar__page.php

settings_calendar__page.php in Booking Calendar 11.8.4, at includes/page-settings-calendar/settings_calendar__page.php

2,256 lines 103.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Calendar settings page.
4 *
5 * @package Booking Calendar
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * Check whether the Calendar settings page is active.
14 *
15 * @return bool
16 */
17 function wpbc_settings_calendar__is_page() {
18
19 if ( ! is_admin() ) {
20 return false;
21 }
22
23 if ( function_exists( 'wpbc_is_settings_calendar_page' ) ) {
24 return wpbc_is_settings_calendar_page();
25 }
26
27 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
28 $page = isset( $_REQUEST['page'] ) ? sanitize_key( wp_unslash( $_REQUEST['page'] ) ) : '';
29 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
30 $tab = isset( $_REQUEST['tab'] ) ? sanitize_key( wp_unslash( $_REQUEST['tab'] ) ) : '';
31
32 return ( 'wpbc-settings' === $page && 'calendar_settings' === $tab );
33 }
34
35 /**
36 * Enqueue CSS for Calendar settings.
37 *
38 * @param string $where_to_load Where assets are loaded.
39 *
40 * @return void
41 */
42 function wpbc_settings_calendar_enqueue_css_files( $where_to_load ) {
43
44 if ( ( ! is_admin() ) || ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) ) ) {
45 return;
46 }
47
48 if ( ! wpbc_settings_calendar__is_page() ) {
49 return;
50 }
51
52 wp_enqueue_style(
53 'wpbc-settings-calendar-page',
54 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/settings_calendar_page.css',
55 array( 'wpbc-calendar', 'wpbc-all-admin' ),
56 WP_BK_VERSION_NUM
57 );
58 }
59 add_action( 'wpbc_enqueue_css_files', 'wpbc_settings_calendar_enqueue_css_files', 66 );
60
61 /**
62 * Enqueue JS for Calendar settings.
63 *
64 * @param string $where_to_load Where assets are loaded.
65 *
66 * @return void
67 */
68 function wpbc_settings_calendar_enqueue_js_files( $where_to_load ) {
69
70 if ( ( ! is_admin() ) || ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) ) ) {
71 return;
72 }
73
74 if ( ! wpbc_settings_calendar__is_page() ) {
75 return;
76 }
77
78 wp_enqueue_script(
79 'wpbc-settings-calendar-page',
80 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/settings_calendar_page.js',
81 array( 'jquery', 'wpbc_all' ),
82 WP_BK_VERSION_NUM,
83 array( 'in_footer' => WPBC_JS_IN_FOOTER )
84 );
85
86 wp_localize_script(
87 'wpbc-settings-calendar-page',
88 'wpbc_settings_calendar_page',
89 array(
90 'ajax_url' => admin_url( 'admin-ajax.php' ),
91 'nonce' => wp_create_nonce( 'wpbc_settings_calendar_ajax_nonce' ),
92 'action' => 'WPBC_AJX_SETTINGS_CALENDAR_SAVE',
93 'preview_action' => 'WPBC_AJX_SETTINGS_CALENDAR_PREVIEW',
94 'settings' => wpbc_settings_calendar__get_settings_response(),
95 'days_selection' => wpbc_settings_calendar__get_days_selection_response(),
96 'open_section' => wpbc_settings_calendar__get_open_section(),
97 'section_groups' => wpbc_settings_calendar__get_section_group_map(),
98 'section_menus' => wpbc_settings_calendar__get_section_menu_slug_map(),
99 'i18n' => array(
100 'saving' => __( 'Saving', 'booking' ),
101 'saved' => __( 'Calendar settings updated.', 'booking' ),
102 'save_failed' => __( 'Unable to save calendar settings.', 'booking' ),
103 'preview_failed' => __( 'Unable to refresh calendar preview.', 'booking' ),
104 'loading' => __( 'Loading', 'booking' ),
105 'premium_notice' => __( 'Advanced range rules are available in Booking Calendar Business Small or higher. Open the live demo to test the real behavior.', 'booking' ),
106 'premium_changeover_notice' => __( 'Changeover days are available in Booking Calendar Business Small or higher. Open the live demo to test the real behavior.', 'booking' ),
107 'premium_option_notice' => __( 'This option is available in Booking Calendar Business Small or higher.', 'booking' ),
108 ),
109 'is_range_supported' => wpbc_settings_calendar__is_range_supported() ? 1 : 0,
110 )
111 );
112 }
113 add_action( 'wpbc_enqueue_js_files', 'wpbc_settings_calendar_enqueue_js_files', 66 );
114
115 /**
116 * Print tooltip initializer for Calendar settings.
117 *
118 * @return void
119 */
120 function wpbc_settings_calendar_print_tooltip_js() {
121
122 if ( ! wpbc_settings_calendar__is_page() ) {
123 return;
124 }
125
126 if ( function_exists( 'wpbc_bs_javascript_tooltips' ) ) {
127 wpbc_bs_javascript_tooltips();
128 }
129 }
130 add_action( 'admin_footer', 'wpbc_settings_calendar_print_tooltip_js', 67 );
131
132 /**
133 * Check whether current edition supports advanced range rules and change-over settings.
134 *
135 * @return bool
136 */
137 function wpbc_settings_calendar__is_range_supported() {
138
139 return class_exists( 'wpdev_bk_biz_s' );
140 }
141
142 /**
143 * Get the main Range days option title for the current edition.
144 *
145 * Free and Personal expose only the unrestricted two-click range. Business
146 * Small and higher select one-click or two-click behavior in the subtype
147 * controls shown below the main option.
148 *
149 * @return string
150 */
151 function wpbc_settings_calendar__get_range_days_title() {
152
153 return wpbc_settings_calendar__is_range_supported()
154 ? __( 'Range days', 'booking' )
155 : __( 'Range days - 2 mouse clicks', 'booking' );
156 }
157
158 /**
159 * Calendar settings right-sidebar section navigation.
160 *
161 * @return array
162 */
163 function wpbc_settings_calendar__get_section_navigation_items() {
164
165 return array(
166 'days_selection' => array(
167 'menu_slug' => 'calendar_days_selection',
168 'group' => 'settings-calendar-days-selection',
169 'title' => __( 'Days Selection', 'booking' ),
170 'hint' => __( 'Choose how users can select days: single day, multiple days, or date range.', 'booking' ),
171 'font_icon' => 'wpbc-bi-calendar3-week',
172 ),
173 'changeover_times' => array(
174 'menu_slug' => 'calendar_changeover_times',
175 'group' => 'settings-calendar-time',
176 'title' => __( 'Changeover and Times', 'booking' ),
177 'hint' => __( 'Configure changeover days, recurrent time, and changeover exceptions.', 'booking' ),
178 'font_icon' => 'wpbc_icn_flip',
179 ),
180 'legend' => array(
181 'menu_slug' => 'calendar_legend',
182 'group' => 'settings-calendar-legend',
183 'title' => __( 'Calendar Legend', 'booking' ),
184 'hint' => __( 'Show or hide the calendar legend and configure each legend item.', 'booking' ),
185 'font_icon' => 'wpbc-bi-list-check',
186 ),
187 'tooltips' => array(
188 'menu_slug' => 'calendar_tooltips',
189 'group' => 'settings-calendar-tooltips',
190 'title' => __( 'Calendar Dates Tooltips', 'booking' ),
191 'hint' => __( 'Configure mouse-over tooltips for booked times, availability, cost, and booking details.', 'booking' ),
192 'font_icon' => 'wpbc-bi-chat-square-dots',
193 ),
194 'general' => array(
195 'menu_slug' => 'calendar_general',
196 'group' => 'settings-calendar-general',
197 'title' => __( 'Calendar General', 'booking' ),
198 'hint' => __( 'Configure month scrolling, week start day, and mobile month display.', 'booking' ),
199 'font_icon' => 'wpbc-bi-calendar2-range',
200 ),
201 );
202 }
203
204 /**
205 * Get section key to left-menu slug map for scripts.
206 *
207 * @return array
208 */
209 function wpbc_settings_calendar__get_section_menu_slug_map() {
210
211 $section_menus = array();
212
213 foreach ( wpbc_settings_calendar__get_section_navigation_items() as $section_key => $section ) {
214 $section_menus[ $section_key ] = $section['menu_slug'];
215 }
216
217 return $section_menus;
218 }
219
220 /**
221 * Get section key to collapsible group map for scripts.
222 *
223 * @return array
224 */
225 function wpbc_settings_calendar__get_section_group_map() {
226
227 $section_groups = array();
228
229 foreach ( wpbc_settings_calendar__get_section_navigation_items() as $section_key => $section ) {
230 $section_groups[ $section_key ] = $section['group'];
231 }
232
233 return $section_groups;
234 }
235
236 /**
237 * Get URL to the Calendar settings page with a right-sidebar section selected.
238 *
239 * @param string $section Section key.
240 * @return string
241 */
242 function wpbc_settings_calendar__get_section_url( $section ) {
243
244 $sections = wpbc_settings_calendar__get_section_navigation_items();
245 $base_url = function_exists( 'wpbc_get_settings_calendar_url' )
246 ? wpbc_get_settings_calendar_url()
247 : admin_url( 'admin.php?page=wpbc-settings&tab=calendar_settings' );
248
249 if ( empty( $sections[ $section ] ) ) {
250 return $base_url;
251 }
252
253 return add_query_arg(
254 array(
255 'wpbc_calendar_section' => $section,
256 ),
257 $base_url
258 );
259 }
260
261 /**
262 * Get the Calendar settings section that should be opened on page load.
263 *
264 * @return string
265 */
266 function wpbc_settings_calendar__get_open_section() {
267
268 $sections = wpbc_settings_calendar__get_section_navigation_items();
269
270 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
271 $open_section = isset( $_REQUEST['wpbc_calendar_section'] ) ? sanitize_key( wp_unslash( $_REQUEST['wpbc_calendar_section'] ) ) : '';
272
273 if ( isset( $sections[ $open_section ] ) ) {
274 return $open_section;
275 }
276
277 return '';
278 }
279
280 /**
281 * Adjust the universal top path for Calendar section URLs.
282 *
283 * Calendar sections use wpbc_calendar_section instead of the reserved subtab
284 * parameter, so we map the active section into the shared top path here.
285 *
286 * @param array $items Top path items.
287 * @param WPBC_Page_Structure $page_structure_obj Page structure object.
288 * @param array $top_path_config Top path config.
289 *
290 * @return array
291 */
292 function wpbc_settings_calendar__top_path_items( $items, $page_structure_obj, $top_path_config ) {
293
294 if ( ! is_object( $page_structure_obj ) || ! method_exists( $page_structure_obj, 'get_current_page_params' ) ) {
295 return $items;
296 }
297
298 $current_page_params = $page_structure_obj->get_current_page_params();
299 if ( empty( $current_page_params['tab']['tag'] ) || 'calendar_settings' !== $current_page_params['tab']['tag'] ) {
300 return $items;
301 }
302
303 $sections = wpbc_settings_calendar__get_section_navigation_items();
304 $section_key = wpbc_settings_calendar__get_open_section();
305 if ( empty( $section_key ) ) {
306 $section_key = 'days_selection';
307 }
308
309 if ( empty( $sections[ $section_key ]['title'] ) ) {
310 return $items;
311 }
312
313 foreach ( $items as $item_index => $item ) {
314 $items[ $item_index ]['active'] = false;
315 }
316
317 if ( ! empty( $items ) ) {
318 $last_item_index = count( $items ) - 1;
319 $section_titles = array_map( 'wp_strip_all_tags', wp_list_pluck( $sections, 'title' ) );
320 $last_title = isset( $items[ $last_item_index ]['title'] ) ? wp_strip_all_tags( $items[ $last_item_index ]['title'] ) : '';
321
322 if ( in_array( $last_title, $section_titles, true ) ) {
323 array_pop( $items );
324 }
325 }
326
327 $items[] = array(
328 'title' => $sections[ $section_key ]['title'],
329 'url' => wpbc_settings_calendar__get_section_url( $section_key ),
330 'onclick' => '',
331 'active' => true,
332 );
333
334 return $items;
335 }
336 add_filter( 'wpbc_ui_settings_top_path_items', 'wpbc_settings_calendar__top_path_items', 10, 3 );
337
338 /**
339 * Manage capability.
340 *
341 * @return string
342 */
343 function wpbc_settings_calendar__get_manage_cap() {
344
345 $min_user_role = get_bk_option( 'booking_user_role_settings' );
346 $capability = array(
347 'administrator' => 'activate_plugins',
348 'editor' => 'publish_pages',
349 'author' => 'publish_posts',
350 'contributor' => 'edit_posts',
351 'subscriber' => 'read',
352 );
353
354 return isset( $capability[ $min_user_role ] ) ? $capability[ $min_user_role ] : 'manage_options';
355 }
356
357 /**
358 * Get booking resources for preview toolbar.
359 *
360 * @return array
361 */
362 function wpbc_settings_calendar__get_resources() {
363
364 if ( function_exists( 'wpbc_settings_themes__get_resources' ) ) {
365 return wpbc_settings_themes__get_resources();
366 }
367
368 return array(
369 array(
370 'id' => 1,
371 'title' => __( 'Default booking resource', 'booking' ),
372 ),
373 );
374 }
375
376 /**
377 * Sanitize preview resource ID.
378 *
379 * @param int|string $resource_id Resource ID.
380 *
381 * @return int
382 */
383 function wpbc_settings_calendar__sanitize_preview_resource_id( $resource_id ) {
384
385 if ( function_exists( 'wpbc_settings_themes__sanitize_preview_resource_id' ) ) {
386 return wpbc_settings_themes__sanitize_preview_resource_id( $resource_id );
387 }
388
389 return max( 1, absint( $resource_id ) );
390 }
391
392 /**
393 * Sanitize preview months count.
394 *
395 * @param int|string $months_count Months count.
396 *
397 * @return int
398 */
399 function wpbc_settings_calendar__sanitize_preview_months_count( $months_count ) {
400
401 $months_count = absint( $months_count );
402 $allowed = array( 1, 2, 3, 4, 6, 12 );
403
404 return in_array( $months_count, $allowed, true ) ? $months_count : 3;
405 }
406
407 /**
408 * Get preview resource ID.
409 *
410 * @return int
411 */
412 function wpbc_settings_calendar__get_preview_resource_id() {
413
414 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
415 $resource_id = isset( $_GET['resource_id'] ) ? absint( wp_unslash( $_GET['resource_id'] ) ) : 1;
416
417 return wpbc_settings_calendar__sanitize_preview_resource_id( $resource_id );
418 }
419
420 /**
421 * Get preview months count.
422 *
423 * @return int
424 */
425 function wpbc_settings_calendar__get_preview_months_count() {
426
427 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
428 $months_count = isset( $_GET['months_count'] ) ? absint( wp_unslash( $_GET['months_count'] ) ) : 2;
429
430 return wpbc_settings_calendar__sanitize_preview_months_count( $months_count );
431 }
432
433 /**
434 * Get week day labels.
435 *
436 * @return array
437 */
438 function wpbc_settings_calendar__get_weekday_options() {
439
440 return array(
441 '0' => __( 'Sunday', 'booking' ),
442 '1' => __( 'Monday', 'booking' ),
443 '2' => __( 'Tuesday', 'booking' ),
444 '3' => __( 'Wednesday', 'booking' ),
445 '4' => __( 'Thursday', 'booking' ),
446 '5' => __( 'Friday', 'booking' ),
447 '6' => __( 'Saturday', 'booking' ),
448 );
449 }
450
451 /**
452 * Get maximum scroll options.
453 *
454 * @return array
455 */
456 function wpbc_settings_calendar__get_max_month_options() {
457
458 $options = array();
459
460 for ( $mm = 1; $mm < 12; $mm++ ) {
461 $options[ $mm . 'm' ] = $mm . ' ' . __( 'month(s)', 'booking' );
462 }
463 $options['18m'] = '18 ' . __( 'month(s)', 'booking' );
464 for ( $yy = 1; $yy < 11; $yy++ ) {
465 $options[ $yy . 'y' ] = $yy . ' ' . __( 'year(s)', 'booking' );
466 }
467
468 return $options;
469 }
470
471 /**
472 * Get time options in 15 minute steps while preserving saved values.
473 *
474 * @param string $current Current time.
475 *
476 * @return array
477 */
478 function wpbc_settings_calendar__get_time_options( $current = '' ) {
479
480 $options = array();
481
482 for ( $hh = 0; $hh < 24; $hh++ ) {
483 foreach ( array( 0, 15, 30, 45 ) as $mm ) {
484 $time = sprintf( '%02d:%02d', $hh, $mm );
485 $options[ $time ] = function_exists( 'wpbc_time_localized' ) ? wpbc_time_localized( $time ) : $time;
486 }
487 }
488
489 if ( '' !== $current && ! isset( $options[ $current ] ) && preg_match( '/^\d{2}:\d{2}$/', $current ) ) {
490 $options[ $current ] = function_exists( 'wpbc_time_localized' ) ? wpbc_time_localized( $current ) : $current;
491 ksort( $options );
492 }
493
494 return $options;
495 }
496
497 /**
498 * Get configurable legend item options.
499 *
500 * @return array
501 */
502 function wpbc_settings_calendar__get_legend_items_config() {
503
504 return array(
505 'available' => array(
506 'label' => __( 'Available item', 'booking' ),
507 'description' => sprintf( __( 'Activate and type your %1$stitle of available%2$s item in legend', 'booking' ), '<b>', '</b>' ),
508 'placeholder' => __( 'Available', 'booking' ),
509 ),
510 'pending' => array(
511 'label' => __( 'Pending item', 'booking' ),
512 'description' => sprintf( __( 'Activate and type your %1$stitle of pending%2$s item in legend', 'booking' ), '<b>', '</b>' ),
513 'placeholder' => __( 'Pending', 'booking' ),
514 ),
515 'approved' => array(
516 'label' => __( 'Approved item', 'booking' ),
517 'description' => sprintf( __( 'Activate and type your %1$stitle of approved%2$s item in legend', 'booking' ), '<b>', '</b>' ),
518 'placeholder' => __( 'Booked', 'booking' ),
519 ),
520 'partially' => array(
521 'label' => __( 'Partially booked item', 'booking' ),
522 'description' => sprintf( __( 'Activate and type your %1$stitle of partially booked%2$s item in legend', 'booking' ), '<b>', '</b>' ),
523 'placeholder' => __( 'Partially booked', 'booking' ),
524 'note' => __( 'Partially booked item - day, which is booked for the specific time-slot(s).', 'booking' ),
525 ),
526 'unavailable' => array(
527 'label' => __( 'Unavailable item', 'booking' ),
528 'description' => sprintf( __( 'Activate and type your %1$stitle of unavailable%2$s item in legend', 'booking' ), '<b>', '</b>' ),
529 'placeholder' => __( 'Unavailable', 'booking' ),
530 ),
531 );
532 }
533
534 /**
535 * Normalize week-day CSV.
536 *
537 * @param string|array $value Week days.
538 *
539 * @return string
540 */
541 function wpbc_settings_calendar__normalize_week_days( $value ) {
542
543 if ( is_array( $value ) ) {
544 $items = $value;
545 } else {
546 $value = (string) $value;
547 if ( '-1' === $value || '' === $value ) {
548 return '-1';
549 }
550 $items = explode( ',', $value );
551 }
552
553 $cleaned = array();
554 foreach ( $items as $item ) {
555 $day = (string) absint( $item );
556 if ( in_array( $day, array( '0', '1', '2', '3', '4', '5', '6' ), true ) ) {
557 $cleaned[] = $day;
558 }
559 }
560
561 $cleaned = array_values( array_unique( $cleaned ) );
562
563 return empty( $cleaned ) ? '-1' : implode( ',', $cleaned );
564 }
565
566 /**
567 * Normalize the fixed one-click range length.
568 *
569 * Existing installations may not have this option yet. Keep explicitly
570 * configured values, including one day, but use three days when it is empty
571 * or invalid.
572 *
573 * @param mixed $value Fixed range day count.
574 *
575 * @return int
576 */
577 function wpbc_settings_calendar__normalize_fixed_range_days_count( $value ) {
578
579 $days_count = absint( $value );
580
581 return ( 0 < $days_count ) ? min( 180, $days_count ) : 3;
582 }
583
584 /**
585 * Get settings response.
586 *
587 * @return array
588 */
589 function wpbc_settings_calendar__get_settings_response() {
590
591 $settings = array(
592 'booking_max_monthes_in_calendar' => (string) get_bk_option( 'booking_max_monthes_in_calendar' ),
593 'booking_start_day_weeek' => (string) get_bk_option( 'booking_start_day_weeek' ),
594 'booking_calendar_allow_several_months_on_mobile' => (string) get_bk_option( 'booking_calendar_allow_several_months_on_mobile' ),
595 'booking_type_of_day_selections' => (string) get_bk_option( 'booking_type_of_day_selections' ),
596 'booking_range_selection_type' => (string) get_bk_option( 'booking_range_selection_type' ),
597 'booking_range_selection_days_count' => (string) wpbc_settings_calendar__normalize_fixed_range_days_count( get_bk_option( 'booking_range_selection_days_count' ) ),
598 'booking_range_start_day' => wpbc_settings_calendar__normalize_week_days( get_bk_option( 'booking_range_start_day' ) ),
599 'booking_range_selection_days_count_dynamic' => (string) get_bk_option( 'booking_range_selection_days_count_dynamic' ),
600 'booking_range_selection_days_max_count_dynamic' => (string) get_bk_option( 'booking_range_selection_days_max_count_dynamic' ),
601 'booking_range_selection_days_specific_num_dynamic' => (string) get_bk_option( 'booking_range_selection_days_specific_num_dynamic' ),
602 'booking_range_start_day_dynamic' => wpbc_settings_calendar__normalize_week_days( get_bk_option( 'booking_range_start_day_dynamic' ) ),
603 'booking_recurrent_time' => (string) get_bk_option( 'booking_recurrent_time' ),
604 'booking_last_checkout_day_available' => (string) get_bk_option( 'booking_last_checkout_day_available' ),
605 'booking_range_selection_time_is_active' => (string) get_bk_option( 'booking_range_selection_time_is_active' ),
606 'booking_range_selection_start_time' => (string) get_bk_option( 'booking_range_selection_start_time' ),
607 'booking_range_selection_end_time' => (string) get_bk_option( 'booking_range_selection_end_time' ),
608 'booking_change_over_days_triangles' => (string) get_bk_option( 'booking_change_over_days_triangles' ),
609 'booking_change_over__is_excerpt_on_pages' => (string) get_bk_option( 'booking_change_over__is_excerpt_on_pages' ),
610 'booking_change_over__excerpt_on_pages' => (string) get_bk_option( 'booking_change_over__excerpt_on_pages' ),
611 'booking_change_over__excerpt_bk_resources' => (string) get_bk_option( 'booking_change_over__excerpt_bk_resources' ),
612 'booking_is_show_legend' => (string) get_bk_option( 'booking_is_show_legend' ),
613 'booking_legend_is_show_numbers' => (string) get_bk_option( 'booking_legend_is_show_numbers' ),
614 'booking_legend_is_vertical' => (string) get_bk_option( 'booking_legend_is_vertical' ),
615 'booking_disable_timeslots_in_tooltip' => (string) get_bk_option( 'booking_disable_timeslots_in_tooltip' ),
616 'booking_highlight_timeslot_word' => (string) get_bk_option( 'booking_highlight_timeslot_word' ),
617 );
618
619 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
620 $settings[ 'booking_legend_is_show_item_' . $legend_item ] = (string) get_bk_option( 'booking_legend_is_show_item_' . $legend_item );
621 $settings[ 'booking_legend_text_for_item_' . $legend_item ] = (string) get_bk_option( 'booking_legend_text_for_item_' . $legend_item );
622 }
623
624 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
625 $settings['booking_is_show_availability_in_tooltips'] = (string) get_bk_option( 'booking_is_show_availability_in_tooltips' );
626 $settings['booking_highlight_availability_word'] = (string) get_bk_option( 'booking_highlight_availability_word' );
627 $settings['booking_is_show_availability_in_date_cell'] = (string) get_bk_option( 'booking_is_show_availability_in_date_cell' );
628 $settings['booking_highlight_availability_word_in_date_cell'] = (string) get_bk_option( 'booking_highlight_availability_word_in_date_cell' );
629 }
630
631 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
632 $settings['booking_is_show_cost_in_tooltips'] = (string) get_bk_option( 'booking_is_show_cost_in_tooltips' );
633 $settings['booking_highlight_cost_word'] = (string) get_bk_option( 'booking_highlight_cost_word' );
634 $settings['booking_is_show_cost_in_date_cell'] = (string) get_bk_option( 'booking_is_show_cost_in_date_cell' );
635 $settings['booking_cost_in_date_cell_currency'] = (string) get_bk_option( 'booking_cost_in_date_cell_currency' );
636 $settings['booking_is_show_booked_data_in_tooltips'] = (string) get_bk_option( 'booking_is_show_booked_data_in_tooltips' );
637 $settings['booking_booked_data_in_tooltips'] = (string) get_bk_option( 'booking_booked_data_in_tooltips' );
638 }
639
640 return $settings;
641 }
642
643 /**
644 * Get normalized day-selection settings for the calendar JS.
645 *
646 * @param array $settings Optional settings.
647 *
648 * @return array
649 */
650 function wpbc_settings_calendar__get_days_selection_response( $settings = array() ) {
651
652 $current = wp_parse_args( $settings, wpbc_settings_calendar__get_settings_response() );
653
654 $specific_days = ( function_exists( 'wpbc_get_specific_range_dates__as_comma_list' ) )
655 ? wpbc_get_specific_range_dates__as_comma_list( $current['booking_range_selection_days_specific_num_dynamic'] )
656 : $current['booking_range_selection_days_specific_num_dynamic'];
657
658 return array(
659 'days_select_mode' => ( 'range' === $current['booking_type_of_day_selections'] )
660 ? ( wpbc_settings_calendar__is_range_supported() ? $current['booking_range_selection_type'] : 'dynamic' )
661 : $current['booking_type_of_day_selections'],
662 'fixed__days_num' => wpbc_settings_calendar__normalize_fixed_range_days_count( $current['booking_range_selection_days_count'] ),
663 'fixed__week_days__start' => wpbc_settings_calendar__normalize_week_days( $current['booking_range_start_day'] ),
664 'dynamic__days_min' => max( 1, absint( $current['booking_range_selection_days_count_dynamic'] ) ),
665 'dynamic__days_max' => max( 1, absint( $current['booking_range_selection_days_max_count_dynamic'] ) ),
666 'dynamic__days_specific' => (string) $specific_days,
667 'dynamic__week_days__start' => wpbc_settings_calendar__normalize_week_days( $current['booking_range_start_day_dynamic'] ),
668 );
669 }
670
671 /**
672 * Check whether booked time slots should be shown in calendar tooltips.
673 *
674 * @param array $settings Calendar settings.
675 *
676 * @return bool
677 */
678 function wpbc_settings_calendar__is_timeslots_tooltip_enabled( $settings ) {
679
680 return ( 'On' !== (string) $settings['booking_disable_timeslots_in_tooltip'] );
681 }
682
683 /**
684 * Override get_bk_option during preview rendering.
685 *
686 * @param mixed $value Current value.
687 * @param string $option Option name.
688 * @param mixed $default Default.
689 *
690 * @return mixed
691 */
692 function wpbc_settings_calendar__preview_get_bk_option( $value, $option, $default ) {
693
694 global $wpbc_settings_calendar__preview_options;
695
696 if (
697 is_array( $wpbc_settings_calendar__preview_options )
698 && array_key_exists( $option, $wpbc_settings_calendar__preview_options )
699 ) {
700 return $wpbc_settings_calendar__preview_options[ $option ];
701 }
702
703 return $value;
704 }
705 add_bk_filter( 'wpdev_bk_get_option', 'wpbc_settings_calendar__preview_get_bk_option' );
706
707 /**
708 * Override native WordPress options while Calendar Settings preview is active.
709 *
710 * This backs up the internal WPBC option filter for render paths that fall through
711 * to get_option(), without saving preview values into the database.
712 *
713 * @param mixed $pre_option Pre-option value.
714 * @param string $option Option name.
715 * @param mixed $default Default option value.
716 *
717 * @return mixed
718 */
719 function wpbc_settings_calendar__preview_get_wp_option( $pre_option, $option, $default ) {
720
721 global $wpbc_settings_calendar__preview_options;
722
723 if (
724 is_array( $wpbc_settings_calendar__preview_options )
725 && array_key_exists( $option, $wpbc_settings_calendar__preview_options )
726 ) {
727 return $wpbc_settings_calendar__preview_options[ $option ];
728 }
729
730 return $pre_option;
731 }
732
733 /**
734 * Register native option preview filters for the current option set.
735 *
736 * @param array $preview_options Preview option overrides.
737 *
738 * @return void
739 */
740 function wpbc_settings_calendar__preview_register_wp_option_filters( $preview_options ) {
741
742 global $wpbc_settings_calendar__preview_wp_option_filters;
743
744 if ( ! is_array( $preview_options ) ) {
745 return;
746 }
747
748 if ( ! is_array( $wpbc_settings_calendar__preview_wp_option_filters ) ) {
749 $wpbc_settings_calendar__preview_wp_option_filters = array();
750 }
751
752 foreach ( array_keys( $preview_options ) as $option_name ) {
753 $option_name = (string) $option_name;
754 if ( isset( $wpbc_settings_calendar__preview_wp_option_filters[ $option_name ] ) ) {
755 continue;
756 }
757 add_filter( 'pre_option_' . $option_name, 'wpbc_settings_calendar__preview_get_wp_option', 10, 3 );
758 $wpbc_settings_calendar__preview_wp_option_filters[ $option_name ] = true;
759 }
760 }
761
762 /**
763 * Activate Calendar Settings preview option overrides.
764 *
765 * @param array $preview_options Preview option overrides.
766 *
767 * @return array Previous preview context.
768 */
769 function wpbc_settings_calendar__preview_options_push( $preview_options ) {
770
771 global $wpbc_settings_calendar__preview_options;
772
773 $previous_context = array(
774 'is_set' => isset( $wpbc_settings_calendar__preview_options ),
775 'value' => isset( $wpbc_settings_calendar__preview_options ) ? $wpbc_settings_calendar__preview_options : null,
776 );
777
778 $wpbc_settings_calendar__preview_options = is_array( $preview_options ) ? $preview_options : array();
779
780 // Re-append while preview is active so this override runs after edition/MU option filters.
781 add_bk_filter( 'wpdev_bk_get_option', 'wpbc_settings_calendar__preview_get_bk_option' );
782
783 wpbc_settings_calendar__preview_register_wp_option_filters( $wpbc_settings_calendar__preview_options );
784
785 return $previous_context;
786 }
787
788 /**
789 * Restore Calendar Settings preview option overrides.
790 *
791 * @param array $previous_context Previous preview context from wpbc_settings_calendar__preview_options_push().
792 *
793 * @return void
794 */
795 function wpbc_settings_calendar__preview_options_pop( $previous_context ) {
796
797 global $wpbc_settings_calendar__preview_options;
798
799 if ( ! empty( $previous_context['is_set'] ) ) {
800 $wpbc_settings_calendar__preview_options = $previous_context['value'];
801 } else {
802 unset( $wpbc_settings_calendar__preview_options );
803 }
804 }
805
806 /**
807 * Check whether a calendar-load AJAX request may use Calendar Settings preview overrides.
808 *
809 * @param array $request_params Calendar-load request params.
810 *
811 * @return bool
812 */
813 function wpbc_settings_calendar__is_calendar_load_preview_request_allowed( $request_params ) {
814
815 return (
816 ! empty( $request_params['wpbc_settings_calendar_preview'] )
817 && function_exists( 'wpbc_is_mu_user_can_be_here' )
818 && wpbc_is_mu_user_can_be_here( 'only_super_admin' )
819 && current_user_can( wpbc_settings_calendar__get_manage_cap() )
820 );
821 }
822
823 /**
824 * Get option overrides from Calendar Settings calendar-load AJAX request.
825 *
826 * @param array $request_params Calendar-load request params.
827 *
828 * @return array
829 */
830 function wpbc_settings_calendar__get_calendar_load_preview_options( $request_params ) {
831
832 $preview_options = array(
833 'booking_range_selection_time_is_active' => isset( $request_params['wpbc_settings_calendar_preview_changeover'] ) ? $request_params['wpbc_settings_calendar_preview_changeover'] : 'Off',
834 'booking_change_over_days_triangles' => isset( $request_params['wpbc_settings_calendar_preview_triangles'] ) ? $request_params['wpbc_settings_calendar_preview_triangles'] : 'On',
835 'booking_recurrent_time' => isset( $request_params['wpbc_settings_calendar_preview_recurrent_time'] ) ? $request_params['wpbc_settings_calendar_preview_recurrent_time'] : 'Off',
836 'booking_last_checkout_day_available' => isset( $request_params['wpbc_settings_calendar_preview_last_checkout'] ) ? $request_params['wpbc_settings_calendar_preview_last_checkout'] : 'Off',
837 'booking_change_over__is_excerpt_on_pages' => isset( $request_params['wpbc_settings_calendar_preview_excerpt_on_pages'] ) ? $request_params['wpbc_settings_calendar_preview_excerpt_on_pages'] : 'Off',
838 'booking_change_over__excerpt_on_pages' => isset( $request_params['wpbc_settings_calendar_preview_excerpt_pages'] ) ? $request_params['wpbc_settings_calendar_preview_excerpt_pages'] : '',
839 'booking_change_over__excerpt_bk_resources' => isset( $request_params['wpbc_settings_calendar_preview_excerpt_resources'] ) ? $request_params['wpbc_settings_calendar_preview_excerpt_resources'] : '',
840 'booking_is_show_legend' => isset( $request_params['wpbc_settings_calendar_preview_show_legend'] ) ? $request_params['wpbc_settings_calendar_preview_show_legend'] : 'Off',
841 'booking_legend_is_show_numbers' => isset( $request_params['wpbc_settings_calendar_preview_legend_show_numbers'] ) ? $request_params['wpbc_settings_calendar_preview_legend_show_numbers'] : 'Off',
842 'booking_legend_is_vertical' => isset( $request_params['wpbc_settings_calendar_preview_legend_vertical'] ) ? $request_params['wpbc_settings_calendar_preview_legend_vertical'] : 'Off',
843 'booking_disable_timeslots_in_tooltip' => isset( $request_params['wpbc_settings_calendar_preview_disable_timeslots_tooltip'] ) ? $request_params['wpbc_settings_calendar_preview_disable_timeslots_tooltip'] : 'Off',
844 'booking_highlight_timeslot_word' => isset( $request_params['wpbc_settings_calendar_preview_timeslot_word'] ) ? $request_params['wpbc_settings_calendar_preview_timeslot_word'] : '',
845 );
846
847 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
848 $preview_options[ 'booking_legend_is_show_item_' . $legend_item ] = isset( $request_params[ 'wpbc_settings_calendar_preview_legend_show_' . $legend_item ] ) ? $request_params[ 'wpbc_settings_calendar_preview_legend_show_' . $legend_item ] : 'Off';
849 $preview_options[ 'booking_legend_text_for_item_' . $legend_item ] = isset( $request_params[ 'wpbc_settings_calendar_preview_legend_text_' . $legend_item ] ) ? $request_params[ 'wpbc_settings_calendar_preview_legend_text_' . $legend_item ] : '';
850 }
851
852 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
853 $preview_options['booking_is_show_availability_in_tooltips'] = isset( $request_params['wpbc_settings_calendar_preview_show_availability_tooltip'] ) ? $request_params['wpbc_settings_calendar_preview_show_availability_tooltip'] : 'Off';
854 $preview_options['booking_highlight_availability_word'] = isset( $request_params['wpbc_settings_calendar_preview_availability_word'] ) ? $request_params['wpbc_settings_calendar_preview_availability_word'] : '';
855 $preview_options['booking_is_show_availability_in_date_cell'] = isset( $request_params['wpbc_settings_calendar_preview_show_availability_cell'] ) ? $request_params['wpbc_settings_calendar_preview_show_availability_cell'] : 'Off';
856 $preview_options['booking_highlight_availability_word_in_date_cell'] = isset( $request_params['wpbc_settings_calendar_preview_availability_cell_word'] ) ? $request_params['wpbc_settings_calendar_preview_availability_cell_word'] : '';
857 }
858
859 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
860 $preview_options['booking_is_show_cost_in_tooltips'] = isset( $request_params['wpbc_settings_calendar_preview_show_cost_tooltip'] ) ? $request_params['wpbc_settings_calendar_preview_show_cost_tooltip'] : 'Off';
861 $preview_options['booking_highlight_cost_word'] = isset( $request_params['wpbc_settings_calendar_preview_cost_word'] ) ? $request_params['wpbc_settings_calendar_preview_cost_word'] : '';
862 $preview_options['booking_is_show_cost_in_date_cell'] = isset( $request_params['wpbc_settings_calendar_preview_show_cost_cell'] ) ? $request_params['wpbc_settings_calendar_preview_show_cost_cell'] : 'Off';
863 $preview_options['booking_cost_in_date_cell_currency'] = isset( $request_params['wpbc_settings_calendar_preview_cost_currency'] ) ? $request_params['wpbc_settings_calendar_preview_cost_currency'] : '';
864 $preview_options['booking_is_show_booked_data_in_tooltips'] = isset( $request_params['wpbc_settings_calendar_preview_show_booked_details'] ) ? $request_params['wpbc_settings_calendar_preview_show_booked_details'] : 'Off';
865 $preview_options['booking_booked_data_in_tooltips'] = isset( $request_params['wpbc_settings_calendar_preview_booked_details'] ) ? $request_params['wpbc_settings_calendar_preview_booked_details'] : '';
866 }
867
868 return $preview_options;
869 }
870
871 /**
872 * Get request overrides for the calendar-load AJAX generated inside Calendar Settings preview.
873 *
874 * @param array $current_settings Current preview settings.
875 *
876 * @return array
877 */
878 function wpbc_settings_calendar__get_calendar_load_preview_request_overrides( $current_settings ) {
879
880 $request_overrides = array(
881 'wpbc_settings_calendar_preview' => 1,
882 'wpbc_settings_calendar_preview_changeover' => ( 'On' === (string) $current_settings['booking_range_selection_time_is_active'] ) ? 'On' : 'Off',
883 'wpbc_settings_calendar_preview_triangles' => ( 'Off' === (string) $current_settings['booking_change_over_days_triangles'] ) ? 'Off' : 'On',
884 'wpbc_settings_calendar_preview_recurrent_time' => ( 'On' === (string) $current_settings['booking_recurrent_time'] ) ? 'On' : 'Off',
885 'wpbc_settings_calendar_preview_last_checkout' => ( 'On' === (string) $current_settings['booking_last_checkout_day_available'] ) ? 'On' : 'Off',
886 'wpbc_settings_calendar_preview_excerpt_on_pages' => ( 'On' === (string) $current_settings['booking_change_over__is_excerpt_on_pages'] ) ? 'On' : 'Off',
887 'wpbc_settings_calendar_preview_excerpt_pages' => (string) $current_settings['booking_change_over__excerpt_on_pages'],
888 'wpbc_settings_calendar_preview_excerpt_resources' => (string) $current_settings['booking_change_over__excerpt_bk_resources'],
889 'wpbc_settings_calendar_preview_show_legend' => ( 'On' === (string) $current_settings['booking_is_show_legend'] ) ? 'On' : 'Off',
890 'wpbc_settings_calendar_preview_legend_show_numbers' => ( 'On' === (string) $current_settings['booking_legend_is_show_numbers'] ) ? 'On' : 'Off',
891 'wpbc_settings_calendar_preview_legend_vertical' => ( 'On' === (string) $current_settings['booking_legend_is_vertical'] ) ? 'On' : 'Off',
892 'wpbc_settings_calendar_preview_disable_timeslots_tooltip' => ( 'On' === (string) $current_settings['booking_disable_timeslots_in_tooltip'] ) ? 'On' : 'Off',
893 'wpbc_settings_calendar_preview_timeslot_word' => (string) $current_settings['booking_highlight_timeslot_word'],
894 );
895
896 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
897 $is_show_key = 'booking_legend_is_show_item_' . $legend_item;
898 $text_key = 'booking_legend_text_for_item_' . $legend_item;
899 if ( isset( $current_settings[ $is_show_key ] ) ) {
900 $request_overrides[ 'wpbc_settings_calendar_preview_legend_show_' . $legend_item ] = ( 'On' === (string) $current_settings[ $is_show_key ] ) ? 'On' : 'Off';
901 }
902 if ( isset( $current_settings[ $text_key ] ) ) {
903 $request_overrides[ 'wpbc_settings_calendar_preview_legend_text_' . $legend_item ] = (string) $current_settings[ $text_key ];
904 }
905 }
906
907 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
908 $request_overrides['wpbc_settings_calendar_preview_show_availability_tooltip'] = ( 'On' === (string) $current_settings['booking_is_show_availability_in_tooltips'] ) ? 'On' : 'Off';
909 $request_overrides['wpbc_settings_calendar_preview_availability_word'] = (string) $current_settings['booking_highlight_availability_word'];
910 $request_overrides['wpbc_settings_calendar_preview_show_availability_cell'] = ( 'On' === (string) $current_settings['booking_is_show_availability_in_date_cell'] ) ? 'On' : 'Off';
911 $request_overrides['wpbc_settings_calendar_preview_availability_cell_word'] = (string) $current_settings['booking_highlight_availability_word_in_date_cell'];
912 }
913
914 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
915 $request_overrides['wpbc_settings_calendar_preview_show_cost_tooltip'] = ( 'On' === (string) $current_settings['booking_is_show_cost_in_tooltips'] ) ? 'On' : 'Off';
916 $request_overrides['wpbc_settings_calendar_preview_cost_word'] = (string) $current_settings['booking_highlight_cost_word'];
917 $request_overrides['wpbc_settings_calendar_preview_show_cost_cell'] = ( 'On' === (string) $current_settings['booking_is_show_cost_in_date_cell'] ) ? 'On' : 'Off';
918 $request_overrides['wpbc_settings_calendar_preview_cost_currency'] = (string) $current_settings['booking_cost_in_date_cell_currency'];
919 $request_overrides['wpbc_settings_calendar_preview_show_booked_details'] = ( 'On' === (string) $current_settings['booking_is_show_booked_data_in_tooltips'] ) ? 'On' : 'Off';
920 $request_overrides['wpbc_settings_calendar_preview_booked_details'] = (string) $current_settings['booking_booked_data_in_tooltips'];
921 }
922
923 return $request_overrides;
924 }
925
926 /**
927 * Check change-over state while Calendar Settings preview option overrides are active.
928 *
929 * @param int|string $resource_id Booking resource ID.
930 * @param string|false $request_uri Request URI or false for current URI.
931 *
932 * @return bool|null Boolean when preview context is active, null otherwise.
933 */
934 function wpbc_settings_calendar__preview_is_changeover_enabled( $resource_id = 0, $request_uri = false ) {
935
936 global $wpbc_settings_calendar__preview_options;
937
938 if ( ! is_array( $wpbc_settings_calendar__preview_options ) ) {
939 return null;
940 }
941
942 if (
943 ! isset( $wpbc_settings_calendar__preview_options['booking_range_selection_time_is_active'] )
944 || 'On' !== (string) $wpbc_settings_calendar__preview_options['booking_range_selection_time_is_active']
945 ) {
946 return false;
947 }
948
949 if ( function_exists( 'wpbc_is_booking_used_check_in_out_time' ) ) {
950 return wpbc_is_booking_used_check_in_out_time( $request_uri, $resource_id );
951 }
952
953 return true;
954 }
955
956 /**
957 * Validate page data.
958 *
959 * @param array $post_data Raw post data.
960 *
961 * @return array
962 */
963 function wpbc_settings_calendar__validate_data( $post_data, $is_preview = false ) {
964
965 $current = wpbc_settings_calendar__get_settings_response();
966 $max_months = wpbc_settings_calendar__get_max_month_options();
967 $weekdays = wpbc_settings_calendar__get_weekday_options();
968 $range_supported = wpbc_settings_calendar__is_range_supported();
969 $cleaned = array();
970
971 $max_monthes = isset( $post_data['booking_max_monthes_in_calendar'] ) ? sanitize_text_field( wp_unslash( $post_data['booking_max_monthes_in_calendar'] ) ) : $current['booking_max_monthes_in_calendar'];
972 $cleaned['booking_max_monthes_in_calendar'] = isset( $max_months[ $max_monthes ] ) ? $max_monthes : '1y';
973
974 $start_day = isset( $post_data['booking_start_day_weeek'] ) ? sanitize_key( wp_unslash( $post_data['booking_start_day_weeek'] ) ) : $current['booking_start_day_weeek'];
975 $cleaned['booking_start_day_weeek'] = array_key_exists( $start_day, $weekdays ) ? $start_day : '0';
976
977 $cleaned['booking_calendar_allow_several_months_on_mobile'] = ( isset( $post_data['booking_calendar_allow_several_months_on_mobile'] ) && 'On' === wp_unslash( $post_data['booking_calendar_allow_several_months_on_mobile'] ) ) ? 'On' : 'Off';
978
979 $day_mode = isset( $post_data['booking_type_of_day_selections'] ) ? sanitize_key( wp_unslash( $post_data['booking_type_of_day_selections'] ) ) : $current['booking_type_of_day_selections'];
980 if ( ! in_array( $day_mode, array( 'single', 'multiple', 'range' ), true ) ) {
981 $day_mode = 'multiple';
982 }
983 $cleaned['booking_type_of_day_selections'] = $day_mode;
984
985 $range_type = isset( $post_data['booking_range_selection_type'] ) ? sanitize_key( wp_unslash( $post_data['booking_range_selection_type'] ) ) : $current['booking_range_selection_type'];
986 $cleaned['booking_range_selection_type'] = in_array( $range_type, array( 'fixed', 'dynamic' ), true ) ? $range_type : 'dynamic';
987
988 $cleaned['booking_range_selection_days_count'] = (string) wpbc_settings_calendar__normalize_fixed_range_days_count( isset( $post_data['booking_range_selection_days_count'] ) ? wp_unslash( $post_data['booking_range_selection_days_count'] ) : $current['booking_range_selection_days_count'] );
989 $cleaned['booking_range_selection_days_count_dynamic'] = (string) min( 1095, max( 1, absint( isset( $post_data['booking_range_selection_days_count_dynamic'] ) ? wp_unslash( $post_data['booking_range_selection_days_count_dynamic'] ) : $current['booking_range_selection_days_count_dynamic'] ) ) );
990 $cleaned['booking_range_selection_days_max_count_dynamic'] = (string) min( 1095, max( 1, absint( isset( $post_data['booking_range_selection_days_max_count_dynamic'] ) ? wp_unslash( $post_data['booking_range_selection_days_max_count_dynamic'] ) : $current['booking_range_selection_days_max_count_dynamic'] ) ) );
991 if ( (int) $cleaned['booking_range_selection_days_max_count_dynamic'] < (int) $cleaned['booking_range_selection_days_count_dynamic'] ) {
992 $cleaned['booking_range_selection_days_max_count_dynamic'] = $cleaned['booking_range_selection_days_count_dynamic'];
993 }
994
995 $cleaned['booking_range_selection_days_specific_num_dynamic'] = isset( $post_data['booking_range_selection_days_specific_num_dynamic'] )
996 ? preg_replace( '/[^0-9,\-\s]/', '', sanitize_text_field( wp_unslash( $post_data['booking_range_selection_days_specific_num_dynamic'] ) ) )
997 : $current['booking_range_selection_days_specific_num_dynamic'];
998
999 $fixed_start_mode = isset( $post_data['booking_range_start_day_mode'] ) ? sanitize_key( wp_unslash( $post_data['booking_range_start_day_mode'] ) ) : ( '-1' === $current['booking_range_start_day'] ? '-1' : 'specific' );
1000 $dynamic_start_mode = isset( $post_data['booking_range_start_day_dynamic_mode'] ) ? sanitize_key( wp_unslash( $post_data['booking_range_start_day_dynamic_mode'] ) ) : ( '-1' === $current['booking_range_start_day_dynamic'] ? '-1' : 'specific' );
1001 $cleaned['booking_range_start_day'] = ( '-1' === $fixed_start_mode )
1002 ? '-1'
1003 : wpbc_settings_calendar__normalize_week_days( isset( $post_data['booking_range_start_day_weekdays'] ) ? wp_unslash( $post_data['booking_range_start_day_weekdays'] ) : $current['booking_range_start_day'] );
1004 $cleaned['booking_range_start_day_dynamic'] = ( '-1' === $dynamic_start_mode )
1005 ? '-1'
1006 : wpbc_settings_calendar__normalize_week_days( isset( $post_data['booking_range_start_day_dynamic_weekdays'] ) ? wp_unslash( $post_data['booking_range_start_day_dynamic_weekdays'] ) : $current['booking_range_start_day_dynamic'] );
1007
1008 $cleaned['booking_recurrent_time'] = ( isset( $post_data['booking_recurrent_time'] ) && 'On' === wp_unslash( $post_data['booking_recurrent_time'] ) ) ? 'On' : 'Off';
1009 $cleaned['booking_last_checkout_day_available'] = ( isset( $post_data['booking_last_checkout_day_available'] ) && 'On' === wp_unslash( $post_data['booking_last_checkout_day_available'] ) ) ? 'On' : 'Off';
1010 $cleaned['booking_range_selection_time_is_active'] = ( isset( $post_data['booking_range_selection_time_is_active'] ) && 'On' === wp_unslash( $post_data['booking_range_selection_time_is_active'] ) ) ? 'On' : 'Off';
1011 $cleaned['booking_change_over_days_triangles'] = ( isset( $post_data['booking_change_over_days_triangles'] ) && 'On' === wp_unslash( $post_data['booking_change_over_days_triangles'] ) ) ? 'On' : 'Off';
1012 $cleaned['booking_change_over__is_excerpt_on_pages'] = ( isset( $post_data['booking_change_over__is_excerpt_on_pages'] ) && 'On' === wp_unslash( $post_data['booking_change_over__is_excerpt_on_pages'] ) ) ? 'On' : 'Off';
1013
1014 foreach ( array( 'booking_range_selection_start_time', 'booking_range_selection_end_time' ) as $time_key ) {
1015 $time_value = isset( $post_data[ $time_key ] ) ? sanitize_text_field( wp_unslash( $post_data[ $time_key ] ) ) : $current[ $time_key ];
1016 $cleaned[ $time_key ] = preg_match( '/^\d{2}:\d{2}$/', $time_value ) ? $time_value : $current[ $time_key ];
1017 }
1018
1019 $cleaned['booking_change_over__excerpt_on_pages'] = isset( $post_data['booking_change_over__excerpt_on_pages'] ) ? sanitize_textarea_field( wp_unslash( $post_data['booking_change_over__excerpt_on_pages'] ) ) : $current['booking_change_over__excerpt_on_pages'];
1020 $cleaned['booking_change_over__excerpt_bk_resources'] = isset( $post_data['booking_change_over__excerpt_bk_resources'] ) ? sanitize_textarea_field( wp_unslash( $post_data['booking_change_over__excerpt_bk_resources'] ) ) : $current['booking_change_over__excerpt_bk_resources'];
1021
1022 $cleaned['booking_is_show_legend'] = ( isset( $post_data['booking_is_show_legend'] ) && 'On' === wp_unslash( $post_data['booking_is_show_legend'] ) ) ? 'On' : 'Off';
1023 $cleaned['booking_legend_is_show_numbers'] = ( isset( $post_data['booking_legend_is_show_numbers'] ) && 'On' === wp_unslash( $post_data['booking_legend_is_show_numbers'] ) ) ? 'On' : 'Off';
1024 $cleaned['booking_legend_is_vertical'] = ( isset( $post_data['booking_legend_is_vertical'] ) && 'On' === wp_unslash( $post_data['booking_legend_is_vertical'] ) ) ? 'On' : 'Off';
1025 if ( isset( $post_data['booking_show_timeslots_in_tooltip'] ) ) {
1026 $cleaned['booking_disable_timeslots_in_tooltip'] = ( 'On' === wp_unslash( $post_data['booking_show_timeslots_in_tooltip'] ) ) ? 'Off' : 'On';
1027 } else {
1028 $cleaned['booking_disable_timeslots_in_tooltip'] = ( isset( $post_data['booking_disable_timeslots_in_tooltip'] ) && 'On' === wp_unslash( $post_data['booking_disable_timeslots_in_tooltip'] ) ) ? 'On' : 'Off';
1029 }
1030 $cleaned['booking_highlight_timeslot_word'] = isset( $post_data['booking_highlight_timeslot_word'] ) ? sanitize_text_field( wp_unslash( $post_data['booking_highlight_timeslot_word'] ) ) : $current['booking_highlight_timeslot_word'];
1031
1032 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
1033 $is_show_key = 'booking_legend_is_show_item_' . $legend_item;
1034 $text_key = 'booking_legend_text_for_item_' . $legend_item;
1035 $cleaned[ $is_show_key ] = ( isset( $post_data[ $is_show_key ] ) && 'On' === wp_unslash( $post_data[ $is_show_key ] ) ) ? 'On' : 'Off';
1036 $cleaned[ $text_key ] = isset( $post_data[ $text_key ] ) ? sanitize_text_field( wp_unslash( $post_data[ $text_key ] ) ) : $current[ $text_key ];
1037 }
1038
1039 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
1040 $cleaned['booking_is_show_availability_in_tooltips'] = ( isset( $post_data['booking_is_show_availability_in_tooltips'] ) && 'On' === wp_unslash( $post_data['booking_is_show_availability_in_tooltips'] ) ) ? 'On' : 'Off';
1041 $cleaned['booking_highlight_availability_word'] = isset( $post_data['booking_highlight_availability_word'] ) ? sanitize_text_field( wp_unslash( $post_data['booking_highlight_availability_word'] ) ) : $current['booking_highlight_availability_word'];
1042 $cleaned['booking_is_show_availability_in_date_cell'] = ( isset( $post_data['booking_is_show_availability_in_date_cell'] ) && 'On' === wp_unslash( $post_data['booking_is_show_availability_in_date_cell'] ) ) ? 'On' : 'Off';
1043 $cleaned['booking_highlight_availability_word_in_date_cell'] = isset( $post_data['booking_highlight_availability_word_in_date_cell'] ) ? sanitize_text_field( wp_unslash( $post_data['booking_highlight_availability_word_in_date_cell'] ) ) : $current['booking_highlight_availability_word_in_date_cell'];
1044 }
1045
1046 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
1047 $cleaned['booking_is_show_cost_in_tooltips'] = ( isset( $post_data['booking_is_show_cost_in_tooltips'] ) && 'On' === wp_unslash( $post_data['booking_is_show_cost_in_tooltips'] ) ) ? 'On' : 'Off';
1048 $cleaned['booking_highlight_cost_word'] = isset( $post_data['booking_highlight_cost_word'] ) ? sanitize_text_field( wp_unslash( $post_data['booking_highlight_cost_word'] ) ) : $current['booking_highlight_cost_word'];
1049 $cleaned['booking_is_show_cost_in_date_cell'] = ( isset( $post_data['booking_is_show_cost_in_date_cell'] ) && 'On' === wp_unslash( $post_data['booking_is_show_cost_in_date_cell'] ) ) ? 'On' : 'Off';
1050 $cleaned['booking_cost_in_date_cell_currency'] = isset( $post_data['booking_cost_in_date_cell_currency'] ) ? sanitize_text_field( wp_unslash( $post_data['booking_cost_in_date_cell_currency'] ) ) : $current['booking_cost_in_date_cell_currency'];
1051 $cleaned['booking_is_show_booked_data_in_tooltips'] = ( isset( $post_data['booking_is_show_booked_data_in_tooltips'] ) && 'On' === wp_unslash( $post_data['booking_is_show_booked_data_in_tooltips'] ) ) ? 'On' : 'Off';
1052 $cleaned['booking_booked_data_in_tooltips'] = isset( $post_data['booking_booked_data_in_tooltips'] ) ? sanitize_text_field( wp_unslash( $post_data['booking_booked_data_in_tooltips'] ) ) : $current['booking_booked_data_in_tooltips'];
1053 }
1054
1055 if ( ! $is_preview && ! $range_supported ) {
1056 foreach ( array( 'booking_range_selection_time_is_active', 'booking_last_checkout_day_available', 'booking_change_over_days_triangles', 'booking_change_over__is_excerpt_on_pages' ) as $premium_key ) {
1057 $cleaned[ $premium_key ] = $current[ $premium_key ];
1058 }
1059 }
1060
1061 return $cleaned;
1062 }
1063
1064 /**
1065 * Update settings.
1066 *
1067 * @param array $cleaned_data Cleaned data.
1068 *
1069 * @return void
1070 */
1071 function wpbc_settings_calendar__update_settings( $cleaned_data ) {
1072
1073 $range_supported = wpbc_settings_calendar__is_range_supported();
1074 $free_keys = array(
1075 'booking_max_monthes_in_calendar',
1076 'booking_start_day_weeek',
1077 'booking_calendar_allow_several_months_on_mobile',
1078 'booking_type_of_day_selections',
1079 'booking_recurrent_time',
1080 'booking_is_show_legend',
1081 'booking_legend_is_show_numbers',
1082 'booking_legend_is_vertical',
1083 'booking_disable_timeslots_in_tooltip',
1084 'booking_highlight_timeslot_word',
1085 );
1086 $premium_keys = array(
1087 'booking_range_selection_type',
1088 'booking_range_selection_days_count',
1089 'booking_range_start_day',
1090 'booking_range_selection_days_count_dynamic',
1091 'booking_range_selection_days_max_count_dynamic',
1092 'booking_range_selection_days_specific_num_dynamic',
1093 'booking_range_start_day_dynamic',
1094 'booking_last_checkout_day_available',
1095 'booking_range_selection_time_is_active',
1096 'booking_range_selection_start_time',
1097 'booking_range_selection_end_time',
1098 'booking_change_over_days_triangles',
1099 'booking_change_over__is_excerpt_on_pages',
1100 'booking_change_over__excerpt_on_pages',
1101 'booking_change_over__excerpt_bk_resources',
1102 );
1103 $availability_tooltip_keys = array(
1104 'booking_is_show_availability_in_tooltips',
1105 'booking_highlight_availability_word',
1106 'booking_is_show_availability_in_date_cell',
1107 'booking_highlight_availability_word_in_date_cell',
1108 );
1109 $cost_tooltip_keys = array(
1110 'booking_is_show_cost_in_tooltips',
1111 'booking_highlight_cost_word',
1112 'booking_is_show_cost_in_date_cell',
1113 'booking_cost_in_date_cell_currency',
1114 'booking_is_show_booked_data_in_tooltips',
1115 'booking_booked_data_in_tooltips',
1116 );
1117 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
1118 $free_keys[] = 'booking_legend_is_show_item_' . $legend_item;
1119 $free_keys[] = 'booking_legend_text_for_item_' . $legend_item;
1120 }
1121
1122 $previous_day_mode = (string) get_bk_option( 'booking_type_of_day_selections' );
1123 foreach ( $free_keys as $key ) {
1124 update_bk_option( $key, $cleaned_data[ $key ] );
1125 }
1126
1127 // Keep a newly selected Free range upgrade-safe: Business Small+ must continue with the same two-click subtype.
1128 if ( ! $range_supported && 'range' === $cleaned_data['booking_type_of_day_selections'] && 'range' !== $previous_day_mode ) {
1129 update_bk_option( 'booking_range_selection_type', 'dynamic' );
1130 }
1131
1132 if ( $range_supported ) {
1133 foreach ( $premium_keys as $key ) {
1134 update_bk_option( $key, $cleaned_data[ $key ] );
1135 }
1136 }
1137
1138 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
1139 foreach ( $availability_tooltip_keys as $key ) {
1140 update_bk_option( $key, $cleaned_data[ $key ] );
1141 }
1142 }
1143
1144 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
1145 foreach ( $cost_tooltip_keys as $key ) {
1146 update_bk_option( $key, $cleaned_data[ $key ] );
1147 }
1148 }
1149 }
1150
1151 /**
1152 * Render select element.
1153 *
1154 * @param string $name Name.
1155 * @param array $options Options.
1156 * @param string $selected Selected value.
1157 * @param array $args Arguments.
1158 *
1159 * @return void
1160 */
1161 function wpbc_settings_calendar__render_select( $name, $options, $selected, $args = array() ) {
1162
1163 $id = isset( $args['id'] ) ? $args['id'] : $name;
1164 $class = isset( $args['class'] ) ? $args['class'] : '';
1165 ?>
1166 <select id="<?php echo esc_attr( $id ); ?>" name="<?php echo esc_attr( $name ); ?>" class="<?php echo esc_attr( $class ); ?>">
1167 <?php foreach ( $options as $value => $label ) : ?>
1168 <option value="<?php echo esc_attr( $value ); ?>" <?php selected( (string) $selected, (string) $value ); ?>><?php echo esc_html( $label ); ?></option>
1169 <?php endforeach; ?>
1170 </select>
1171 <?php
1172 }
1173
1174 /**
1175 * Get premium feature URL by required version label.
1176 *
1177 * @param string $label Premium label.
1178 * @param string $url Optional explicit URL.
1179 *
1180 * @return string
1181 */
1182 function wpbc_settings_calendar__get_premium_url( $label = 'Pro', $url = '' ) {
1183
1184 $generic_features_url = 'https://wpbookingcalendar.com/features/';
1185 $url = trim( (string) $url );
1186
1187 if ( ( '' !== $url ) && ( $generic_features_url !== $url ) ) {
1188 return $url;
1189 }
1190
1191 $label = strtolower( (string) $label );
1192
1193 if ( false !== strpos( $label, 'multiuser' ) ) {
1194 return 'https://wpbookingcalendar.com/features/#multiuser';
1195 }
1196 if ( false !== strpos( $label, 'business large' ) || false !== strpos( $label, 'bl+' ) ) {
1197 return 'https://wpbookingcalendar.com/features/#bl';
1198 }
1199 if ( false !== strpos( $label, 'business medium' ) || false !== strpos( $label, 'bm+' ) ) {
1200 return 'https://wpbookingcalendar.com/features/#bm';
1201 }
1202 if ( false !== strpos( $label, 'business small' ) || false !== strpos( $label, 'bs+' ) ) {
1203 return 'https://wpbookingcalendar.com/features/#bs';
1204 }
1205
1206 return $generic_features_url;
1207 }
1208
1209 /**
1210 * Render premium label.
1211 *
1212 * @return void
1213 */
1214 function wpbc_settings_calendar__render_premium_label( $label = 'Business Small+', $url = 'https://wpbookingcalendar.com/features/', $dismiss_id = '' ) {
1215
1216 $url = wpbc_settings_calendar__get_premium_url( $label, $url );
1217 ?>
1218 <a class="wpbc_pro_label wpbc_calendar_pro_label" href="<?php echo esc_url( $url ); ?>" target="_blank"><?php echo esc_html( $label ); ?></a>
1219 <?php if ( '' !== $dismiss_id ) : ?>
1220 <?php wpbc_settings_calendar__render_dismiss_button( $dismiss_id ); ?>
1221 <?php endif; ?>
1222 <?php
1223 }
1224
1225 /**
1226 * Check if a Calendar Settings upsell row is visible for current user.
1227 *
1228 * @param string $dismiss_id Dismiss ID.
1229 *
1230 * @return bool
1231 */
1232 function wpbc_settings_calendar__is_dismissed_visible( $dismiss_id ) {
1233
1234 if ( wpbc_is_this_demo() ) {
1235 return true;
1236 }
1237
1238 return ! function_exists( 'wpbc_is_dismissed_panel_visible' ) || wpbc_is_dismissed_panel_visible( $dismiss_id );
1239 }
1240
1241 /**
1242 * Get dismiss ID for a Calendar Settings premium option.
1243 *
1244 * @param string $option_name Option name.
1245 *
1246 * @return string
1247 */
1248 function wpbc_settings_calendar__get_premium_option_dismiss_id( $option_name ) {
1249
1250 return 'wpbc_is_dismissed__calendar_settings__' . sanitize_key( $option_name );
1251 }
1252
1253 /**
1254 * Render small dismiss button for Calendar Settings premium hints.
1255 *
1256 * @param string $dismiss_id Dismiss ID.
1257 *
1258 * @return void
1259 */
1260 function wpbc_settings_calendar__render_dismiss_button( $dismiss_id ) {
1261
1262 if ( wpbc_is_this_demo() || ! function_exists( 'wpbc_is_dismissed' ) ) {
1263 return;
1264 }
1265
1266 ?>
1267 <span class="wpbc_calendar_premium_dismiss">
1268 <?php
1269 wpbc_is_dismissed(
1270 $dismiss_id,
1271 array(
1272 'title' => '&times;',
1273 'hint' => __( 'Hide this option', 'booking' ),
1274 'css' => 'float:none;margin-left:4px;',
1275 )
1276 );
1277 ?>
1278 </span>
1279 <?php
1280 }
1281
1282 /**
1283 * Render the Business Small+ explanation for advanced range controls.
1284 *
1285 * @return void
1286 */
1287 function wpbc_settings_calendar__render_range_upgrade_note() {
1288
1289 ?>
1290 <div class="wpbc_calendar_premium_note" data-wpbc-calendar-range-upgrade-note="1">
1291 <div>
1292 <strong><?php esc_html_e( 'Advanced range selection rules', 'booking' ); ?></strong>
1293 <p><?php esc_html_e( 'Two-click range selection is included. Fixed one-click ranges, minimum and maximum lengths, specific permitted lengths, and allowed start weekdays are available in Booking Calendar Business Small or higher.', 'booking' ); ?></p>
1294 </div>
1295 <div class="wpbc_calendar_premium_note_actions">
1296 <a class="button button-secondary" href="<?php echo esc_url( 'https://bm.wpbookingcalendar.com/' ); ?>" target="_blank"><?php esc_html_e( 'View live demo', 'booking' ); ?></a>
1297 <a class="button button-primary" href="<?php echo esc_url( wpbc_settings_calendar__get_premium_url( 'Business Small+' ) ); ?>" target="_blank"><?php esc_html_e( 'Upgrade', 'booking' ); ?></a>
1298 </div>
1299 </div>
1300 <?php
1301 }
1302
1303 /**
1304 * Render Business Small+ explanation for locked changeover controls.
1305 *
1306 * @return void
1307 */
1308 function wpbc_settings_calendar__render_changeover_upgrade_note() {
1309
1310 ?>
1311 <div class="wpbc_calendar_premium_note" data-wpbc-calendar-changeover-upgrade-note="1">
1312 <div>
1313 <strong><?php esc_html_e( 'Changeover days', 'booking' ); ?></strong>
1314 <p><?php esc_html_e( 'Check-in and check-out days can be shown as half-day changeover dates with diagonal or vertical markings. This feature is available in Booking Calendar Business Small or higher.', 'booking' ); ?></p>
1315 </div>
1316 <div class="wpbc_calendar_premium_note_actions">
1317 <a class="button button-secondary" href="<?php echo esc_url( 'https://bm.wpbookingcalendar.com/' ); ?>" target="_blank"><?php esc_html_e( 'View live demo', 'booking' ); ?></a>
1318 <a class="button button-primary" href="<?php echo esc_url( wpbc_settings_calendar__get_premium_url( 'Business Small+' ) ); ?>" target="_blank"><?php esc_html_e( 'Upgrade', 'booking' ); ?></a>
1319 </div>
1320 </div>
1321 <?php
1322 }
1323
1324 /**
1325 * Render disabled premium-only toggle row.
1326 *
1327 * @param string $name Option name.
1328 * @param string $label Label.
1329 * @param string $description Description.
1330 * @param string $premium_label Premium label.
1331 *
1332 * @return void
1333 */
1334 function wpbc_settings_calendar__render_locked_premium_checkbox( $name, $label, $description, $premium_label ) {
1335
1336 $dismiss_id = wpbc_settings_calendar__get_premium_option_dismiss_id( $name );
1337 if ( ! wpbc_settings_calendar__is_dismissed_visible( $dismiss_id ) ) {
1338 return;
1339 }
1340 ?>
1341 <div id="<?php echo esc_attr( $dismiss_id ); ?>" class="wpbc_calendar_field_row wpbc_calendar_locked_premium_field">
1342 <label class="wpbc_calendar_switch wpbc_calendar_switch_card is-premium" aria-disabled="true">
1343 <input type="checkbox" name="<?php echo esc_attr( $name ); ?>" value="On" disabled="disabled" data-wpbc-calendar-premium="1" />
1344 <span class="wpbc_calendar_switch_control" aria-hidden="true"><span class="wpbc_calendar_switch_knob"></span></span>
1345 <span class="wpbc_calendar_switch_label"><?php echo esc_html( $label ); ?></span>
1346 <?php wpbc_settings_calendar__render_premium_label( $premium_label, '', $dismiss_id ); ?>
1347 </label>
1348 <?php if ( '' !== $description ) : ?>
1349 <p class="wpbc_calendar_description"><?php echo wp_kses_post( $description ); ?></p>
1350 <?php endif; ?>
1351 </div>
1352 <?php
1353 }
1354
1355 /**
1356 * Render checkbox field.
1357 *
1358 * @param string $name Option name.
1359 * @param string $label Label.
1360 * @param string $description Description.
1361 * @param array $settings Settings.
1362 * @param bool $is_premium Whether field is premium.
1363 *
1364 * @return bool
1365 */
1366 function wpbc_settings_calendar__render_checkbox( $name, $label, $description, $settings, $is_premium = false ) {
1367
1368 $premium_attr = $is_premium ? 'data-wpbc-calendar-premium="1"' : '';
1369 $dismiss_id = $is_premium ? wpbc_settings_calendar__get_premium_option_dismiss_id( $name ) : '';
1370 if ( $is_premium && ! wpbc_settings_calendar__is_dismissed_visible( $dismiss_id ) ) {
1371 return false;
1372 }
1373 if ( $is_premium && 'booking_range_selection_time_is_active' === $name ) {
1374 $premium_attr .= ' data-wpbc-calendar-premium-changeover-info="1"';
1375 }
1376 ?>
1377 <label class="wpbc_calendar_switch wpbc_calendar_switch_card <?php echo $is_premium ? 'is-premium' : ''; ?>">
1378 <input type="checkbox" name="<?php echo esc_attr( $name ); ?>" value="On" <?php checked( 'On', $settings[ $name ] ); ?> <?php echo $premium_attr; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> />
1379 <span class="wpbc_calendar_switch_control" aria-hidden="true"><span class="wpbc_calendar_switch_knob"></span></span>
1380 <span class="wpbc_calendar_switch_label"><?php echo esc_html( $label ); ?></span>
1381 <?php if ( $is_premium ) : ?>
1382 <?php wpbc_settings_calendar__render_premium_label( 'Business Small+', '', $dismiss_id ); ?>
1383 <?php endif; ?>
1384 </label>
1385 <?php if ( '' !== $description ) : ?>
1386 <p class="wpbc_calendar_description"><?php echo wp_kses_post( $description ); ?></p>
1387 <?php endif; ?>
1388 <?php
1389 return true;
1390 }
1391
1392 /**
1393 * Render legend item toggle with title field.
1394 *
1395 * @param string $legend_item Legend item key.
1396 * @param array $config Legend item config.
1397 * @param array $settings Settings.
1398 *
1399 * @return void
1400 */
1401 function wpbc_settings_calendar__render_legend_item_control( $legend_item, $config, $settings ) {
1402
1403 $is_show_key = 'booking_legend_is_show_item_' . $legend_item;
1404 $text_key = 'booking_legend_text_for_item_' . $legend_item;
1405 ?>
1406 <div class="wpbc_calendar_legend_item_tile" data-wpbc-calendar-legend-item="<?php echo esc_attr( $legend_item ); ?>">
1407 <div class="wpbc_calendar_legend_item_header">
1408 <label class="wpbc_calendar_switch">
1409 <input type="checkbox" name="<?php echo esc_attr( $is_show_key ); ?>" value="On" <?php checked( 'On', $settings[ $is_show_key ] ); ?> />
1410 <span class="wpbc_calendar_switch_control" aria-hidden="true"><span class="wpbc_calendar_switch_knob"></span></span>
1411 <span class="wpbc_calendar_switch_label"><?php echo esc_html( $config['label'] ); ?></span>
1412 </label>
1413 </div>
1414 <div class="wpbc_calendar_legend_item_title">
1415 <label for="<?php echo esc_attr( $text_key ); ?>"><?php esc_html_e( 'Title', 'booking' ); ?></label>
1416 <input type="text" id="<?php echo esc_attr( $text_key ); ?>" name="<?php echo esc_attr( $text_key ); ?>" value="<?php echo esc_attr( $settings[ $text_key ] ); ?>" placeholder="<?php echo esc_attr( $config['placeholder'] ); ?>" />
1417 </div>
1418 <p class="wpbc_calendar_description"><?php echo wp_kses_post( $config['description'] ); ?></p>
1419 <?php if ( ! empty( $config['note'] ) ) : ?>
1420 <p class="wpbc_calendar_description"><strong><?php esc_html_e( 'Note', 'booking' ); ?>:</strong> <?php echo esc_html( $config['note'] ); ?></p>
1421 <?php endif; ?>
1422 </div>
1423 <?php
1424 }
1425
1426 /**
1427 * Render week-day checkbox row.
1428 *
1429 * @param string $name Field name.
1430 * @param string $value Current CSV value.
1431 *
1432 * @return void
1433 */
1434 function wpbc_settings_calendar__render_weekday_checks( $name, $value ) {
1435
1436 $selected = ( '-1' === $value || '' === $value ) ? array() : explode( ',', $value );
1437 ?>
1438 <div class="wpbc_calendar_weekday_checks" data-wpbc-calendar-weekday-checks="<?php echo esc_attr( $name ); ?>">
1439 <?php foreach ( wpbc_settings_calendar__get_weekday_options() as $day_value => $day_label ) : ?>
1440 <label>
1441 <input type="checkbox" name="<?php echo esc_attr( $name ); ?>[]" value="<?php echo esc_attr( $day_value ); ?>" <?php checked( in_array( (string) $day_value, $selected, true ) ); ?> />
1442 <span><?php echo esc_html( $day_label ); ?></span>
1443 </label>
1444 <?php endforeach; ?>
1445 </div>
1446 <?php
1447 }
1448
1449 /**
1450 * Render calendar preview.
1451 *
1452 * @param int $resource_id Resource ID.
1453 * @param int $months_count Number of months.
1454 * @param array $preview_settings Optional settings.
1455 *
1456 * @return void
1457 */
1458 function wpbc_settings_calendar__render_calendar_preview( $resource_id, $months_count, $preview_settings = array() ) {
1459
1460 $resource_id = wpbc_settings_calendar__sanitize_preview_resource_id( $resource_id );
1461 $months_count = wpbc_settings_calendar__sanitize_preview_months_count( $months_count );
1462 $current_settings = wp_parse_args( $preview_settings, wpbc_settings_calendar__get_settings_response() );
1463 $is_change_over_preview = ( 'On' === (string) $current_settings['booking_range_selection_time_is_active'] );
1464 $is_triangle_preview = ( 'Off' !== (string) $current_settings['booking_change_over_days_triangles'] );
1465 $preview_css_classes = 'wpbc_calendar_settings_preview';
1466 if ( $is_change_over_preview && $is_triangle_preview ) {
1467 $preview_css_classes .= ' wpbc_change_over_triangle';
1468 }
1469 $previous_preview_options = wpbc_settings_calendar__preview_options_push( $current_settings );
1470 ?>
1471 <div class="<?php echo esc_attr( $preview_css_classes ); ?>" data-wpbc-admin-calendar-preview="1" data-wpbc-calendar-preview="1" data-resource-id="<?php echo esc_attr( $resource_id ); ?>" data-months-count="<?php echo esc_attr( $months_count ); ?>">
1472 <div class="wpbc_calendar_settings_real_preview" data-wpbc-calendar-panel="1">
1473 <?php
1474 if ( class_exists( 'WPBC_FE_Render' ) ) {
1475 WPBC_FE_Render::render_calendar_only(
1476 array(
1477 'resource_id' => $resource_id,
1478 'cal_count' => $months_count,
1479 'is_echo' => 1,
1480 'calendar_request_overrides' => wpbc_settings_calendar__get_calendar_load_preview_request_overrides( $current_settings ),
1481 )
1482 );
1483 } elseif ( function_exists( 'wpbc__calendar__load' ) ) {
1484 $start_script_code = wpbc__calendar__load(
1485 array(
1486 'resource_id' => $resource_id,
1487 'aggregate_resource_id_arr' => array(),
1488 'selected_dates_without_calendar' => '',
1489 'calendar_number_of_months' => $months_count,
1490 'start_month_calendar' => false,
1491 'shortcode_options' => '',
1492 'custom_form' => 'standard',
1493 'skip_general_availability' => 1,
1494 'calendar_request_overrides' => wpbc_settings_calendar__get_calendar_load_preview_request_overrides( $current_settings ),
1495 )
1496 );
1497 if ( function_exists( 'wpbc_pre_get_calendar_html' ) ) {
1498 echo '<div style="clear:both;height:10px;"></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1499 echo wpbc_pre_get_calendar_html( $resource_id, $months_count, '' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1500 echo ' ' . $start_script_code; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1501 } else {
1502 echo $start_script_code; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1503 }
1504 }
1505 ?>
1506 </div>
1507 </div>
1508 <?php
1509
1510 wpbc_settings_calendar__preview_options_pop( $previous_preview_options );
1511 }
1512
1513 /**
1514 * Show Calendar save button in top toolbar.
1515 *
1516 * @param string $page_tag Current page tag.
1517 * @param string $active_page_tab Current tab.
1518 * @param string $active_page_subtab Current subtab.
1519 *
1520 * @return void
1521 */
1522 function wpbc_settings_calendar__top_toolbar__show_save_button( $page_tag, $active_page_tab, $active_page_subtab ) {
1523
1524 if ( ( 'wpbc-settings' !== $page_tag ) || ( 'calendar_settings' !== $active_page_tab ) ) {
1525 return;
1526 }
1527
1528 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_calendar__get_manage_cap() ) ) {
1529 return;
1530 }
1531 ?>
1532 <div class="wpbc_ui_el__buttons_group wpbc_calendar__top_toolbar_group">
1533 <a href="javascript:void(0);"
1534 class="button button-primary wpbc_calendar__top_btn_save"
1535 data-wpbc-calendar-save="1"
1536 data-wpbc-u-busy-text="<?php esc_attr_e( 'Saving', 'booking' ); ?>...">
1537 <i class="menu_icon icon-1x wpbc-bi-check2-circle"></i>
1538 <span class="in-button-text">&nbsp;&nbsp;<?php esc_html_e( 'Save Changes', 'booking' ); ?></span>
1539 </a>
1540 </div>
1541 <?php
1542 }
1543 add_action( 'wpbc_ui_el__top_nav__content_end', 'wpbc_settings_calendar__top_toolbar__show_save_button', 20, 3 );
1544
1545 /**
1546 * Block direct access for regular users in MultiUser context.
1547 *
1548 * @param bool $is_show_this_page Whether to show page.
1549 * @param string $page_tag Current page.
1550 * @param string $active_page_tab Active tab.
1551 * @param string $active_page_subtab Active subtab.
1552 *
1553 * @return bool
1554 */
1555 function wpbc_settings_calendar__check_showing_page( $is_show_this_page, $page_tag, $active_page_tab, $active_page_subtab ) {
1556
1557 if ( ( 'wpbc-settings' === $page_tag ) && ( 'calendar_settings' === $active_page_tab ) && ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_calendar__get_manage_cap() ) ) ) {
1558 return false;
1559 }
1560
1561 return $is_show_this_page;
1562 }
1563 add_filter( 'wpbc_before_showing_settings_page_is_show_page', 'wpbc_settings_calendar__check_showing_page', 20, 4 );
1564
1565 /**
1566 * Calendar settings tab.
1567 */
1568 class WPBC_Page_Settings_Calendar extends WPBC_Page_Structure {
1569
1570 /**
1571 * Whether settings were saved during this request.
1572 *
1573 * @var bool
1574 */
1575 private $is_updated = false;
1576
1577 /**
1578 * Menu slug.
1579 *
1580 * @return string
1581 */
1582 public function in_page() {
1583
1584 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_calendar__get_manage_cap() ) ) {
1585 return (string) wp_rand( 100000, 1000000 );
1586 }
1587
1588 return 'wpbc-settings';
1589 }
1590
1591 /**
1592 * Register tab.
1593 *
1594 * @return array
1595 */
1596 public function tabs() {
1597
1598 $subtabs = array();
1599 $subtab_default = array(
1600 'type' => 'subtab',
1601 'title' => '',
1602 'page_title' => __( 'Calendar Settings', 'booking' ),
1603 'hint' => '',
1604 'link' => '',
1605 'css_classes' => '',
1606 'font_icon' => 'wpbc-bi-calendar2-range',
1607 'font_icon_right' => 'wpbc-bi-question-circle',
1608 'default' => false,
1609 'content' => 'content',
1610 );
1611
1612 foreach ( wpbc_settings_calendar__get_section_navigation_items() as $section_key => $section ) {
1613 $subtabs[ $section['menu_slug'] ] = array_merge(
1614 $subtab_default,
1615 array(
1616 'title' => $section['title'],
1617 'hint' => $section['hint'],
1618 'font_icon' => $section['font_icon'],
1619 'link' => wpbc_settings_calendar__get_section_url( $section_key ),
1620 'default' => ( 'days_selection' === $section_key ),
1621 )
1622 );
1623 }
1624
1625 return array(
1626 'calendar_settings' => array(
1627 'is_show_top_path' => true,
1628 'right_vertical_sidebar__is_show' => true,
1629 'right_vertical_sidebar__default_view_mode' => '',
1630 'right_vertical_sidebar_compact__is_show' => true,
1631 'left_navigation__default_view_mode' => '', // FixIn:11.7.1.1: 'compact',
1632 'top_path_title' => __( 'Calendar', 'booking' ),
1633 'title' => __( 'Calendar', 'booking' ), // . '<span class="wpbc_new_label" style="margin-left: auto;">' . esc_html__( 'New', 'booking' ) . '</span>&nbsp;&nbsp;',
1634 'hint' => __( 'Preview and configure date selection, range selection, and change-over behavior.', 'booking' ),
1635 'page_title' => __( 'Calendar Settings', 'booking' ),
1636 'link' => '',
1637 'position' => '',
1638 'css_classes' => 'wpbc_top_tab__calendar_settings',
1639 'icon' => '',
1640 'font_icon' => 'wpbc-bi-calendar2-range',
1641 'font_icon_right' => '',
1642 'default' => false,
1643 'disabled' => false,
1644 'hided' => false,
1645 'subtabs' => $subtabs,
1646 'folder_style' => 'order:18;',
1647 ),
1648 );
1649 }
1650
1651 /**
1652 * Save settings.
1653 *
1654 * @return void
1655 */
1656 public function maybe_update() {
1657
1658 $form_name = 'wpbc_settings_calendar_form';
1659
1660 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1661 if ( ! isset( $_POST[ 'is_form_submitted_' . $form_name ] ) ) {
1662 return;
1663 }
1664
1665 check_admin_referer( 'wpbc_settings_page_' . $form_name );
1666
1667 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_calendar__get_manage_cap() ) ) {
1668 return;
1669 }
1670
1671 $cleaned_data = wpbc_settings_calendar__validate_data( $_POST ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1672 wpbc_settings_calendar__update_settings( $cleaned_data );
1673
1674 $this->is_updated = true;
1675 }
1676
1677 /**
1678 * Right compact sidebar tabs.
1679 *
1680 * @return void
1681 */
1682 public function right_sidebar_compact_content() {
1683
1684 WPBC_UI_Sidebar_Panels::render_rightbar_tabs(
1685 array(
1686 array(
1687 'id' => 'wpbc_tab_calendar_settings',
1688 'panel_id' => 'wpbc_calendar__inspector_settings',
1689 'title' => __( 'Settings', 'booking' ),
1690 'icon' => 'wpbc_icn_tune',
1691 'selected' => true,
1692 ),
1693 array(
1694 'id' => 'wpbc_tab_calendar_notes',
1695 'panel_id' => 'wpbc_calendar__inspector_notes',
1696 'title' => __( 'Notes', 'booking' ),
1697 'icon' => 'wpbc-bi-info-circle',
1698 ),
1699 ),
1700 array(
1701 'aria_label' => __( 'Calendar Panels', 'booking' ),
1702 'context' => 'settings_calendar',
1703 'class' => 'wpbc_calendar_rightbar_tabs',
1704 )
1705 );
1706 }
1707
1708 /**
1709 * Right sidebar panels.
1710 *
1711 * @return void
1712 */
1713 public function right_sidebar_content() {
1714 ?>
1715 <div class="wpbc_bfb__panel--library wpbc_rightbar_palette wpbc_calendar_rightbar_panels">
1716 <?php
1717 WPBC_UI_Sidebar_Panels::render_panel(
1718 array(
1719 'id' => 'wpbc_calendar__inspector_settings',
1720 'labelledby' => 'wpbc_tab_calendar_settings',
1721 'class' => 'wpbc_calendar__inspector_settings',
1722 ),
1723 array( $this, 'right_panel_settings_content' )
1724 );
1725
1726 WPBC_UI_Sidebar_Panels::render_panel(
1727 array(
1728 'id' => 'wpbc_calendar__inspector_notes',
1729 'labelledby' => 'wpbc_tab_calendar_notes',
1730 'class' => 'wpbc_calendar__inspector_notes',
1731 'hidden' => true,
1732 ),
1733 array( $this, 'right_panel_notes_content' )
1734 );
1735 ?>
1736 </div>
1737 <?php
1738 }
1739
1740 /**
1741 * Settings panel content.
1742 *
1743 * @return void
1744 */
1745 public function right_panel_settings_content() {
1746
1747 $form_name = 'wpbc_settings_calendar_form';
1748 $settings = wpbc_settings_calendar__get_settings_response();
1749 $is_premium_lock = ! wpbc_settings_calendar__is_range_supported();
1750 $open_section = wpbc_settings_calendar__get_open_section();
1751
1752 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Calendar Settings', 'booking' ), __( 'Date selection and change-over behavior with live calendar preview.', 'booking' ) );
1753 ?>
1754 <form method="post" id="<?php echo esc_attr( $form_name ); ?>" class="wpbc_calendar_settings_form" data-wpbc-calendar-settings-form="1">
1755 <?php wp_nonce_field( 'wpbc_settings_page_' . $form_name ); ?>
1756 <input type="hidden" name="is_form_submitted_<?php echo esc_attr( $form_name ); ?>" value="1" />
1757 <div class="wpbc_bfb__inspector__body wpbc_calendar_inspector_body">
1758 <?php
1759 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1760 array(
1761 'id' => 'wpbc_calendar_days_selection_group',
1762 'group' => 'settings-calendar-days-selection',
1763 'title' => __( 'Days Selection', 'booking' ),
1764 'open' => ( '' === $open_section || 'days_selection' === $open_section ),
1765 ),
1766 function () use ( $settings, $is_premium_lock ) {
1767 $selected_day_mode = in_array( $settings['booking_type_of_day_selections'], array( 'single', 'multiple', 'range' ), true )
1768 ? $settings['booking_type_of_day_selections']
1769 : 'multiple';
1770 $range_days_title = wpbc_settings_calendar__get_range_days_title();
1771 ?>
1772 <div class="wpbc_calendar_radio_stack" data-wpbc-calendar-days-mode="1">
1773 <label><input type="radio" name="booking_type_of_day_selections" value="single" <?php checked( 'single', $selected_day_mode ); ?> /> <span><?php esc_html_e( 'Single day', 'booking' ); ?></span></label>
1774 <label><input type="radio" name="booking_type_of_day_selections" value="multiple" <?php checked( 'multiple', $selected_day_mode ); ?> /> <span><?php esc_html_e( 'Multiple days', 'booking' ); ?></span></label>
1775 <label><input type="radio" name="booking_type_of_day_selections" value="range" <?php checked( 'range', $selected_day_mode ); ?> /> <span><?php echo esc_html( $range_days_title ); ?></span></label>
1776 </div>
1777 <?php if ( $is_premium_lock ) : ?>
1778 <?php wpbc_settings_calendar__render_range_upgrade_note(); ?>
1779 <?php endif; ?>
1780 <?php if ( ! $is_premium_lock ) : ?>
1781 <div class="wpbc_calendar_subsettings" data-wpbc-calendar-range-settings="1">
1782 <div class="wpbc_calendar_radio_stack">
1783 <label><input type="radio" name="booking_range_selection_type" value="fixed" <?php checked( 'fixed', $settings['booking_range_selection_type'] ); ?> /> <span><?php esc_html_e( 'Select a fixed number of days with 1 mouse click', 'booking' ); ?></span></label>
1784 <label><input type="radio" name="booking_range_selection_type" value="dynamic" <?php checked( 'dynamic', $settings['booking_range_selection_type'] ); ?> /> <span><?php esc_html_e( 'Select a dynamic range of days with 2 mouse clicks', 'booking' ); ?></span></label>
1785 </div>
1786 <div class="wpbc_calendar_range_block" data-wpbc-calendar-range-type="fixed">
1787 <div class="wpbc_calendar_field_row">
1788 <label for="booking_range_selection_days_count"><?php esc_html_e( 'Days selection number', 'booking' ); ?></label>
1789 <input type="number" id="booking_range_selection_days_count" name="booking_range_selection_days_count" min="1" max="180" value="<?php echo esc_attr( $settings['booking_range_selection_days_count'] ); ?>" />
1790 </div>
1791 <div class="wpbc_calendar_field_row">
1792 <label><?php esc_html_e( 'Start day of range', 'booking' ); ?></label>
1793 <label><input type="radio" name="booking_range_start_day_mode" value="-1" <?php checked( '-1', $settings['booking_range_start_day'] ); ?> /> <?php esc_html_e( 'Any day of week', 'booking' ); ?></label>
1794 <label><input type="radio" name="booking_range_start_day_mode" value="specific" <?php checked( '-1' !== $settings['booking_range_start_day'] ); ?> /> <?php esc_html_e( 'Specific day(s) of week', 'booking' ); ?></label>
1795 <?php wpbc_settings_calendar__render_weekday_checks( 'booking_range_start_day_weekdays', $settings['booking_range_start_day'] ); ?>
1796 </div>
1797 </div>
1798 <div class="wpbc_calendar_range_block" data-wpbc-calendar-range-type="dynamic">
1799 <div class="wpbc_calendar_inline_fields">
1800 <div class="wpbc_calendar_field_row">
1801 <label for="booking_range_selection_days_count_dynamic"><?php esc_html_e( 'Min', 'booking' ); ?></label>
1802 <input type="number" id="booking_range_selection_days_count_dynamic" name="booking_range_selection_days_count_dynamic" min="1" max="1095" value="<?php echo esc_attr( $settings['booking_range_selection_days_count_dynamic'] ); ?>" />
1803 </div>
1804 <div class="wpbc_calendar_field_row">
1805 <label for="booking_range_selection_days_max_count_dynamic"><?php esc_html_e( 'Max', 'booking' ); ?></label>
1806 <input type="number" id="booking_range_selection_days_max_count_dynamic" name="booking_range_selection_days_max_count_dynamic" min="1" max="1095" value="<?php echo esc_attr( $settings['booking_range_selection_days_max_count_dynamic'] ); ?>" />
1807 </div>
1808 </div>
1809 <div class="wpbc_calendar_field_row">
1810 <label for="booking_range_selection_days_specific_num_dynamic"><?php esc_html_e( 'Specific days selections', 'booking' ); ?></label>
1811 <input type="text" id="booking_range_selection_days_specific_num_dynamic" name="booking_range_selection_days_specific_num_dynamic" value="<?php echo esc_attr( $settings['booking_range_selection_days_specific_num_dynamic'] ); ?>" placeholder="<?php esc_attr_e( 'Example: 7,14,21,28', 'booking' ); ?>" />
1812 </div>
1813 <div class="wpbc_calendar_field_row">
1814 <label><?php esc_html_e( 'Start day of range', 'booking' ); ?></label>
1815 <label><input type="radio" name="booking_range_start_day_dynamic_mode" value="-1" <?php checked( '-1', $settings['booking_range_start_day_dynamic'] ); ?> /> <?php esc_html_e( 'Any day of week', 'booking' ); ?></label>
1816 <label><input type="radio" name="booking_range_start_day_dynamic_mode" value="specific" <?php checked( '-1' !== $settings['booking_range_start_day_dynamic'] ); ?> /> <?php esc_html_e( 'Specific day(s) of week', 'booking' ); ?></label>
1817 <?php wpbc_settings_calendar__render_weekday_checks( 'booking_range_start_day_dynamic_weekdays', $settings['booking_range_start_day_dynamic'] ); ?>
1818 </div>
1819 </div>
1820 </div>
1821 <?php endif; ?>
1822 <?php
1823 }
1824 );
1825
1826 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1827 array(
1828 'id' => 'wpbc_calendar_time_group',
1829 'group' => 'settings-calendar-time',
1830 'title' => __( 'Changeover and Times', 'booking' ),
1831 'open' => ( 'changeover_times' === $open_section ),
1832 ),
1833 function () use ( $settings, $is_premium_lock ) {
1834 $time_options = wpbc_settings_calendar__get_time_options( $settings['booking_range_selection_start_time'] );
1835 $time_options = array_merge( $time_options, wpbc_settings_calendar__get_time_options( $settings['booking_range_selection_end_time'] ) );
1836 ksort( $time_options );
1837 ?>
1838 <div class="wpbc_calendar_field_row">
1839 <?php
1840 wpbc_settings_calendar__render_checkbox(
1841 'booking_recurrent_time',
1842 __( 'Use selected times for each booking date', 'booking' ),
1843 __( 'Use selected times as booked time slots on each selected date.', 'booking' ),
1844 $settings
1845 );
1846 ?>
1847 </div>
1848 <?php if ( ! $is_premium_lock || wpbc_settings_calendar__is_dismissed_visible( wpbc_settings_calendar__get_premium_option_dismiss_id( 'booking_last_checkout_day_available' ) ) ) : ?>
1849 <div class="wpbc_calendar_field_row">
1850 <?php
1851 wpbc_settings_calendar__render_checkbox(
1852 'booking_last_checkout_day_available',
1853 __( 'Set check out date as available', 'booking' ),
1854 __( 'Remove the last selected day from saving to the booking.', 'booking' ),
1855 $settings,
1856 $is_premium_lock
1857 );
1858 ?>
1859 </div>
1860 <?php endif; ?>
1861 <?php if ( ! $is_premium_lock || wpbc_settings_calendar__is_dismissed_visible( wpbc_settings_calendar__get_premium_option_dismiss_id( 'booking_range_selection_time_is_active' ) ) ) : ?>
1862 <div class="wpbc_calendar_field_row">
1863 <?php
1864 wpbc_settings_calendar__render_checkbox(
1865 'booking_range_selection_time_is_active',
1866 __( 'Use changeover days', 'booking' ),
1867 __( 'Check-in/out days will be marked with vertical or diagonal lines.', 'booking' ),
1868 $settings,
1869 $is_premium_lock
1870 );
1871 ?>
1872 <?php if ( $is_premium_lock ) : ?>
1873 <?php wpbc_settings_calendar__render_changeover_upgrade_note(); ?>
1874 <?php endif; ?>
1875 </div>
1876 <?php endif; ?>
1877 <div class="wpbc_calendar_subsettings" data-wpbc-calendar-changeover-settings="1">
1878 <div class="wpbc_calendar_inline_fields">
1879 <div class="wpbc_calendar_field_row">
1880 <label for="booking_range_selection_start_time"><?php esc_html_e( 'Check-in time', 'booking' ); ?></label>
1881 <?php wpbc_settings_calendar__render_select( 'booking_range_selection_start_time', $time_options, $settings['booking_range_selection_start_time'] ); ?>
1882 </div>
1883 <div class="wpbc_calendar_field_row">
1884 <label for="booking_range_selection_end_time"><?php esc_html_e( 'Check-Out time', 'booking' ); ?></label>
1885 <?php wpbc_settings_calendar__render_select( 'booking_range_selection_end_time', $time_options, $settings['booking_range_selection_end_time'] ); ?>
1886 </div>
1887 </div>
1888 <?php if ( ! $is_premium_lock || wpbc_settings_calendar__is_dismissed_visible( wpbc_settings_calendar__get_premium_option_dismiss_id( 'booking_change_over_days_triangles' ) ) ) : ?>
1889 <div class="wpbc_calendar_field_row">
1890 <?php
1891 wpbc_settings_calendar__render_checkbox(
1892 'booking_change_over_days_triangles',
1893 __( 'Change over days as triangles', 'booking' ),
1894 '',
1895 $settings,
1896 $is_premium_lock
1897 );
1898 ?>
1899 </div>
1900 <?php endif; ?>
1901 <?php if ( ! $is_premium_lock || wpbc_settings_calendar__is_dismissed_visible( wpbc_settings_calendar__get_premium_option_dismiss_id( 'booking_change_over__is_excerpt_on_pages' ) ) ) : ?>
1902 <div class="wpbc_calendar_field_row">
1903 <?php
1904 wpbc_settings_calendar__render_checkbox(
1905 'booking_change_over__is_excerpt_on_pages',
1906 __( 'Do not use change over days on certain pages', 'booking' ),
1907 __( 'Activate exceptions for pages that should not use change over days.', 'booking' ),
1908 $settings,
1909 $is_premium_lock
1910 );
1911 ?>
1912 </div>
1913 <?php endif; ?>
1914 <div class="wpbc_calendar_field_row">
1915 <label for="booking_change_over__excerpt_on_pages"><?php esc_html_e( 'Relative URLs of pages', 'booking' ); ?></label>
1916 <textarea id="booking_change_over__excerpt_on_pages" name="booking_change_over__excerpt_on_pages" rows="4" placeholder="/page-no-change-over/"><?php echo esc_textarea( $settings['booking_change_over__excerpt_on_pages'] ); ?></textarea>
1917 </div>
1918 <div class="wpbc_calendar_field_row">
1919 <label for="booking_change_over__excerpt_bk_resources"><?php esc_html_e( 'Booking resource IDs', 'booking' ); ?></label>
1920 <textarea id="booking_change_over__excerpt_bk_resources" name="booking_change_over__excerpt_bk_resources" rows="3" placeholder="17, 21, 34"><?php echo esc_textarea( $settings['booking_change_over__excerpt_bk_resources'] ); ?></textarea>
1921 </div>
1922 </div>
1923 <?php
1924 }
1925 );
1926
1927 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1928 array(
1929 'id' => 'wpbc_calendar_legend_group',
1930 'group' => 'settings-calendar-legend',
1931 'title' => __( 'Calendar Legend', 'booking' ),
1932 'open' => ( 'legend' === $open_section ),
1933 ),
1934 function () use ( $settings ) {
1935 ?>
1936 <div class="wpbc_calendar_field_row">
1937 <?php
1938 wpbc_settings_calendar__render_checkbox(
1939 'booking_is_show_legend',
1940 __( 'Show legend below calendar', 'booking' ),
1941 __( 'Check this box to display a legend of dates below the booking calendar.', 'booking' ),
1942 $settings
1943 );
1944 ?>
1945 </div>
1946 <div class="wpbc_calendar_subsettings" data-wpbc-calendar-legend-settings="1">
1947 <div class="wpbc_calendar_legend_items_grid">
1948 <?php
1949 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
1950 wpbc_settings_calendar__render_legend_item_control( $legend_item, $legend_config, $settings );
1951 }
1952 ?>
1953 </div>
1954 <div class="wpbc_calendar_field_row">
1955 <?php
1956 wpbc_settings_calendar__render_checkbox(
1957 'booking_legend_is_show_numbers',
1958 __( 'Show date number in legend', 'booking' ),
1959 __( 'Check this box to display today date number in legend cells.', 'booking' ),
1960 $settings
1961 );
1962 ?>
1963 </div>
1964 <div class="wpbc_calendar_field_row">
1965 <?php
1966 wpbc_settings_calendar__render_checkbox(
1967 'booking_legend_is_vertical',
1968 __( 'Show legend items in a column', 'booking' ),
1969 __( 'Check this box to display legend items vertically in a column.', 'booking' ),
1970 $settings
1971 );
1972 ?>
1973 </div>
1974 </div>
1975 <?php
1976 }
1977 );
1978
1979 $settings['booking_show_timeslots_in_tooltip'] = wpbc_settings_calendar__is_timeslots_tooltip_enabled( $settings ) ? 'On' : 'Off';
1980
1981 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1982 array(
1983 'id' => 'wpbc_calendar_tooltips_group',
1984 'group' => 'settings-calendar-tooltips',
1985 'title' => __( 'Calendar Dates Tooltips', 'booking' ),
1986 'open' => ( 'tooltips' === $open_section ),
1987 ),
1988 function () use ( $settings ) {
1989 ?>
1990 <div class="wpbc_calendar_field_row">
1991 <?php
1992 wpbc_settings_calendar__render_checkbox(
1993 'booking_show_timeslots_in_tooltip',
1994 __( 'Show time slots in tooltips', 'booking' ),
1995 __( 'Show booked time slots in the tooltip when the mouse hovers over a booked day in the calendar.', 'booking' ),
1996 $settings
1997 );
1998 ?>
1999 </div>
2000 <div class="wpbc_calendar_field_row" data-wpbc-calendar-timeslot-tooltip-settings="1">
2001 <label for="booking_highlight_timeslot_word"><?php esc_html_e( 'Title of booked timeslot(s)', 'booking' ); ?></label>
2002 <input type="text" id="booking_highlight_timeslot_word" name="booking_highlight_timeslot_word" value="<?php echo esc_attr( $settings['booking_highlight_timeslot_word'] ); ?>" placeholder="<?php esc_attr_e( 'Booked Times:', 'booking' ); ?>" />
2003 <p class="wpbc_calendar_description"><?php echo wp_kses_post( sprintf( __( 'Type your %1$stitle%2$s, what will show in mouseover tooltip near booked timeslot(s)', 'booking' ), '<b>', '</b>' ) ); ?></p>
2004 </div>
2005 <?php if ( class_exists( 'wpdev_bk_biz_l' ) ) : ?>
2006 <div class="wpbc_calendar_field_row">
2007 <?php
2008 wpbc_settings_calendar__render_checkbox(
2009 'booking_is_show_availability_in_tooltips',
2010 __( 'Show availability in tooltip', 'booking' ),
2011 __( 'Check this box to display the available number of booking resources with a tooltip, when mouse hovers over each day on the calendar(s).', 'booking' ),
2012 $settings
2013 );
2014 ?>
2015 </div>
2016 <div class="wpbc_calendar_field_row" data-wpbc-calendar-availability-tooltip-settings="1">
2017 <label for="booking_highlight_availability_word"><?php esc_html_e( 'Availability Title', 'booking' ); ?></label>
2018 <input type="text" id="booking_highlight_availability_word" name="booking_highlight_availability_word" value="<?php echo esc_attr( $settings['booking_highlight_availability_word'] ); ?>" placeholder="<?php esc_attr_e( 'Available: ', 'booking' ); ?>" />
2019 <p class="wpbc_calendar_description"><?php echo wp_kses_post( sprintf( __( 'Type your %1$savailability%2$s description', 'booking' ), '<b>', '</b>' ) ); ?></p>
2020 </div>
2021 <div class="wpbc_calendar_field_row">
2022 <?php
2023 wpbc_settings_calendar__render_checkbox(
2024 'booking_is_show_availability_in_date_cell',
2025 __( 'Show availability in date cell', 'booking' ),
2026 __( 'Check this box to display the available number of booking resources at the date cells in the calendar(s).', 'booking' ),
2027 $settings
2028 );
2029 ?>
2030 </div>
2031 <div class="wpbc_calendar_field_row" data-wpbc-calendar-availability-cell-settings="1">
2032 <label for="booking_highlight_availability_word_in_date_cell"><?php esc_html_e( 'Availability Title', 'booking' ); ?></label>
2033 <input type="text" id="booking_highlight_availability_word_in_date_cell" name="booking_highlight_availability_word_in_date_cell" value="<?php echo esc_attr( $settings['booking_highlight_availability_word_in_date_cell'] ); ?>" placeholder="<?php echo esc_attr( __( 'available', 'booking' ) . ' / ' . __( 'slots', 'booking' ) . ' / ' . __( 'rooms', 'booking' ) ); ?>" />
2034 <p class="wpbc_calendar_description"><?php echo wp_kses_post( sprintf( __( 'Type your %1$savailability%2$s description', 'booking' ), '<b>', '</b>' ) ); ?></p>
2035 </div>
2036 <?php else : ?>
2037 <?php
2038 wpbc_settings_calendar__render_locked_premium_checkbox(
2039 'booking_is_show_availability_in_tooltips',
2040 __( 'Show availability in tooltip', 'booking' ),
2041 __( 'Display the available number of booking resources in the day tooltip.', 'booking' ),
2042 'Business Large+'
2043 );
2044 wpbc_settings_calendar__render_locked_premium_checkbox(
2045 'booking_is_show_availability_in_date_cell',
2046 __( 'Show availability in date cell', 'booking' ),
2047 __( 'Display the available number of booking resources directly inside calendar date cells.', 'booking' ),
2048 'Business Large+'
2049 );
2050 ?>
2051 <?php endif; ?>
2052 <?php if ( class_exists( 'wpdev_bk_biz_m' ) ) : ?>
2053 <div class="wpbc_calendar_field_row">
2054 <?php
2055 wpbc_settings_calendar__render_checkbox(
2056 'booking_is_show_cost_in_tooltips',
2057 __( 'Showing cost in tooltip', 'booking' ),
2058 __( 'Check this box to display the daily cost with a tooltip when mouse hovers over each day on the calendar(s).', 'booking' ),
2059 $settings
2060 );
2061 ?>
2062 </div>
2063 <div class="wpbc_calendar_field_row" data-wpbc-calendar-cost-tooltip-settings="1">
2064 <label for="booking_highlight_cost_word"><?php esc_html_e( 'Cost Title', 'booking' ); ?></label>
2065 <input type="text" id="booking_highlight_cost_word" name="booking_highlight_cost_word" value="<?php echo esc_attr( $settings['booking_highlight_cost_word'] ); ?>" placeholder="<?php esc_attr_e( 'Cost: ', 'booking' ); ?>" />
2066 <p class="wpbc_calendar_description"><?php echo wp_kses_post( sprintf( __( 'Type your %1$scost%2$s description', 'booking' ), '<b>', '</b>' ) ); ?></p>
2067 </div>
2068 <div class="wpbc_calendar_field_row">
2069 <?php
2070 wpbc_settings_calendar__render_checkbox(
2071 'booking_is_show_cost_in_date_cell',
2072 __( 'Showing cost in date cell', 'booking' ),
2073 sprintf( __( 'Check this box to display the %1$sdaily cost at the date cells%2$s in the calendar(s).', 'booking' ), '<b>', '</b>' ),
2074 $settings
2075 );
2076 ?>
2077 </div>
2078 <div class="wpbc_calendar_field_row" data-wpbc-calendar-cost-cell-settings="1">
2079 <label for="booking_cost_in_date_cell_currency"><?php esc_html_e( 'Currency symbol', 'booking' ); ?></label>
2080 <input type="text" id="booking_cost_in_date_cell_currency" name="booking_cost_in_date_cell_currency" value="<?php echo esc_attr( $settings['booking_cost_in_date_cell_currency'] ); ?>" placeholder="&#36;" />
2081 <p class="wpbc_calendar_description"><?php echo wp_kses_post( sprintf( __( 'Type your %1$scurrency symbol%2$s to display near daily cost in date cells.', 'booking' ), '<b>', '</b>' ) ); ?></p>
2082 </div>
2083 <div class="wpbc_calendar_field_row">
2084 <?php
2085 wpbc_settings_calendar__render_checkbox(
2086 'booking_is_show_booked_data_in_tooltips',
2087 __( 'Show booking details in tooltip', 'booking' ),
2088 __( 'Check this box to display booking details with a tooltip, when mouse hovers over each day on the usual month calendar(s).', 'booking' ),
2089 $settings
2090 );
2091 ?>
2092 </div>
2093 <div class="wpbc_calendar_field_row" data-wpbc-calendar-booked-tooltip-settings="1">
2094 <label for="booking_booked_data_in_tooltips"><?php esc_html_e( 'Booking details', 'booking' ); ?></label>
2095 <input type="text" id="booking_booked_data_in_tooltips" name="booking_booked_data_in_tooltips" value="<?php echo esc_attr( $settings['booking_booked_data_in_tooltips'] ); ?>" placeholder="[name] [secondname]" />
2096 <p class="wpbc_calendar_description"><?php esc_html_e( 'You can use the shortcodes from the bottom form of Settings Fields page.', 'booking' ); ?></p>
2097 </div>
2098 <?php else : ?>
2099 <?php
2100 wpbc_settings_calendar__render_locked_premium_checkbox(
2101 'booking_is_show_cost_in_tooltips',
2102 __( 'Showing cost in tooltip', 'booking' ),
2103 __( 'Display the daily cost in the tooltip when the mouse hovers over a calendar day.', 'booking' ),
2104 'Business Medium+'
2105 );
2106 wpbc_settings_calendar__render_locked_premium_checkbox(
2107 'booking_is_show_cost_in_date_cell',
2108 __( 'Showing cost in date cell', 'booking' ),
2109 __( 'Display the daily cost directly inside calendar date cells.', 'booking' ),
2110 'Business Medium+'
2111 );
2112 wpbc_settings_calendar__render_locked_premium_checkbox(
2113 'booking_is_show_booked_data_in_tooltips',
2114 __( 'Show booking details in tooltip', 'booking' ),
2115 __( 'Display selected booking details in the tooltip when the mouse hovers over booked days.', 'booking' ),
2116 'Business Medium+'
2117 );
2118 ?>
2119 <?php endif; ?>
2120 <?php
2121 }
2122 );
2123
2124 WPBC_UI_Sidebar_Panels::render_collapsible_group(
2125 array(
2126 'id' => 'wpbc_calendar_general_group',
2127 'group' => 'settings-calendar-general',
2128 'title' => __( 'Calendar General', 'booking' ),
2129 'open' => ( 'general' === $open_section ),
2130 ),
2131 function () use ( $settings ) {
2132 ?>
2133 <div class="wpbc_calendar_field_row">
2134 <label for="booking_max_monthes_in_calendar"><?php esc_html_e( 'Number of months to scroll', 'booking' ); ?></label>
2135 <?php wpbc_settings_calendar__render_select( 'booking_max_monthes_in_calendar', wpbc_settings_calendar__get_max_month_options(), $settings['booking_max_monthes_in_calendar'] ); ?>
2136 </div>
2137 <div class="wpbc_calendar_field_row">
2138 <label for="booking_start_day_weeek"><?php esc_html_e( 'Start Day of the week', 'booking' ); ?></label>
2139 <?php wpbc_settings_calendar__render_select( 'booking_start_day_weeek', wpbc_settings_calendar__get_weekday_options(), $settings['booking_start_day_weeek'] ); ?>
2140 </div>
2141 <div class="wpbc_calendar_field_row">
2142 <?php
2143 wpbc_settings_calendar__render_checkbox(
2144 'booking_calendar_allow_several_months_on_mobile',
2145 __( 'Allow multiple months to be shown on mobile', 'booking' ),
2146 __( 'Enable this option to allow multiple months to be shown in the calendar on mobile devices.', 'booking' ),
2147 $settings
2148 );
2149 ?>
2150 </div>
2151 <?php
2152 }
2153 );
2154 ?>
2155 </div>
2156 </form>
2157 <?php
2158 }
2159
2160 /**
2161 * Notes panel content.
2162 *
2163 * @return void
2164 */
2165 public function right_panel_notes_content() {
2166
2167 ?>
2168 <div class="wpbc_calendar_notes_panel">
2169 <?php WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Notes', 'booking' ), __( 'The preview uses the real booking calendar and applies the selected settings before saving.', 'booking' ) ); ?>
2170 <div class="wpbc_ts_hint wpbc_calendar_hint_bar">
2171 <span class="wpbc_icn_info_outline"></span>
2172 <?php esc_html_e( 'Premium options can be tested in the preview, but they are saved only when the installed edition supports them.', 'booking' ); ?>
2173 </div>
2174 </div>
2175 <?php
2176 }
2177
2178 /**
2179 * Page content.
2180 *
2181 * @return void
2182 */
2183 public function content() {
2184
2185 do_action( 'wpbc_hook_settings_page_header', 'page_settings_calendar' );
2186
2187 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_calendar__get_manage_cap() ) ) {
2188 return false;
2189 }
2190
2191 if ( function_exists( 'wpbc_js_for_bookings_page' ) ) {
2192 wpbc_js_for_bookings_page();
2193 }
2194
2195 if ( $this->is_updated ) {
2196 wpbc_show_changes_saved_message();
2197 }
2198
2199 $resource_id = wpbc_settings_calendar__get_preview_resource_id();
2200 $months_count = wpbc_settings_calendar__get_preview_months_count();
2201 $resources = wpbc_settings_calendar__get_resources();
2202 $is_free_version = ! class_exists( 'wpdev_bk_personal' );
2203 ?>
2204 <div class="wpbc_calendar_settings_page wpdevelop" data-wpbc-calendar-page="1" data-wpbc-calendar-resource-id="<?php echo esc_attr( $resource_id ); ?>">
2205 <form method="get" class="wpbc_calendar_toolbar wpbc_ts_toolbar wpbc_calendar_preview_controls" data-wpbc-calendar-preview-toolbar="1">
2206 <input type="hidden" name="page" value="wpbc-settings" />
2207 <input type="hidden" name="tab" value="calendar_settings" />
2208 <div class="wpbc_ts_control wpbc_calendar_control_resource">
2209 <label for="wpbc_calendar_resource_id"><?php esc_html_e( 'Booking resource', 'booking' ); ?></label>
2210 <?php if ( $is_free_version ) : ?>
2211 <input type="hidden" id="wpbc_calendar_resource_id" name="resource_id" value="<?php echo esc_attr( $resource_id ); ?>" />
2212 <div class="wpbc_calendar_toolbar_value">
2213 <i class="menu_icon icon-1x wpbc-bi-calendar2-day"></i>
2214 <span><?php echo esc_html( ! empty( $resources[0]['title'] ) ? $resources[0]['title'] : __( 'Default booking resource', 'booking' ) ); ?></span>
2215 </div>
2216 <?php
2217 $resource_dismiss_id = wpbc_settings_calendar__get_premium_option_dismiss_id( 'booking_resources' );
2218 if ( wpbc_settings_calendar__is_dismissed_visible( $resource_dismiss_id ) ) :
2219 ?>
2220 <div id="<?php echo esc_attr( $resource_dismiss_id ); ?>" class="wpbc_calendar_upgrade_hint">
2221 <?php wpbc_settings_calendar__render_premium_label( 'Pro', '', $resource_dismiss_id ); ?>
2222 <span><?php esc_html_e( 'The Free version has one default booking resource. To have multiple resources, please upgrade to a premium version.', 'booking' ); ?></span>
2223 </div>
2224 <?php endif; ?>
2225 <?php else : ?>
2226 <select id="wpbc_calendar_resource_id" name="resource_id">
2227 <?php foreach ( $resources as $resource ) : ?>
2228 <option value="<?php echo esc_attr( $resource['id'] ); ?>" <?php selected( $resource_id, (int) $resource['id'] ); ?>><?php echo esc_html( $resource['title'] ); ?></option>
2229 <?php endforeach; ?>
2230 </select>
2231 <?php endif; ?>
2232 </div>
2233 <div class="wpbc_ts_control wpbc_calendar_control_months">
2234 <label for="wpbc_calendar_months_count"><?php esc_html_e( 'Months', 'booking' ); ?></label>
2235 <select id="wpbc_calendar_months_count" name="months_count">
2236 <?php foreach ( array( 1, 2, 3, 4, 6, 12 ) as $month_option ) : ?>
2237 <option value="<?php echo esc_attr( $month_option ); ?>" <?php selected( $months_count, $month_option ); ?>><?php echo esc_html( $month_option ); ?></option>
2238 <?php endforeach; ?>
2239 </select>
2240 </div>
2241 </form>
2242 <?php wpbc_settings_calendar__render_calendar_preview( $resource_id, $months_count ); ?>
2243 <div class="wpbc_calendar_settings_notes" data-wpbc-calendar-notes="1">
2244 <div class="wpbc_ts_hint wpbc_calendar_hint_bar">
2245 <span class="wpbc_icn_info_outline"></span>
2246 <?php esc_html_e( 'Preview how date selection behaves before saving the calendar settings.', 'booking' ); ?>
2247 </div>
2248 </div>
2249 </div>
2250 <?php
2251
2252 do_action( 'wpbc_hook_settings_page_footer', 'page_settings_calendar' );
2253 }
2254 }
2255 add_action( 'wpbc_menu_created', array( new WPBC_Page_Settings_Calendar(), '__construct' ) );
2256