PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
11.9 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 All 205 releases
booking / includes / page-settings-calendar / settings_calendar__page.php

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

2,264 lines 103.7 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 $is_settings_preview_allowed = (
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 if ( $is_settings_preview_allowed ) {
822 return true;
823 }
824
825 return (
826 class_exists( 'WPBC_Setup_Wizard_Date_Selection' )
827 && WPBC_Setup_Wizard_Date_Selection::is_calendar_preview_request_allowed( (array) $request_params )
828 );
829 }
830
831 /**
832 * Get option overrides from Calendar Settings calendar-load AJAX request.
833 *
834 * @param array $request_params Calendar-load request params.
835 *
836 * @return array
837 */
838 function wpbc_settings_calendar__get_calendar_load_preview_options( $request_params ) {
839
840 $preview_options = array(
841 'booking_range_selection_time_is_active' => isset( $request_params['wpbc_settings_calendar_preview_changeover'] ) ? $request_params['wpbc_settings_calendar_preview_changeover'] : 'Off',
842 'booking_change_over_days_triangles' => isset( $request_params['wpbc_settings_calendar_preview_triangles'] ) ? $request_params['wpbc_settings_calendar_preview_triangles'] : 'On',
843 'booking_recurrent_time' => isset( $request_params['wpbc_settings_calendar_preview_recurrent_time'] ) ? $request_params['wpbc_settings_calendar_preview_recurrent_time'] : 'Off',
844 'booking_last_checkout_day_available' => isset( $request_params['wpbc_settings_calendar_preview_last_checkout'] ) ? $request_params['wpbc_settings_calendar_preview_last_checkout'] : 'Off',
845 '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',
846 'booking_change_over__excerpt_on_pages' => isset( $request_params['wpbc_settings_calendar_preview_excerpt_pages'] ) ? $request_params['wpbc_settings_calendar_preview_excerpt_pages'] : '',
847 'booking_change_over__excerpt_bk_resources' => isset( $request_params['wpbc_settings_calendar_preview_excerpt_resources'] ) ? $request_params['wpbc_settings_calendar_preview_excerpt_resources'] : '',
848 'booking_is_show_legend' => isset( $request_params['wpbc_settings_calendar_preview_show_legend'] ) ? $request_params['wpbc_settings_calendar_preview_show_legend'] : 'Off',
849 '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',
850 'booking_legend_is_vertical' => isset( $request_params['wpbc_settings_calendar_preview_legend_vertical'] ) ? $request_params['wpbc_settings_calendar_preview_legend_vertical'] : 'Off',
851 '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',
852 'booking_highlight_timeslot_word' => isset( $request_params['wpbc_settings_calendar_preview_timeslot_word'] ) ? $request_params['wpbc_settings_calendar_preview_timeslot_word'] : '',
853 );
854
855 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
856 $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';
857 $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 ] : '';
858 }
859
860 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
861 $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';
862 $preview_options['booking_highlight_availability_word'] = isset( $request_params['wpbc_settings_calendar_preview_availability_word'] ) ? $request_params['wpbc_settings_calendar_preview_availability_word'] : '';
863 $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';
864 $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'] : '';
865 }
866
867 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
868 $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';
869 $preview_options['booking_highlight_cost_word'] = isset( $request_params['wpbc_settings_calendar_preview_cost_word'] ) ? $request_params['wpbc_settings_calendar_preview_cost_word'] : '';
870 $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';
871 $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'] : '';
872 $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';
873 $preview_options['booking_booked_data_in_tooltips'] = isset( $request_params['wpbc_settings_calendar_preview_booked_details'] ) ? $request_params['wpbc_settings_calendar_preview_booked_details'] : '';
874 }
875
876 return $preview_options;
877 }
878
879 /**
880 * Get request overrides for the calendar-load AJAX generated inside Calendar Settings preview.
881 *
882 * @param array $current_settings Current preview settings.
883 *
884 * @return array
885 */
886 function wpbc_settings_calendar__get_calendar_load_preview_request_overrides( $current_settings ) {
887
888 $request_overrides = array(
889 'wpbc_settings_calendar_preview' => 1,
890 'wpbc_settings_calendar_preview_changeover' => ( 'On' === (string) $current_settings['booking_range_selection_time_is_active'] ) ? 'On' : 'Off',
891 'wpbc_settings_calendar_preview_triangles' => ( 'Off' === (string) $current_settings['booking_change_over_days_triangles'] ) ? 'Off' : 'On',
892 'wpbc_settings_calendar_preview_recurrent_time' => ( 'On' === (string) $current_settings['booking_recurrent_time'] ) ? 'On' : 'Off',
893 'wpbc_settings_calendar_preview_last_checkout' => ( 'On' === (string) $current_settings['booking_last_checkout_day_available'] ) ? 'On' : 'Off',
894 'wpbc_settings_calendar_preview_excerpt_on_pages' => ( 'On' === (string) $current_settings['booking_change_over__is_excerpt_on_pages'] ) ? 'On' : 'Off',
895 'wpbc_settings_calendar_preview_excerpt_pages' => (string) $current_settings['booking_change_over__excerpt_on_pages'],
896 'wpbc_settings_calendar_preview_excerpt_resources' => (string) $current_settings['booking_change_over__excerpt_bk_resources'],
897 'wpbc_settings_calendar_preview_show_legend' => ( 'On' === (string) $current_settings['booking_is_show_legend'] ) ? 'On' : 'Off',
898 'wpbc_settings_calendar_preview_legend_show_numbers' => ( 'On' === (string) $current_settings['booking_legend_is_show_numbers'] ) ? 'On' : 'Off',
899 'wpbc_settings_calendar_preview_legend_vertical' => ( 'On' === (string) $current_settings['booking_legend_is_vertical'] ) ? 'On' : 'Off',
900 'wpbc_settings_calendar_preview_disable_timeslots_tooltip' => ( 'On' === (string) $current_settings['booking_disable_timeslots_in_tooltip'] ) ? 'On' : 'Off',
901 'wpbc_settings_calendar_preview_timeslot_word' => (string) $current_settings['booking_highlight_timeslot_word'],
902 );
903
904 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
905 $is_show_key = 'booking_legend_is_show_item_' . $legend_item;
906 $text_key = 'booking_legend_text_for_item_' . $legend_item;
907 if ( isset( $current_settings[ $is_show_key ] ) ) {
908 $request_overrides[ 'wpbc_settings_calendar_preview_legend_show_' . $legend_item ] = ( 'On' === (string) $current_settings[ $is_show_key ] ) ? 'On' : 'Off';
909 }
910 if ( isset( $current_settings[ $text_key ] ) ) {
911 $request_overrides[ 'wpbc_settings_calendar_preview_legend_text_' . $legend_item ] = (string) $current_settings[ $text_key ];
912 }
913 }
914
915 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
916 $request_overrides['wpbc_settings_calendar_preview_show_availability_tooltip'] = ( 'On' === (string) $current_settings['booking_is_show_availability_in_tooltips'] ) ? 'On' : 'Off';
917 $request_overrides['wpbc_settings_calendar_preview_availability_word'] = (string) $current_settings['booking_highlight_availability_word'];
918 $request_overrides['wpbc_settings_calendar_preview_show_availability_cell'] = ( 'On' === (string) $current_settings['booking_is_show_availability_in_date_cell'] ) ? 'On' : 'Off';
919 $request_overrides['wpbc_settings_calendar_preview_availability_cell_word'] = (string) $current_settings['booking_highlight_availability_word_in_date_cell'];
920 }
921
922 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
923 $request_overrides['wpbc_settings_calendar_preview_show_cost_tooltip'] = ( 'On' === (string) $current_settings['booking_is_show_cost_in_tooltips'] ) ? 'On' : 'Off';
924 $request_overrides['wpbc_settings_calendar_preview_cost_word'] = (string) $current_settings['booking_highlight_cost_word'];
925 $request_overrides['wpbc_settings_calendar_preview_show_cost_cell'] = ( 'On' === (string) $current_settings['booking_is_show_cost_in_date_cell'] ) ? 'On' : 'Off';
926 $request_overrides['wpbc_settings_calendar_preview_cost_currency'] = (string) $current_settings['booking_cost_in_date_cell_currency'];
927 $request_overrides['wpbc_settings_calendar_preview_show_booked_details'] = ( 'On' === (string) $current_settings['booking_is_show_booked_data_in_tooltips'] ) ? 'On' : 'Off';
928 $request_overrides['wpbc_settings_calendar_preview_booked_details'] = (string) $current_settings['booking_booked_data_in_tooltips'];
929 }
930
931 return $request_overrides;
932 }
933
934 /**
935 * Check change-over state while Calendar Settings preview option overrides are active.
936 *
937 * @param int|string $resource_id Booking resource ID.
938 * @param string|false $request_uri Request URI or false for current URI.
939 *
940 * @return bool|null Boolean when preview context is active, null otherwise.
941 */
942 function wpbc_settings_calendar__preview_is_changeover_enabled( $resource_id = 0, $request_uri = false ) {
943
944 global $wpbc_settings_calendar__preview_options;
945
946 if ( ! is_array( $wpbc_settings_calendar__preview_options ) ) {
947 return null;
948 }
949
950 if (
951 ! isset( $wpbc_settings_calendar__preview_options['booking_range_selection_time_is_active'] )
952 || 'On' !== (string) $wpbc_settings_calendar__preview_options['booking_range_selection_time_is_active']
953 ) {
954 return false;
955 }
956
957 if ( function_exists( 'wpbc_is_booking_used_check_in_out_time' ) ) {
958 return wpbc_is_booking_used_check_in_out_time( $request_uri, $resource_id );
959 }
960
961 return true;
962 }
963
964 /**
965 * Validate page data.
966 *
967 * @param array $post_data Raw post data.
968 *
969 * @return array
970 */
971 function wpbc_settings_calendar__validate_data( $post_data, $is_preview = false ) {
972
973 $current = wpbc_settings_calendar__get_settings_response();
974 $max_months = wpbc_settings_calendar__get_max_month_options();
975 $weekdays = wpbc_settings_calendar__get_weekday_options();
976 $range_supported = wpbc_settings_calendar__is_range_supported();
977 $cleaned = array();
978
979 $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'];
980 $cleaned['booking_max_monthes_in_calendar'] = isset( $max_months[ $max_monthes ] ) ? $max_monthes : '1y';
981
982 $start_day = isset( $post_data['booking_start_day_weeek'] ) ? sanitize_key( wp_unslash( $post_data['booking_start_day_weeek'] ) ) : $current['booking_start_day_weeek'];
983 $cleaned['booking_start_day_weeek'] = array_key_exists( $start_day, $weekdays ) ? $start_day : '0';
984
985 $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';
986
987 $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'];
988 if ( ! in_array( $day_mode, array( 'single', 'multiple', 'range' ), true ) ) {
989 $day_mode = 'multiple';
990 }
991 $cleaned['booking_type_of_day_selections'] = $day_mode;
992
993 $range_type = isset( $post_data['booking_range_selection_type'] ) ? sanitize_key( wp_unslash( $post_data['booking_range_selection_type'] ) ) : $current['booking_range_selection_type'];
994 $cleaned['booking_range_selection_type'] = in_array( $range_type, array( 'fixed', 'dynamic' ), true ) ? $range_type : 'dynamic';
995
996 $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'] );
997 $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'] ) ) );
998 $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'] ) ) );
999 if ( (int) $cleaned['booking_range_selection_days_max_count_dynamic'] < (int) $cleaned['booking_range_selection_days_count_dynamic'] ) {
1000 $cleaned['booking_range_selection_days_max_count_dynamic'] = $cleaned['booking_range_selection_days_count_dynamic'];
1001 }
1002
1003 $cleaned['booking_range_selection_days_specific_num_dynamic'] = isset( $post_data['booking_range_selection_days_specific_num_dynamic'] )
1004 ? preg_replace( '/[^0-9,\-\s]/', '', sanitize_text_field( wp_unslash( $post_data['booking_range_selection_days_specific_num_dynamic'] ) ) )
1005 : $current['booking_range_selection_days_specific_num_dynamic'];
1006
1007 $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' );
1008 $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' );
1009 $cleaned['booking_range_start_day'] = ( '-1' === $fixed_start_mode )
1010 ? '-1'
1011 : 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'] );
1012 $cleaned['booking_range_start_day_dynamic'] = ( '-1' === $dynamic_start_mode )
1013 ? '-1'
1014 : 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'] );
1015
1016 $cleaned['booking_recurrent_time'] = ( isset( $post_data['booking_recurrent_time'] ) && 'On' === wp_unslash( $post_data['booking_recurrent_time'] ) ) ? 'On' : 'Off';
1017 $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';
1018 $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';
1019 $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';
1020 $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';
1021
1022 foreach ( array( 'booking_range_selection_start_time', 'booking_range_selection_end_time' ) as $time_key ) {
1023 $time_value = isset( $post_data[ $time_key ] ) ? sanitize_text_field( wp_unslash( $post_data[ $time_key ] ) ) : $current[ $time_key ];
1024 $cleaned[ $time_key ] = preg_match( '/^\d{2}:\d{2}$/', $time_value ) ? $time_value : $current[ $time_key ];
1025 }
1026
1027 $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'];
1028 $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'];
1029
1030 $cleaned['booking_is_show_legend'] = ( isset( $post_data['booking_is_show_legend'] ) && 'On' === wp_unslash( $post_data['booking_is_show_legend'] ) ) ? 'On' : 'Off';
1031 $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';
1032 $cleaned['booking_legend_is_vertical'] = ( isset( $post_data['booking_legend_is_vertical'] ) && 'On' === wp_unslash( $post_data['booking_legend_is_vertical'] ) ) ? 'On' : 'Off';
1033 if ( isset( $post_data['booking_show_timeslots_in_tooltip'] ) ) {
1034 $cleaned['booking_disable_timeslots_in_tooltip'] = ( 'On' === wp_unslash( $post_data['booking_show_timeslots_in_tooltip'] ) ) ? 'Off' : 'On';
1035 } else {
1036 $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';
1037 }
1038 $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'];
1039
1040 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
1041 $is_show_key = 'booking_legend_is_show_item_' . $legend_item;
1042 $text_key = 'booking_legend_text_for_item_' . $legend_item;
1043 $cleaned[ $is_show_key ] = ( isset( $post_data[ $is_show_key ] ) && 'On' === wp_unslash( $post_data[ $is_show_key ] ) ) ? 'On' : 'Off';
1044 $cleaned[ $text_key ] = isset( $post_data[ $text_key ] ) ? sanitize_text_field( wp_unslash( $post_data[ $text_key ] ) ) : $current[ $text_key ];
1045 }
1046
1047 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
1048 $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';
1049 $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'];
1050 $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';
1051 $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'];
1052 }
1053
1054 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
1055 $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';
1056 $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'];
1057 $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';
1058 $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'];
1059 $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';
1060 $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'];
1061 }
1062
1063 if ( ! $is_preview && ! $range_supported ) {
1064 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 ) {
1065 $cleaned[ $premium_key ] = $current[ $premium_key ];
1066 }
1067 }
1068
1069 return $cleaned;
1070 }
1071
1072 /**
1073 * Update settings.
1074 *
1075 * @param array $cleaned_data Cleaned data.
1076 *
1077 * @return void
1078 */
1079 function wpbc_settings_calendar__update_settings( $cleaned_data ) {
1080
1081 $range_supported = wpbc_settings_calendar__is_range_supported();
1082 $free_keys = array(
1083 'booking_max_monthes_in_calendar',
1084 'booking_start_day_weeek',
1085 'booking_calendar_allow_several_months_on_mobile',
1086 'booking_type_of_day_selections',
1087 'booking_recurrent_time',
1088 'booking_is_show_legend',
1089 'booking_legend_is_show_numbers',
1090 'booking_legend_is_vertical',
1091 'booking_disable_timeslots_in_tooltip',
1092 'booking_highlight_timeslot_word',
1093 );
1094 $premium_keys = array(
1095 'booking_range_selection_type',
1096 'booking_range_selection_days_count',
1097 'booking_range_start_day',
1098 'booking_range_selection_days_count_dynamic',
1099 'booking_range_selection_days_max_count_dynamic',
1100 'booking_range_selection_days_specific_num_dynamic',
1101 'booking_range_start_day_dynamic',
1102 'booking_last_checkout_day_available',
1103 'booking_range_selection_time_is_active',
1104 'booking_range_selection_start_time',
1105 'booking_range_selection_end_time',
1106 'booking_change_over_days_triangles',
1107 'booking_change_over__is_excerpt_on_pages',
1108 'booking_change_over__excerpt_on_pages',
1109 'booking_change_over__excerpt_bk_resources',
1110 );
1111 $availability_tooltip_keys = array(
1112 'booking_is_show_availability_in_tooltips',
1113 'booking_highlight_availability_word',
1114 'booking_is_show_availability_in_date_cell',
1115 'booking_highlight_availability_word_in_date_cell',
1116 );
1117 $cost_tooltip_keys = array(
1118 'booking_is_show_cost_in_tooltips',
1119 'booking_highlight_cost_word',
1120 'booking_is_show_cost_in_date_cell',
1121 'booking_cost_in_date_cell_currency',
1122 'booking_is_show_booked_data_in_tooltips',
1123 'booking_booked_data_in_tooltips',
1124 );
1125 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
1126 $free_keys[] = 'booking_legend_is_show_item_' . $legend_item;
1127 $free_keys[] = 'booking_legend_text_for_item_' . $legend_item;
1128 }
1129
1130 $previous_day_mode = (string) get_bk_option( 'booking_type_of_day_selections' );
1131 foreach ( $free_keys as $key ) {
1132 update_bk_option( $key, $cleaned_data[ $key ] );
1133 }
1134
1135 // Keep a newly selected Free range upgrade-safe: Business Small+ must continue with the same two-click subtype.
1136 if ( ! $range_supported && 'range' === $cleaned_data['booking_type_of_day_selections'] && 'range' !== $previous_day_mode ) {
1137 update_bk_option( 'booking_range_selection_type', 'dynamic' );
1138 }
1139
1140 if ( $range_supported ) {
1141 foreach ( $premium_keys as $key ) {
1142 update_bk_option( $key, $cleaned_data[ $key ] );
1143 }
1144 }
1145
1146 if ( class_exists( 'wpdev_bk_biz_l' ) ) {
1147 foreach ( $availability_tooltip_keys as $key ) {
1148 update_bk_option( $key, $cleaned_data[ $key ] );
1149 }
1150 }
1151
1152 if ( class_exists( 'wpdev_bk_biz_m' ) ) {
1153 foreach ( $cost_tooltip_keys as $key ) {
1154 update_bk_option( $key, $cleaned_data[ $key ] );
1155 }
1156 }
1157 }
1158
1159 /**
1160 * Render select element.
1161 *
1162 * @param string $name Name.
1163 * @param array $options Options.
1164 * @param string $selected Selected value.
1165 * @param array $args Arguments.
1166 *
1167 * @return void
1168 */
1169 function wpbc_settings_calendar__render_select( $name, $options, $selected, $args = array() ) {
1170
1171 $id = isset( $args['id'] ) ? $args['id'] : $name;
1172 $class = isset( $args['class'] ) ? $args['class'] : '';
1173 ?>
1174 <select id="<?php echo esc_attr( $id ); ?>" name="<?php echo esc_attr( $name ); ?>" class="<?php echo esc_attr( $class ); ?>">
1175 <?php foreach ( $options as $value => $label ) : ?>
1176 <option value="<?php echo esc_attr( $value ); ?>" <?php selected( (string) $selected, (string) $value ); ?>><?php echo esc_html( $label ); ?></option>
1177 <?php endforeach; ?>
1178 </select>
1179 <?php
1180 }
1181
1182 /**
1183 * Get premium feature URL by required version label.
1184 *
1185 * @param string $label Premium label.
1186 * @param string $url Optional explicit URL.
1187 *
1188 * @return string
1189 */
1190 function wpbc_settings_calendar__get_premium_url( $label = 'Pro', $url = '' ) {
1191
1192 $generic_features_url = 'https://wpbookingcalendar.com/features/';
1193 $url = trim( (string) $url );
1194
1195 if ( ( '' !== $url ) && ( $generic_features_url !== $url ) ) {
1196 return $url;
1197 }
1198
1199 $label = strtolower( (string) $label );
1200
1201 if ( false !== strpos( $label, 'multiuser' ) ) {
1202 return 'https://wpbookingcalendar.com/features/#multiuser';
1203 }
1204 if ( false !== strpos( $label, 'business large' ) || false !== strpos( $label, 'bl+' ) ) {
1205 return 'https://wpbookingcalendar.com/features/#bl';
1206 }
1207 if ( false !== strpos( $label, 'business medium' ) || false !== strpos( $label, 'bm+' ) ) {
1208 return 'https://wpbookingcalendar.com/features/#bm';
1209 }
1210 if ( false !== strpos( $label, 'business small' ) || false !== strpos( $label, 'bs+' ) ) {
1211 return 'https://wpbookingcalendar.com/features/#bs';
1212 }
1213
1214 return $generic_features_url;
1215 }
1216
1217 /**
1218 * Render premium label.
1219 *
1220 * @return void
1221 */
1222 function wpbc_settings_calendar__render_premium_label( $label = 'Business Small+', $url = 'https://wpbookingcalendar.com/features/', $dismiss_id = '' ) {
1223
1224 $url = wpbc_settings_calendar__get_premium_url( $label, $url );
1225 ?>
1226 <a class="wpbc_pro_label wpbc_calendar_pro_label" href="<?php echo esc_url( $url ); ?>" target="_blank"><?php echo esc_html( $label ); ?></a>
1227 <?php if ( '' !== $dismiss_id ) : ?>
1228 <?php wpbc_settings_calendar__render_dismiss_button( $dismiss_id ); ?>
1229 <?php endif; ?>
1230 <?php
1231 }
1232
1233 /**
1234 * Check if a Calendar Settings upsell row is visible for current user.
1235 *
1236 * @param string $dismiss_id Dismiss ID.
1237 *
1238 * @return bool
1239 */
1240 function wpbc_settings_calendar__is_dismissed_visible( $dismiss_id ) {
1241
1242 if ( wpbc_is_this_demo() ) {
1243 return true;
1244 }
1245
1246 return ! function_exists( 'wpbc_is_dismissed_panel_visible' ) || wpbc_is_dismissed_panel_visible( $dismiss_id );
1247 }
1248
1249 /**
1250 * Get dismiss ID for a Calendar Settings premium option.
1251 *
1252 * @param string $option_name Option name.
1253 *
1254 * @return string
1255 */
1256 function wpbc_settings_calendar__get_premium_option_dismiss_id( $option_name ) {
1257
1258 return 'wpbc_is_dismissed__calendar_settings__' . sanitize_key( $option_name );
1259 }
1260
1261 /**
1262 * Render small dismiss button for Calendar Settings premium hints.
1263 *
1264 * @param string $dismiss_id Dismiss ID.
1265 *
1266 * @return void
1267 */
1268 function wpbc_settings_calendar__render_dismiss_button( $dismiss_id ) {
1269
1270 if ( wpbc_is_this_demo() || ! function_exists( 'wpbc_is_dismissed' ) ) {
1271 return;
1272 }
1273
1274 ?>
1275 <span class="wpbc_calendar_premium_dismiss">
1276 <?php
1277 wpbc_is_dismissed(
1278 $dismiss_id,
1279 array(
1280 'title' => '&times;',
1281 'hint' => __( 'Hide this option', 'booking' ),
1282 'css' => 'float:none;margin-left:4px;',
1283 )
1284 );
1285 ?>
1286 </span>
1287 <?php
1288 }
1289
1290 /**
1291 * Render the Business Small+ explanation for advanced range controls.
1292 *
1293 * @return void
1294 */
1295 function wpbc_settings_calendar__render_range_upgrade_note() {
1296
1297 ?>
1298 <div class="wpbc_calendar_premium_note" data-wpbc-calendar-range-upgrade-note="1">
1299 <div>
1300 <strong><?php esc_html_e( 'Advanced range selection rules', 'booking' ); ?></strong>
1301 <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>
1302 </div>
1303 <div class="wpbc_calendar_premium_note_actions">
1304 <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>
1305 <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>
1306 </div>
1307 </div>
1308 <?php
1309 }
1310
1311 /**
1312 * Render Business Small+ explanation for locked changeover controls.
1313 *
1314 * @return void
1315 */
1316 function wpbc_settings_calendar__render_changeover_upgrade_note() {
1317
1318 ?>
1319 <div class="wpbc_calendar_premium_note" data-wpbc-calendar-changeover-upgrade-note="1">
1320 <div>
1321 <strong><?php esc_html_e( 'Changeover days', 'booking' ); ?></strong>
1322 <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>
1323 </div>
1324 <div class="wpbc_calendar_premium_note_actions">
1325 <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>
1326 <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>
1327 </div>
1328 </div>
1329 <?php
1330 }
1331
1332 /**
1333 * Render disabled premium-only toggle row.
1334 *
1335 * @param string $name Option name.
1336 * @param string $label Label.
1337 * @param string $description Description.
1338 * @param string $premium_label Premium label.
1339 *
1340 * @return void
1341 */
1342 function wpbc_settings_calendar__render_locked_premium_checkbox( $name, $label, $description, $premium_label ) {
1343
1344 $dismiss_id = wpbc_settings_calendar__get_premium_option_dismiss_id( $name );
1345 if ( ! wpbc_settings_calendar__is_dismissed_visible( $dismiss_id ) ) {
1346 return;
1347 }
1348 ?>
1349 <div id="<?php echo esc_attr( $dismiss_id ); ?>" class="wpbc_calendar_field_row wpbc_calendar_locked_premium_field">
1350 <label class="wpbc_calendar_switch wpbc_calendar_switch_card is-premium" aria-disabled="true">
1351 <input type="checkbox" name="<?php echo esc_attr( $name ); ?>" value="On" disabled="disabled" data-wpbc-calendar-premium="1" />
1352 <span class="wpbc_calendar_switch_control" aria-hidden="true"><span class="wpbc_calendar_switch_knob"></span></span>
1353 <span class="wpbc_calendar_switch_label"><?php echo esc_html( $label ); ?></span>
1354 <?php wpbc_settings_calendar__render_premium_label( $premium_label, '', $dismiss_id ); ?>
1355 </label>
1356 <?php if ( '' !== $description ) : ?>
1357 <p class="wpbc_calendar_description"><?php echo wp_kses_post( $description ); ?></p>
1358 <?php endif; ?>
1359 </div>
1360 <?php
1361 }
1362
1363 /**
1364 * Render checkbox field.
1365 *
1366 * @param string $name Option name.
1367 * @param string $label Label.
1368 * @param string $description Description.
1369 * @param array $settings Settings.
1370 * @param bool $is_premium Whether field is premium.
1371 *
1372 * @return bool
1373 */
1374 function wpbc_settings_calendar__render_checkbox( $name, $label, $description, $settings, $is_premium = false ) {
1375
1376 $premium_attr = $is_premium ? 'data-wpbc-calendar-premium="1"' : '';
1377 $dismiss_id = $is_premium ? wpbc_settings_calendar__get_premium_option_dismiss_id( $name ) : '';
1378 if ( $is_premium && ! wpbc_settings_calendar__is_dismissed_visible( $dismiss_id ) ) {
1379 return false;
1380 }
1381 if ( $is_premium && 'booking_range_selection_time_is_active' === $name ) {
1382 $premium_attr .= ' data-wpbc-calendar-premium-changeover-info="1"';
1383 }
1384 ?>
1385 <label class="wpbc_calendar_switch wpbc_calendar_switch_card <?php echo $is_premium ? 'is-premium' : ''; ?>">
1386 <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 ?> />
1387 <span class="wpbc_calendar_switch_control" aria-hidden="true"><span class="wpbc_calendar_switch_knob"></span></span>
1388 <span class="wpbc_calendar_switch_label"><?php echo esc_html( $label ); ?></span>
1389 <?php if ( $is_premium ) : ?>
1390 <?php wpbc_settings_calendar__render_premium_label( 'Business Small+', '', $dismiss_id ); ?>
1391 <?php endif; ?>
1392 </label>
1393 <?php if ( '' !== $description ) : ?>
1394 <p class="wpbc_calendar_description"><?php echo wp_kses_post( $description ); ?></p>
1395 <?php endif; ?>
1396 <?php
1397 return true;
1398 }
1399
1400 /**
1401 * Render legend item toggle with title field.
1402 *
1403 * @param string $legend_item Legend item key.
1404 * @param array $config Legend item config.
1405 * @param array $settings Settings.
1406 *
1407 * @return void
1408 */
1409 function wpbc_settings_calendar__render_legend_item_control( $legend_item, $config, $settings ) {
1410
1411 $is_show_key = 'booking_legend_is_show_item_' . $legend_item;
1412 $text_key = 'booking_legend_text_for_item_' . $legend_item;
1413 ?>
1414 <div class="wpbc_calendar_legend_item_tile" data-wpbc-calendar-legend-item="<?php echo esc_attr( $legend_item ); ?>">
1415 <div class="wpbc_calendar_legend_item_header">
1416 <label class="wpbc_calendar_switch">
1417 <input type="checkbox" name="<?php echo esc_attr( $is_show_key ); ?>" value="On" <?php checked( 'On', $settings[ $is_show_key ] ); ?> />
1418 <span class="wpbc_calendar_switch_control" aria-hidden="true"><span class="wpbc_calendar_switch_knob"></span></span>
1419 <span class="wpbc_calendar_switch_label"><?php echo esc_html( $config['label'] ); ?></span>
1420 </label>
1421 </div>
1422 <div class="wpbc_calendar_legend_item_title">
1423 <label for="<?php echo esc_attr( $text_key ); ?>"><?php esc_html_e( 'Title', 'booking' ); ?></label>
1424 <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'] ); ?>" />
1425 </div>
1426 <p class="wpbc_calendar_description"><?php echo wp_kses_post( $config['description'] ); ?></p>
1427 <?php if ( ! empty( $config['note'] ) ) : ?>
1428 <p class="wpbc_calendar_description"><strong><?php esc_html_e( 'Note', 'booking' ); ?>:</strong> <?php echo esc_html( $config['note'] ); ?></p>
1429 <?php endif; ?>
1430 </div>
1431 <?php
1432 }
1433
1434 /**
1435 * Render week-day checkbox row.
1436 *
1437 * @param string $name Field name.
1438 * @param string $value Current CSV value.
1439 *
1440 * @return void
1441 */
1442 function wpbc_settings_calendar__render_weekday_checks( $name, $value ) {
1443
1444 $selected = ( '-1' === $value || '' === $value ) ? array() : explode( ',', $value );
1445 ?>
1446 <div class="wpbc_calendar_weekday_checks" data-wpbc-calendar-weekday-checks="<?php echo esc_attr( $name ); ?>">
1447 <?php foreach ( wpbc_settings_calendar__get_weekday_options() as $day_value => $day_label ) : ?>
1448 <label>
1449 <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 ) ); ?> />
1450 <span><?php echo esc_html( $day_label ); ?></span>
1451 </label>
1452 <?php endforeach; ?>
1453 </div>
1454 <?php
1455 }
1456
1457 /**
1458 * Render calendar preview.
1459 *
1460 * @param int $resource_id Resource ID.
1461 * @param int $months_count Number of months.
1462 * @param array $preview_settings Optional settings.
1463 *
1464 * @return void
1465 */
1466 function wpbc_settings_calendar__render_calendar_preview( $resource_id, $months_count, $preview_settings = array() ) {
1467
1468 $resource_id = wpbc_settings_calendar__sanitize_preview_resource_id( $resource_id );
1469 $months_count = wpbc_settings_calendar__sanitize_preview_months_count( $months_count );
1470 $current_settings = wp_parse_args( $preview_settings, wpbc_settings_calendar__get_settings_response() );
1471 $is_change_over_preview = ( 'On' === (string) $current_settings['booking_range_selection_time_is_active'] );
1472 $is_triangle_preview = ( 'Off' !== (string) $current_settings['booking_change_over_days_triangles'] );
1473 $preview_css_classes = 'wpbc_calendar_settings_preview';
1474 if ( $is_change_over_preview && $is_triangle_preview ) {
1475 $preview_css_classes .= ' wpbc_change_over_triangle';
1476 }
1477 $previous_preview_options = wpbc_settings_calendar__preview_options_push( $current_settings );
1478 ?>
1479 <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 ); ?>">
1480 <div class="wpbc_calendar_settings_real_preview" data-wpbc-calendar-panel="1">
1481 <?php
1482 if ( class_exists( 'WPBC_FE_Render' ) ) {
1483 WPBC_FE_Render::render_calendar_only(
1484 array(
1485 'resource_id' => $resource_id,
1486 'cal_count' => $months_count,
1487 'is_echo' => 1,
1488 'calendar_request_overrides' => wpbc_settings_calendar__get_calendar_load_preview_request_overrides( $current_settings ),
1489 )
1490 );
1491 } elseif ( function_exists( 'wpbc__calendar__load' ) ) {
1492 $start_script_code = wpbc__calendar__load(
1493 array(
1494 'resource_id' => $resource_id,
1495 'aggregate_resource_id_arr' => array(),
1496 'selected_dates_without_calendar' => '',
1497 'calendar_number_of_months' => $months_count,
1498 'start_month_calendar' => false,
1499 'shortcode_options' => '',
1500 'custom_form' => 'standard',
1501 'skip_general_availability' => 1,
1502 'calendar_request_overrides' => wpbc_settings_calendar__get_calendar_load_preview_request_overrides( $current_settings ),
1503 )
1504 );
1505 if ( function_exists( 'wpbc_pre_get_calendar_html' ) ) {
1506 echo '<div style="clear:both;height:10px;"></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1507 echo wpbc_pre_get_calendar_html( $resource_id, $months_count, '' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1508 echo ' ' . $start_script_code; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1509 } else {
1510 echo $start_script_code; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1511 }
1512 }
1513 ?>
1514 </div>
1515 </div>
1516 <?php
1517
1518 wpbc_settings_calendar__preview_options_pop( $previous_preview_options );
1519 }
1520
1521 /**
1522 * Show Calendar save button in top toolbar.
1523 *
1524 * @param string $page_tag Current page tag.
1525 * @param string $active_page_tab Current tab.
1526 * @param string $active_page_subtab Current subtab.
1527 *
1528 * @return void
1529 */
1530 function wpbc_settings_calendar__top_toolbar__show_save_button( $page_tag, $active_page_tab, $active_page_subtab ) {
1531
1532 if ( ( 'wpbc-settings' !== $page_tag ) || ( 'calendar_settings' !== $active_page_tab ) ) {
1533 return;
1534 }
1535
1536 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_calendar__get_manage_cap() ) ) {
1537 return;
1538 }
1539 ?>
1540 <div class="wpbc_ui_el__buttons_group wpbc_calendar__top_toolbar_group">
1541 <a href="javascript:void(0);"
1542 class="button button-primary wpbc_calendar__top_btn_save"
1543 data-wpbc-calendar-save="1"
1544 data-wpbc-u-busy-text="<?php esc_attr_e( 'Saving', 'booking' ); ?>...">
1545 <i class="menu_icon icon-1x wpbc-bi-check2-circle"></i>
1546 <span class="in-button-text">&nbsp;&nbsp;<?php esc_html_e( 'Save Changes', 'booking' ); ?></span>
1547 </a>
1548 </div>
1549 <?php
1550 }
1551 add_action( 'wpbc_ui_el__top_nav__content_end', 'wpbc_settings_calendar__top_toolbar__show_save_button', 20, 3 );
1552
1553 /**
1554 * Block direct access for regular users in MultiUser context.
1555 *
1556 * @param bool $is_show_this_page Whether to show page.
1557 * @param string $page_tag Current page.
1558 * @param string $active_page_tab Active tab.
1559 * @param string $active_page_subtab Active subtab.
1560 *
1561 * @return bool
1562 */
1563 function wpbc_settings_calendar__check_showing_page( $is_show_this_page, $page_tag, $active_page_tab, $active_page_subtab ) {
1564
1565 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() ) ) ) {
1566 return false;
1567 }
1568
1569 return $is_show_this_page;
1570 }
1571 add_filter( 'wpbc_before_showing_settings_page_is_show_page', 'wpbc_settings_calendar__check_showing_page', 20, 4 );
1572
1573 /**
1574 * Calendar settings tab.
1575 */
1576 class WPBC_Page_Settings_Calendar extends WPBC_Page_Structure {
1577
1578 /**
1579 * Whether settings were saved during this request.
1580 *
1581 * @var bool
1582 */
1583 private $is_updated = false;
1584
1585 /**
1586 * Menu slug.
1587 *
1588 * @return string
1589 */
1590 public function in_page() {
1591
1592 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_calendar__get_manage_cap() ) ) {
1593 return (string) wp_rand( 100000, 1000000 );
1594 }
1595
1596 return 'wpbc-settings';
1597 }
1598
1599 /**
1600 * Register tab.
1601 *
1602 * @return array
1603 */
1604 public function tabs() {
1605
1606 $subtabs = array();
1607 $subtab_default = array(
1608 'type' => 'subtab',
1609 'title' => '',
1610 'page_title' => __( 'Calendar Settings', 'booking' ),
1611 'hint' => '',
1612 'link' => '',
1613 'css_classes' => '',
1614 'font_icon' => 'wpbc-bi-calendar2-range',
1615 'font_icon_right' => 'wpbc-bi-question-circle',
1616 'default' => false,
1617 'content' => 'content',
1618 );
1619
1620 foreach ( wpbc_settings_calendar__get_section_navigation_items() as $section_key => $section ) {
1621 $subtabs[ $section['menu_slug'] ] = array_merge(
1622 $subtab_default,
1623 array(
1624 'title' => $section['title'],
1625 'hint' => $section['hint'],
1626 'font_icon' => $section['font_icon'],
1627 'link' => wpbc_settings_calendar__get_section_url( $section_key ),
1628 'default' => ( 'days_selection' === $section_key ),
1629 )
1630 );
1631 }
1632
1633 return array(
1634 'calendar_settings' => array(
1635 'is_show_top_path' => true,
1636 'right_vertical_sidebar__is_show' => true,
1637 'right_vertical_sidebar__default_view_mode' => '',
1638 'right_vertical_sidebar_compact__is_show' => true,
1639 'left_navigation__default_view_mode' => '', // FixIn:11.7.1.1: 'compact',
1640 'top_path_title' => __( 'Calendar', 'booking' ),
1641 'title' => __( 'Calendar', 'booking' ), // . '<span class="wpbc_new_label" style="margin-left: auto;">' . esc_html__( 'New', 'booking' ) . '</span>&nbsp;&nbsp;',
1642 'hint' => __( 'Preview and configure date selection, range selection, and change-over behavior.', 'booking' ),
1643 'page_title' => __( 'Calendar Settings', 'booking' ),
1644 'link' => '',
1645 'position' => '',
1646 'css_classes' => 'wpbc_top_tab__calendar_settings',
1647 'icon' => '',
1648 'font_icon' => 'wpbc-bi-calendar2-range',
1649 'font_icon_right' => '',
1650 'default' => false,
1651 'disabled' => false,
1652 'hided' => false,
1653 'subtabs' => $subtabs,
1654 'folder_style' => 'order:18;',
1655 ),
1656 );
1657 }
1658
1659 /**
1660 * Save settings.
1661 *
1662 * @return void
1663 */
1664 public function maybe_update() {
1665
1666 $form_name = 'wpbc_settings_calendar_form';
1667
1668 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1669 if ( ! isset( $_POST[ 'is_form_submitted_' . $form_name ] ) ) {
1670 return;
1671 }
1672
1673 check_admin_referer( 'wpbc_settings_page_' . $form_name );
1674
1675 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_calendar__get_manage_cap() ) ) {
1676 return;
1677 }
1678
1679 $cleaned_data = wpbc_settings_calendar__validate_data( $_POST ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1680 wpbc_settings_calendar__update_settings( $cleaned_data );
1681
1682 $this->is_updated = true;
1683 }
1684
1685 /**
1686 * Right compact sidebar tabs.
1687 *
1688 * @return void
1689 */
1690 public function right_sidebar_compact_content() {
1691
1692 WPBC_UI_Sidebar_Panels::render_rightbar_tabs(
1693 array(
1694 array(
1695 'id' => 'wpbc_tab_calendar_settings',
1696 'panel_id' => 'wpbc_calendar__inspector_settings',
1697 'title' => __( 'Settings', 'booking' ),
1698 'icon' => 'wpbc_icn_tune',
1699 'selected' => true,
1700 ),
1701 array(
1702 'id' => 'wpbc_tab_calendar_notes',
1703 'panel_id' => 'wpbc_calendar__inspector_notes',
1704 'title' => __( 'Notes', 'booking' ),
1705 'icon' => 'wpbc-bi-info-circle',
1706 ),
1707 ),
1708 array(
1709 'aria_label' => __( 'Calendar Panels', 'booking' ),
1710 'context' => 'settings_calendar',
1711 'class' => 'wpbc_calendar_rightbar_tabs',
1712 )
1713 );
1714 }
1715
1716 /**
1717 * Right sidebar panels.
1718 *
1719 * @return void
1720 */
1721 public function right_sidebar_content() {
1722 ?>
1723 <div class="wpbc_bfb__panel--library wpbc_rightbar_palette wpbc_calendar_rightbar_panels">
1724 <?php
1725 WPBC_UI_Sidebar_Panels::render_panel(
1726 array(
1727 'id' => 'wpbc_calendar__inspector_settings',
1728 'labelledby' => 'wpbc_tab_calendar_settings',
1729 'class' => 'wpbc_calendar__inspector_settings',
1730 ),
1731 array( $this, 'right_panel_settings_content' )
1732 );
1733
1734 WPBC_UI_Sidebar_Panels::render_panel(
1735 array(
1736 'id' => 'wpbc_calendar__inspector_notes',
1737 'labelledby' => 'wpbc_tab_calendar_notes',
1738 'class' => 'wpbc_calendar__inspector_notes',
1739 'hidden' => true,
1740 ),
1741 array( $this, 'right_panel_notes_content' )
1742 );
1743 ?>
1744 </div>
1745 <?php
1746 }
1747
1748 /**
1749 * Settings panel content.
1750 *
1751 * @return void
1752 */
1753 public function right_panel_settings_content() {
1754
1755 $form_name = 'wpbc_settings_calendar_form';
1756 $settings = wpbc_settings_calendar__get_settings_response();
1757 $is_premium_lock = ! wpbc_settings_calendar__is_range_supported();
1758 $open_section = wpbc_settings_calendar__get_open_section();
1759
1760 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Calendar Settings', 'booking' ), __( 'Date selection and change-over behavior with live calendar preview.', 'booking' ) );
1761 ?>
1762 <form method="post" id="<?php echo esc_attr( $form_name ); ?>" class="wpbc_calendar_settings_form" data-wpbc-calendar-settings-form="1">
1763 <?php wp_nonce_field( 'wpbc_settings_page_' . $form_name ); ?>
1764 <input type="hidden" name="is_form_submitted_<?php echo esc_attr( $form_name ); ?>" value="1" />
1765 <div class="wpbc_bfb__inspector__body wpbc_calendar_inspector_body">
1766 <?php
1767 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1768 array(
1769 'id' => 'wpbc_calendar_days_selection_group',
1770 'group' => 'settings-calendar-days-selection',
1771 'title' => __( 'Days Selection', 'booking' ),
1772 'open' => ( '' === $open_section || 'days_selection' === $open_section ),
1773 ),
1774 function () use ( $settings, $is_premium_lock ) {
1775 $selected_day_mode = in_array( $settings['booking_type_of_day_selections'], array( 'single', 'multiple', 'range' ), true )
1776 ? $settings['booking_type_of_day_selections']
1777 : 'multiple';
1778 $range_days_title = wpbc_settings_calendar__get_range_days_title();
1779 ?>
1780 <div class="wpbc_calendar_radio_stack" data-wpbc-calendar-days-mode="1">
1781 <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>
1782 <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>
1783 <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>
1784 </div>
1785 <?php if ( $is_premium_lock ) : ?>
1786 <?php wpbc_settings_calendar__render_range_upgrade_note(); ?>
1787 <?php endif; ?>
1788 <?php if ( ! $is_premium_lock ) : ?>
1789 <div class="wpbc_calendar_subsettings" data-wpbc-calendar-range-settings="1">
1790 <div class="wpbc_calendar_radio_stack">
1791 <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>
1792 <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>
1793 </div>
1794 <div class="wpbc_calendar_range_block" data-wpbc-calendar-range-type="fixed">
1795 <div class="wpbc_calendar_field_row">
1796 <label for="booking_range_selection_days_count"><?php esc_html_e( 'Days selection number', 'booking' ); ?></label>
1797 <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'] ); ?>" />
1798 </div>
1799 <div class="wpbc_calendar_field_row">
1800 <label><?php esc_html_e( 'Start day of range', 'booking' ); ?></label>
1801 <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>
1802 <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>
1803 <?php wpbc_settings_calendar__render_weekday_checks( 'booking_range_start_day_weekdays', $settings['booking_range_start_day'] ); ?>
1804 </div>
1805 </div>
1806 <div class="wpbc_calendar_range_block" data-wpbc-calendar-range-type="dynamic">
1807 <div class="wpbc_calendar_inline_fields">
1808 <div class="wpbc_calendar_field_row">
1809 <label for="booking_range_selection_days_count_dynamic"><?php esc_html_e( 'Min', 'booking' ); ?></label>
1810 <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'] ); ?>" />
1811 </div>
1812 <div class="wpbc_calendar_field_row">
1813 <label for="booking_range_selection_days_max_count_dynamic"><?php esc_html_e( 'Max', 'booking' ); ?></label>
1814 <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'] ); ?>" />
1815 </div>
1816 </div>
1817 <div class="wpbc_calendar_field_row">
1818 <label for="booking_range_selection_days_specific_num_dynamic"><?php esc_html_e( 'Specific days selections', 'booking' ); ?></label>
1819 <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' ); ?>" />
1820 </div>
1821 <div class="wpbc_calendar_field_row">
1822 <label><?php esc_html_e( 'Start day of range', 'booking' ); ?></label>
1823 <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>
1824 <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>
1825 <?php wpbc_settings_calendar__render_weekday_checks( 'booking_range_start_day_dynamic_weekdays', $settings['booking_range_start_day_dynamic'] ); ?>
1826 </div>
1827 </div>
1828 </div>
1829 <?php endif; ?>
1830 <?php
1831 }
1832 );
1833
1834 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1835 array(
1836 'id' => 'wpbc_calendar_time_group',
1837 'group' => 'settings-calendar-time',
1838 'title' => __( 'Changeover and Times', 'booking' ),
1839 'open' => ( 'changeover_times' === $open_section ),
1840 ),
1841 function () use ( $settings, $is_premium_lock ) {
1842 $time_options = wpbc_settings_calendar__get_time_options( $settings['booking_range_selection_start_time'] );
1843 $time_options = array_merge( $time_options, wpbc_settings_calendar__get_time_options( $settings['booking_range_selection_end_time'] ) );
1844 ksort( $time_options );
1845 ?>
1846 <div class="wpbc_calendar_field_row">
1847 <?php
1848 wpbc_settings_calendar__render_checkbox(
1849 'booking_recurrent_time',
1850 __( 'Use selected times for each booking date', 'booking' ),
1851 __( 'Use selected times as booked time slots on each selected date.', 'booking' ),
1852 $settings
1853 );
1854 ?>
1855 </div>
1856 <?php if ( ! $is_premium_lock || wpbc_settings_calendar__is_dismissed_visible( wpbc_settings_calendar__get_premium_option_dismiss_id( 'booking_last_checkout_day_available' ) ) ) : ?>
1857 <div class="wpbc_calendar_field_row">
1858 <?php
1859 wpbc_settings_calendar__render_checkbox(
1860 'booking_last_checkout_day_available',
1861 __( 'Set check out date as available', 'booking' ),
1862 __( 'Remove the last selected day from saving to the booking.', 'booking' ),
1863 $settings,
1864 $is_premium_lock
1865 );
1866 ?>
1867 </div>
1868 <?php endif; ?>
1869 <?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' ) ) ) : ?>
1870 <div class="wpbc_calendar_field_row">
1871 <?php
1872 wpbc_settings_calendar__render_checkbox(
1873 'booking_range_selection_time_is_active',
1874 __( 'Use changeover days', 'booking' ),
1875 __( 'Check-in/out days will be marked with vertical or diagonal lines.', 'booking' ),
1876 $settings,
1877 $is_premium_lock
1878 );
1879 ?>
1880 <?php if ( $is_premium_lock ) : ?>
1881 <?php wpbc_settings_calendar__render_changeover_upgrade_note(); ?>
1882 <?php endif; ?>
1883 </div>
1884 <?php endif; ?>
1885 <div class="wpbc_calendar_subsettings" data-wpbc-calendar-changeover-settings="1">
1886 <div class="wpbc_calendar_inline_fields">
1887 <div class="wpbc_calendar_field_row">
1888 <label for="booking_range_selection_start_time"><?php esc_html_e( 'Check-in time', 'booking' ); ?></label>
1889 <?php wpbc_settings_calendar__render_select( 'booking_range_selection_start_time', $time_options, $settings['booking_range_selection_start_time'] ); ?>
1890 </div>
1891 <div class="wpbc_calendar_field_row">
1892 <label for="booking_range_selection_end_time"><?php esc_html_e( 'Check-Out time', 'booking' ); ?></label>
1893 <?php wpbc_settings_calendar__render_select( 'booking_range_selection_end_time', $time_options, $settings['booking_range_selection_end_time'] ); ?>
1894 </div>
1895 </div>
1896 <?php if ( ! $is_premium_lock || wpbc_settings_calendar__is_dismissed_visible( wpbc_settings_calendar__get_premium_option_dismiss_id( 'booking_change_over_days_triangles' ) ) ) : ?>
1897 <div class="wpbc_calendar_field_row">
1898 <?php
1899 wpbc_settings_calendar__render_checkbox(
1900 'booking_change_over_days_triangles',
1901 __( 'Change over days as triangles', 'booking' ),
1902 '',
1903 $settings,
1904 $is_premium_lock
1905 );
1906 ?>
1907 </div>
1908 <?php endif; ?>
1909 <?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' ) ) ) : ?>
1910 <div class="wpbc_calendar_field_row">
1911 <?php
1912 wpbc_settings_calendar__render_checkbox(
1913 'booking_change_over__is_excerpt_on_pages',
1914 __( 'Do not use change over days on certain pages', 'booking' ),
1915 __( 'Activate exceptions for pages that should not use change over days.', 'booking' ),
1916 $settings,
1917 $is_premium_lock
1918 );
1919 ?>
1920 </div>
1921 <?php endif; ?>
1922 <div class="wpbc_calendar_field_row">
1923 <label for="booking_change_over__excerpt_on_pages"><?php esc_html_e( 'Relative URLs of pages', 'booking' ); ?></label>
1924 <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>
1925 </div>
1926 <div class="wpbc_calendar_field_row">
1927 <label for="booking_change_over__excerpt_bk_resources"><?php esc_html_e( 'Booking resource IDs', 'booking' ); ?></label>
1928 <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>
1929 </div>
1930 </div>
1931 <?php
1932 }
1933 );
1934
1935 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1936 array(
1937 'id' => 'wpbc_calendar_legend_group',
1938 'group' => 'settings-calendar-legend',
1939 'title' => __( 'Calendar Legend', 'booking' ),
1940 'open' => ( 'legend' === $open_section ),
1941 ),
1942 function () use ( $settings ) {
1943 ?>
1944 <div class="wpbc_calendar_field_row">
1945 <?php
1946 wpbc_settings_calendar__render_checkbox(
1947 'booking_is_show_legend',
1948 __( 'Show legend below calendar', 'booking' ),
1949 __( 'Check this box to display a legend of dates below the booking calendar.', 'booking' ),
1950 $settings
1951 );
1952 ?>
1953 </div>
1954 <div class="wpbc_calendar_subsettings" data-wpbc-calendar-legend-settings="1">
1955 <div class="wpbc_calendar_legend_items_grid">
1956 <?php
1957 foreach ( wpbc_settings_calendar__get_legend_items_config() as $legend_item => $legend_config ) {
1958 wpbc_settings_calendar__render_legend_item_control( $legend_item, $legend_config, $settings );
1959 }
1960 ?>
1961 </div>
1962 <div class="wpbc_calendar_field_row">
1963 <?php
1964 wpbc_settings_calendar__render_checkbox(
1965 'booking_legend_is_show_numbers',
1966 __( 'Show date number in legend', 'booking' ),
1967 __( 'Check this box to display today date number in legend cells.', 'booking' ),
1968 $settings
1969 );
1970 ?>
1971 </div>
1972 <div class="wpbc_calendar_field_row">
1973 <?php
1974 wpbc_settings_calendar__render_checkbox(
1975 'booking_legend_is_vertical',
1976 __( 'Show legend items in a column', 'booking' ),
1977 __( 'Check this box to display legend items vertically in a column.', 'booking' ),
1978 $settings
1979 );
1980 ?>
1981 </div>
1982 </div>
1983 <?php
1984 }
1985 );
1986
1987 $settings['booking_show_timeslots_in_tooltip'] = wpbc_settings_calendar__is_timeslots_tooltip_enabled( $settings ) ? 'On' : 'Off';
1988
1989 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1990 array(
1991 'id' => 'wpbc_calendar_tooltips_group',
1992 'group' => 'settings-calendar-tooltips',
1993 'title' => __( 'Calendar Dates Tooltips', 'booking' ),
1994 'open' => ( 'tooltips' === $open_section ),
1995 ),
1996 function () use ( $settings ) {
1997 ?>
1998 <div class="wpbc_calendar_field_row">
1999 <?php
2000 wpbc_settings_calendar__render_checkbox(
2001 'booking_show_timeslots_in_tooltip',
2002 __( 'Show time slots in tooltips', 'booking' ),
2003 __( 'Show booked time slots in the tooltip when the mouse hovers over a booked day in the calendar.', 'booking' ),
2004 $settings
2005 );
2006 ?>
2007 </div>
2008 <div class="wpbc_calendar_field_row" data-wpbc-calendar-timeslot-tooltip-settings="1">
2009 <label for="booking_highlight_timeslot_word"><?php esc_html_e( 'Title of booked timeslot(s)', 'booking' ); ?></label>
2010 <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' ); ?>" />
2011 <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>
2012 </div>
2013 <?php if ( class_exists( 'wpdev_bk_biz_l' ) ) : ?>
2014 <div class="wpbc_calendar_field_row">
2015 <?php
2016 wpbc_settings_calendar__render_checkbox(
2017 'booking_is_show_availability_in_tooltips',
2018 __( 'Show availability in tooltip', 'booking' ),
2019 __( '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' ),
2020 $settings
2021 );
2022 ?>
2023 </div>
2024 <div class="wpbc_calendar_field_row" data-wpbc-calendar-availability-tooltip-settings="1">
2025 <label for="booking_highlight_availability_word"><?php esc_html_e( 'Availability Title', 'booking' ); ?></label>
2026 <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' ); ?>" />
2027 <p class="wpbc_calendar_description"><?php echo wp_kses_post( sprintf( __( 'Type your %1$savailability%2$s description', 'booking' ), '<b>', '</b>' ) ); ?></p>
2028 </div>
2029 <div class="wpbc_calendar_field_row">
2030 <?php
2031 wpbc_settings_calendar__render_checkbox(
2032 'booking_is_show_availability_in_date_cell',
2033 __( 'Show availability in date cell', 'booking' ),
2034 __( 'Check this box to display the available number of booking resources at the date cells in the calendar(s).', 'booking' ),
2035 $settings
2036 );
2037 ?>
2038 </div>
2039 <div class="wpbc_calendar_field_row" data-wpbc-calendar-availability-cell-settings="1">
2040 <label for="booking_highlight_availability_word_in_date_cell"><?php esc_html_e( 'Availability Title', 'booking' ); ?></label>
2041 <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' ) ); ?>" />
2042 <p class="wpbc_calendar_description"><?php echo wp_kses_post( sprintf( __( 'Type your %1$savailability%2$s description', 'booking' ), '<b>', '</b>' ) ); ?></p>
2043 </div>
2044 <?php else : ?>
2045 <?php
2046 wpbc_settings_calendar__render_locked_premium_checkbox(
2047 'booking_is_show_availability_in_tooltips',
2048 __( 'Show availability in tooltip', 'booking' ),
2049 __( 'Display the available number of booking resources in the day tooltip.', 'booking' ),
2050 'Business Large+'
2051 );
2052 wpbc_settings_calendar__render_locked_premium_checkbox(
2053 'booking_is_show_availability_in_date_cell',
2054 __( 'Show availability in date cell', 'booking' ),
2055 __( 'Display the available number of booking resources directly inside calendar date cells.', 'booking' ),
2056 'Business Large+'
2057 );
2058 ?>
2059 <?php endif; ?>
2060 <?php if ( class_exists( 'wpdev_bk_biz_m' ) ) : ?>
2061 <div class="wpbc_calendar_field_row">
2062 <?php
2063 wpbc_settings_calendar__render_checkbox(
2064 'booking_is_show_cost_in_tooltips',
2065 __( 'Showing cost in tooltip', 'booking' ),
2066 __( 'Check this box to display the daily cost with a tooltip when mouse hovers over each day on the calendar(s).', 'booking' ),
2067 $settings
2068 );
2069 ?>
2070 </div>
2071 <div class="wpbc_calendar_field_row" data-wpbc-calendar-cost-tooltip-settings="1">
2072 <label for="booking_highlight_cost_word"><?php esc_html_e( 'Cost Title', 'booking' ); ?></label>
2073 <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' ); ?>" />
2074 <p class="wpbc_calendar_description"><?php echo wp_kses_post( sprintf( __( 'Type your %1$scost%2$s description', 'booking' ), '<b>', '</b>' ) ); ?></p>
2075 </div>
2076 <div class="wpbc_calendar_field_row">
2077 <?php
2078 wpbc_settings_calendar__render_checkbox(
2079 'booking_is_show_cost_in_date_cell',
2080 __( 'Showing cost in date cell', 'booking' ),
2081 sprintf( __( 'Check this box to display the %1$sdaily cost at the date cells%2$s in the calendar(s).', 'booking' ), '<b>', '</b>' ),
2082 $settings
2083 );
2084 ?>
2085 </div>
2086 <div class="wpbc_calendar_field_row" data-wpbc-calendar-cost-cell-settings="1">
2087 <label for="booking_cost_in_date_cell_currency"><?php esc_html_e( 'Currency symbol', 'booking' ); ?></label>
2088 <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;" />
2089 <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>
2090 </div>
2091 <div class="wpbc_calendar_field_row">
2092 <?php
2093 wpbc_settings_calendar__render_checkbox(
2094 'booking_is_show_booked_data_in_tooltips',
2095 __( 'Show booking details in tooltip', 'booking' ),
2096 __( 'Check this box to display booking details with a tooltip, when mouse hovers over each day on the usual month calendar(s).', 'booking' ),
2097 $settings
2098 );
2099 ?>
2100 </div>
2101 <div class="wpbc_calendar_field_row" data-wpbc-calendar-booked-tooltip-settings="1">
2102 <label for="booking_booked_data_in_tooltips"><?php esc_html_e( 'Booking details', 'booking' ); ?></label>
2103 <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]" />
2104 <p class="wpbc_calendar_description"><?php esc_html_e( 'You can use the shortcodes from the bottom form of Settings Fields page.', 'booking' ); ?></p>
2105 </div>
2106 <?php else : ?>
2107 <?php
2108 wpbc_settings_calendar__render_locked_premium_checkbox(
2109 'booking_is_show_cost_in_tooltips',
2110 __( 'Showing cost in tooltip', 'booking' ),
2111 __( 'Display the daily cost in the tooltip when the mouse hovers over a calendar day.', 'booking' ),
2112 'Business Medium+'
2113 );
2114 wpbc_settings_calendar__render_locked_premium_checkbox(
2115 'booking_is_show_cost_in_date_cell',
2116 __( 'Showing cost in date cell', 'booking' ),
2117 __( 'Display the daily cost directly inside calendar date cells.', 'booking' ),
2118 'Business Medium+'
2119 );
2120 wpbc_settings_calendar__render_locked_premium_checkbox(
2121 'booking_is_show_booked_data_in_tooltips',
2122 __( 'Show booking details in tooltip', 'booking' ),
2123 __( 'Display selected booking details in the tooltip when the mouse hovers over booked days.', 'booking' ),
2124 'Business Medium+'
2125 );
2126 ?>
2127 <?php endif; ?>
2128 <?php
2129 }
2130 );
2131
2132 WPBC_UI_Sidebar_Panels::render_collapsible_group(
2133 array(
2134 'id' => 'wpbc_calendar_general_group',
2135 'group' => 'settings-calendar-general',
2136 'title' => __( 'Calendar General', 'booking' ),
2137 'open' => ( 'general' === $open_section ),
2138 ),
2139 function () use ( $settings ) {
2140 ?>
2141 <div class="wpbc_calendar_field_row">
2142 <label for="booking_max_monthes_in_calendar"><?php esc_html_e( 'Number of months to scroll', 'booking' ); ?></label>
2143 <?php wpbc_settings_calendar__render_select( 'booking_max_monthes_in_calendar', wpbc_settings_calendar__get_max_month_options(), $settings['booking_max_monthes_in_calendar'] ); ?>
2144 </div>
2145 <div class="wpbc_calendar_field_row">
2146 <label for="booking_start_day_weeek"><?php esc_html_e( 'Start Day of the week', 'booking' ); ?></label>
2147 <?php wpbc_settings_calendar__render_select( 'booking_start_day_weeek', wpbc_settings_calendar__get_weekday_options(), $settings['booking_start_day_weeek'] ); ?>
2148 </div>
2149 <div class="wpbc_calendar_field_row">
2150 <?php
2151 wpbc_settings_calendar__render_checkbox(
2152 'booking_calendar_allow_several_months_on_mobile',
2153 __( 'Allow multiple months to be shown on mobile', 'booking' ),
2154 __( 'Enable this option to allow multiple months to be shown in the calendar on mobile devices.', 'booking' ),
2155 $settings
2156 );
2157 ?>
2158 </div>
2159 <?php
2160 }
2161 );
2162 ?>
2163 </div>
2164 </form>
2165 <?php
2166 }
2167
2168 /**
2169 * Notes panel content.
2170 *
2171 * @return void
2172 */
2173 public function right_panel_notes_content() {
2174
2175 ?>
2176 <div class="wpbc_calendar_notes_panel">
2177 <?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' ) ); ?>
2178 <div class="wpbc_ts_hint wpbc_calendar_hint_bar">
2179 <span class="wpbc_icn_info_outline"></span>
2180 <?php esc_html_e( 'Premium options can be tested in the preview, but they are saved only when the installed edition supports them.', 'booking' ); ?>
2181 </div>
2182 </div>
2183 <?php
2184 }
2185
2186 /**
2187 * Page content.
2188 *
2189 * @return void
2190 */
2191 public function content() {
2192
2193 do_action( 'wpbc_hook_settings_page_header', 'page_settings_calendar' );
2194
2195 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_calendar__get_manage_cap() ) ) {
2196 return false;
2197 }
2198
2199 if ( function_exists( 'wpbc_js_for_bookings_page' ) ) {
2200 wpbc_js_for_bookings_page();
2201 }
2202
2203 if ( $this->is_updated ) {
2204 wpbc_show_changes_saved_message();
2205 }
2206
2207 $resource_id = wpbc_settings_calendar__get_preview_resource_id();
2208 $months_count = wpbc_settings_calendar__get_preview_months_count();
2209 $resources = wpbc_settings_calendar__get_resources();
2210 $is_free_version = ! class_exists( 'wpdev_bk_personal' );
2211 ?>
2212 <div class="wpbc_calendar_settings_page wpdevelop" data-wpbc-calendar-page="1" data-wpbc-calendar-resource-id="<?php echo esc_attr( $resource_id ); ?>">
2213 <form method="get" class="wpbc_calendar_toolbar wpbc_ts_toolbar wpbc_calendar_preview_controls" data-wpbc-calendar-preview-toolbar="1">
2214 <input type="hidden" name="page" value="wpbc-settings" />
2215 <input type="hidden" name="tab" value="calendar_settings" />
2216 <div class="wpbc_ts_control wpbc_calendar_control_resource">
2217 <label for="wpbc_calendar_resource_id"><?php esc_html_e( 'Booking resource', 'booking' ); ?></label>
2218 <?php if ( $is_free_version ) : ?>
2219 <input type="hidden" id="wpbc_calendar_resource_id" name="resource_id" value="<?php echo esc_attr( $resource_id ); ?>" />
2220 <div class="wpbc_calendar_toolbar_value">
2221 <i class="menu_icon icon-1x wpbc-bi-calendar2-day"></i>
2222 <span><?php echo esc_html( ! empty( $resources[0]['title'] ) ? $resources[0]['title'] : __( 'Default booking resource', 'booking' ) ); ?></span>
2223 </div>
2224 <?php
2225 $resource_dismiss_id = wpbc_settings_calendar__get_premium_option_dismiss_id( 'booking_resources' );
2226 if ( wpbc_settings_calendar__is_dismissed_visible( $resource_dismiss_id ) ) :
2227 ?>
2228 <div id="<?php echo esc_attr( $resource_dismiss_id ); ?>" class="wpbc_calendar_upgrade_hint">
2229 <?php wpbc_settings_calendar__render_premium_label( 'Pro', '', $resource_dismiss_id ); ?>
2230 <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>
2231 </div>
2232 <?php endif; ?>
2233 <?php else : ?>
2234 <select id="wpbc_calendar_resource_id" name="resource_id">
2235 <?php foreach ( $resources as $resource ) : ?>
2236 <option value="<?php echo esc_attr( $resource['id'] ); ?>" <?php selected( $resource_id, (int) $resource['id'] ); ?>><?php echo esc_html( $resource['title'] ); ?></option>
2237 <?php endforeach; ?>
2238 </select>
2239 <?php endif; ?>
2240 </div>
2241 <div class="wpbc_ts_control wpbc_calendar_control_months">
2242 <label for="wpbc_calendar_months_count"><?php esc_html_e( 'Months', 'booking' ); ?></label>
2243 <select id="wpbc_calendar_months_count" name="months_count">
2244 <?php foreach ( array( 1, 2, 3, 4, 6, 12 ) as $month_option ) : ?>
2245 <option value="<?php echo esc_attr( $month_option ); ?>" <?php selected( $months_count, $month_option ); ?>><?php echo esc_html( $month_option ); ?></option>
2246 <?php endforeach; ?>
2247 </select>
2248 </div>
2249 </form>
2250 <?php wpbc_settings_calendar__render_calendar_preview( $resource_id, $months_count ); ?>
2251 <div class="wpbc_calendar_settings_notes" data-wpbc-calendar-notes="1">
2252 <div class="wpbc_ts_hint wpbc_calendar_hint_bar">
2253 <span class="wpbc_icn_info_outline"></span>
2254 <?php esc_html_e( 'Preview how date selection behaves before saving the calendar settings.', 'booking' ); ?>
2255 </div>
2256 </div>
2257 </div>
2258 <?php
2259
2260 do_action( 'wpbc_hook_settings_page_footer', 'page_settings_calendar' );
2261 }
2262 }
2263 add_action( 'wpbc_menu_created', array( new WPBC_Page_Settings_Calendar(), '__construct' ) );
2264