PluginProbe
Booking Calendar / 11.4.3
Booking Calendar v11.4.3
11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 All 204 releases
booking / includes / page-settings-themes / settings_themes__page.php

settings_themes__page.php in Booking Calendar 11.4.3, at includes/page-settings-themes/settings_themes__page.php

1,626 lines 61.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Appearance / Theme settings page.
4 *
5 * @package Booking Calendar
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 require_once WPBC_PLUGIN_DIR . '/includes/_front_end/form-style-presets.php';
13
14 /**
15 * Check whether the Appearance / Theme settings page is active.
16 *
17 * @return bool
18 */
19 function wpbc_settings_themes__is_page() {
20
21 if ( ! is_admin() ) {
22 return false;
23 }
24
25 if ( function_exists( 'wpbc_is_settings_themes_page' ) ) {
26 return wpbc_is_settings_themes_page();
27 }
28
29 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
30 $page = isset( $_REQUEST['page'] ) ? sanitize_key( wp_unslash( $_REQUEST['page'] ) ) : '';
31 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
32 $tab = isset( $_REQUEST['tab'] ) ? sanitize_key( wp_unslash( $_REQUEST['tab'] ) ) : '';
33
34 return ( 'wpbc-settings' === $page && 'themes' === $tab );
35 }
36
37 /**
38 * Redirect legacy Color Theme URLs to the new Appearance / Theme page.
39 *
40 * @return void
41 */
42 function wpbc_settings_themes__redirect_legacy_color_themes_url() {
43
44 if ( ! is_admin() ) {
45 return;
46 }
47
48 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
49 $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
50 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
51 $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : '';
52
53 if (
54 'wpbc-settings' !== $page
55 || 'color_themes' !== $tab
56 ) {
57 return;
58 }
59
60 $args = array();
61 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
62 foreach ( wp_unslash( $_GET ) as $key => $value ) {
63 $key = sanitize_key( $key );
64 if ( in_array( $key, array( 'page', 'tab' ), true ) || is_array( $value ) ) {
65 continue;
66 }
67 $args[ $key ] = sanitize_text_field( $value );
68 }
69
70 $url = function_exists( 'wpbc_get_settings_themes_url' )
71 ? wpbc_get_settings_themes_url()
72 : admin_url( 'admin.php?page=wpbc-settings&tab=themes' );
73
74 wp_safe_redirect( add_query_arg( $args, $url ) );
75 exit;
76 }
77 add_action( 'admin_init', 'wpbc_settings_themes__redirect_legacy_color_themes_url', 1 );
78
79 /**
80 * Enqueue CSS for Appearance / Theme.
81 *
82 * @param string $where_to_load Where assets are loaded.
83 *
84 * @return void
85 */
86 function wpbc_settings_themes_enqueue_css_files( $where_to_load ) {
87
88 if ( ( ! is_admin() ) || ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) ) ) {
89 return;
90 }
91
92 if ( ! wpbc_settings_themes__is_page() ) {
93 return;
94 }
95
96 wp_enqueue_style(
97 'wpbc-settings-themes-page',
98 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/settings_themes_page.css',
99 array( 'wpbc-calendar', 'wpbc-all-admin' ),
100 WP_BK_VERSION_NUM
101 );
102 }
103 add_action( 'wpbc_enqueue_css_files', 'wpbc_settings_themes_enqueue_css_files', 66 );
104
105 /**
106 * Enqueue JS for Appearance / Theme.
107 *
108 * @param string $where_to_load Where assets are loaded.
109 *
110 * @return void
111 */
112 function wpbc_settings_themes_enqueue_js_files( $where_to_load ) {
113
114 if ( ( ! is_admin() ) || ( ! in_array( $where_to_load, array( 'admin', 'both' ), true ) ) ) {
115 return;
116 }
117
118 if ( ! wpbc_settings_themes__is_page() ) {
119 return;
120 }
121
122 wp_enqueue_script(
123 'wpbc-settings-themes-page',
124 trailingslashit( plugins_url( '', __FILE__ ) ) . '_out/settings_themes_page.js',
125 array( 'jquery', 'wpbc_all' ),
126 WP_BK_VERSION_NUM,
127 array( 'in_footer' => WPBC_JS_IN_FOOTER )
128 );
129
130 wp_localize_script(
131 'wpbc-settings-themes-page',
132 'wpbc_settings_themes_page',
133 array(
134 'ajax_url' => admin_url( 'admin-ajax.php' ),
135 'plugin_url' => trailingslashit( WPBC_PLUGIN_URL ),
136 'nonce' => wp_create_nonce( 'wpbc_settings_themes_ajax_nonce' ),
137 'action' => 'WPBC_AJX_SETTINGS_THEMES_SAVE',
138 'preview_action' => 'WPBC_AJX_SETTINGS_THEMES_PREVIEW',
139 'settings' => wpbc_settings_themes__get_settings_response(),
140 'form_style_presets' => wpbc_bfb_settings__get_form_style_presets(),
141 'form_style_css_var_names' => wpbc_bfb_settings__get_form_style_css_var_names(),
142 'custom_form_style_defaults' => wpbc_bfb_settings__get_default_custom_form_style_options(),
143 'days_selection' => wpbc_settings_themes__get_days_selection_response(),
144 'i18n' => array(
145 'saving' => __( 'Saving', 'booking' ),
146 'saved' => __( 'Appearance settings updated.', 'booking' ),
147 'save_failed' => __( 'Unable to save appearance settings.', 'booking' ),
148 'preview_failed' => __( 'Unable to refresh calendar preview.', 'booking' ),
149 'security_error' => __( 'Security check failed.', 'booking' ),
150 'loading' => __( 'Loading', 'booking' ),
151 'calendar_only_theme_notice' => __( 'Preview is set to Calendar only. A matching calendar skin was selected automatically; switch Preview to Booking form to inspect the form theme.', 'booking' ),
152 'form_preview_option_notice' => __( 'This option is visible in the Booking form preview. Switch Preview to Booking form to inspect it.', 'booking' ),
153 ),
154 )
155 );
156 }
157 add_action( 'wpbc_enqueue_js_files', 'wpbc_settings_themes_enqueue_js_files', 66 );
158
159 /**
160 * Print tooltip initializer for Appearance / Theme.
161 *
162 * @return void
163 */
164 function wpbc_settings_themes_print_tooltip_js() {
165
166 if ( ! wpbc_settings_themes__is_page() ) {
167 return;
168 }
169
170 if ( function_exists( 'wpbc_bs_javascript_tooltips' ) ) {
171 wpbc_bs_javascript_tooltips();
172 }
173 }
174 add_action( 'admin_footer', 'wpbc_settings_themes_print_tooltip_js', 67 );
175
176 /**
177 * Get day-selection settings in the same normalized shape used by calendar boot code.
178 *
179 * @return array
180 */
181 function wpbc_settings_themes__get_days_selection_response() {
182
183 $days_selection = array(
184 'days_select_mode' => 'multiple',
185 'fixed__days_num' => 0,
186 'fixed__week_days__start' => '-1',
187 'dynamic__days_min' => 0,
188 'dynamic__days_max' => 0,
189 'dynamic__days_specific' => '',
190 'dynamic__week_days__start' => '-1',
191 );
192
193 if ( function_exists( 'wpbc__calendar__js_params__get_days_selection_arr' ) ) {
194 $days_selection = wp_parse_args( wpbc__calendar__js_params__get_days_selection_arr(), $days_selection );
195 }
196
197 return array(
198 'days_select_mode' => (string) $days_selection['days_select_mode'],
199 'fixed__days_num' => (int) $days_selection['fixed__days_num'],
200 'fixed__week_days__start' => (string) $days_selection['fixed__week_days__start'],
201 'dynamic__days_min' => (int) $days_selection['dynamic__days_min'],
202 'dynamic__days_max' => (int) $days_selection['dynamic__days_max'],
203 'dynamic__days_specific' => (string) $days_selection['dynamic__days_specific'],
204 'dynamic__week_days__start' => (string) $days_selection['dynamic__week_days__start'],
205 );
206 }
207
208 /**
209 * Get resource options.
210 *
211 * @return array
212 */
213 function wpbc_settings_themes__get_resources() {
214
215 if ( function_exists( 'wpbc_availability_general__get_resources' ) ) {
216 return wpbc_availability_general__get_resources();
217 }
218
219 $resources = array();
220
221 if ( function_exists( 'wpbc_ajx_get_sorted_booking_resources_arr' ) && function_exists( 'wpbc_ajx_get_all_booking_resources_arr' ) ) {
222 $resource_rows = wpbc_ajx_get_sorted_booking_resources_arr( wpbc_ajx_get_all_booking_resources_arr() );
223 foreach ( $resource_rows as $resource ) {
224 $resources[] = array(
225 'id' => isset( $resource['booking_type_id'] ) ? (int) $resource['booking_type_id'] : 1,
226 'title' => isset( $resource['title'] ) ? $resource['title'] : __( 'Booking resource', 'booking' ),
227 );
228 }
229 }
230
231 if ( empty( $resources ) ) {
232 $resources[] = array(
233 'id' => function_exists( 'wpbc_get_default_resource' ) ? (int) wpbc_get_default_resource() : 1,
234 'title' => __( 'Booking resource', 'booking' ),
235 );
236 }
237
238 return $resources;
239 }
240
241 /**
242 * Get capability required to manage Appearance / Theme.
243 *
244 * @return string
245 */
246 function wpbc_settings_themes__get_manage_cap() {
247
248 $min_user_role = get_bk_option( 'booking_user_role_settings' );
249 $capability = array(
250 'administrator' => 'activate_plugins',
251 'editor' => 'publish_pages',
252 'author' => 'publish_posts',
253 'contributor' => 'edit_posts',
254 'subscriber' => 'read',
255 );
256
257 return isset( $capability[ $min_user_role ] ) ? $capability[ $min_user_role ] : 'manage_options';
258 }
259
260 /**
261 * Check if a Theme Settings upsell row is visible for current user.
262 *
263 * @param string $dismiss_id Dismiss ID.
264 *
265 * @return bool
266 */
267 function wpbc_settings_themes__is_dismissed_visible( $dismiss_id ) {
268
269 if ( wpbc_is_this_demo() ) {
270 return true;
271 }
272
273 return ! function_exists( 'wpbc_is_dismissed_panel_visible' ) || wpbc_is_dismissed_panel_visible( $dismiss_id );
274 }
275
276 /**
277 * Get dismiss ID for Theme Settings premium option.
278 *
279 * @param string $option_name Option name.
280 *
281 * @return string
282 */
283 function wpbc_settings_themes__get_premium_option_dismiss_id( $option_name ) {
284
285 return 'wpbc_is_dismissed__theme_settings__' . sanitize_key( $option_name );
286 }
287
288 /**
289 * Render compact dismiss button for Theme Settings premium hints.
290 *
291 * @param string $dismiss_id Dismiss ID.
292 *
293 * @return void
294 */
295 function wpbc_settings_themes__render_dismiss_button( $dismiss_id ) {
296
297 if ( wpbc_is_this_demo() || ! function_exists( 'wpbc_is_dismissed' ) ) {
298 return;
299 }
300
301 ?>
302 <span class="wpbc_theme_premium_dismiss">
303 <?php
304 wpbc_is_dismissed(
305 $dismiss_id,
306 array(
307 'title' => '&times;',
308 'hint' => __( 'Hide this option', 'booking' ),
309 'css' => 'float:none;margin-left:4px;',
310 )
311 );
312 ?>
313 </span>
314 <?php
315 }
316
317 /**
318 * Sanitize preview resource ID.
319 *
320 * @param int $resource_id Resource ID.
321 *
322 * @return int
323 */
324 function wpbc_settings_themes__sanitize_preview_resource_id( $resource_id ) {
325
326 $resource_id = absint( $resource_id );
327 $resources = wpbc_settings_themes__get_resources();
328 $allowed = array();
329
330 foreach ( $resources as $resource ) {
331 $allowed[] = (int) $resource['id'];
332 }
333
334 if ( in_array( $resource_id, $allowed, true ) ) {
335 return $resource_id;
336 }
337
338 return ! empty( $allowed ) ? (int) $allowed[0] : 1;
339 }
340
341 /**
342 * Sanitize preview months count.
343 *
344 * @param int $months_count Months count.
345 *
346 * @return int
347 */
348 function wpbc_settings_themes__sanitize_preview_months_count( $months_count ) {
349
350 $months_count = absint( $months_count );
351 $allowed = array( 1, 2, 3, 4, 6, 12 );
352
353 return in_array( $months_count, $allowed, true ) ? $months_count : 1;
354 }
355
356 /**
357 * Get preview resource from request or default.
358 *
359 * @return int
360 */
361 function wpbc_settings_themes__get_preview_resource_id() {
362
363 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
364 $resource_id = isset( $_REQUEST['resource_id'] ) ? absint( wp_unslash( $_REQUEST['resource_id'] ) ) : ( function_exists( 'wpbc_get_default_resource' ) ? (int) wpbc_get_default_resource() : 1 );
365
366 return wpbc_settings_themes__sanitize_preview_resource_id( $resource_id );
367 }
368
369 /**
370 * Get preview months count from request or default.
371 *
372 * @return int
373 */
374 function wpbc_settings_themes__get_preview_months_count() {
375
376 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
377 $months_count = isset( $_REQUEST['months_count'] ) ? absint( wp_unslash( $_REQUEST['months_count'] ) ) : 1;
378
379 return wpbc_settings_themes__sanitize_preview_months_count( $months_count );
380 }
381
382 /**
383 * Get preview mode options.
384 *
385 * @return array
386 */
387 function wpbc_settings_themes__get_preview_mode_options() {
388
389 return array(
390 'calendar' => __( 'Calendar only', 'booking' ),
391 'form' => __( 'Booking form', 'booking' ),
392 );
393 }
394
395 /**
396 * Sanitize preview mode.
397 *
398 * @param string $preview_mode Preview mode.
399 *
400 * @return string
401 */
402 function wpbc_settings_themes__sanitize_preview_mode( $preview_mode ) {
403
404 $preview_mode = sanitize_key( (string) $preview_mode );
405
406 return array_key_exists( $preview_mode, wpbc_settings_themes__get_preview_mode_options() ) ? $preview_mode : 'calendar';
407 }
408
409 /**
410 * Get preview mode from request.
411 *
412 * @return string
413 */
414 function wpbc_settings_themes__get_preview_mode() {
415
416 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
417 $preview_mode = isset( $_REQUEST['preview_mode'] ) ? sanitize_key( wp_unslash( $_REQUEST['preview_mode'] ) ) : 'calendar';
418
419 return wpbc_settings_themes__sanitize_preview_mode( $preview_mode );
420 }
421
422 /**
423 * Get booking form options for preview.
424 *
425 * @return array
426 */
427 function wpbc_settings_themes__get_booking_form_options() {
428
429 $form_options = array(
430 'standard' => __( 'Standard booking form', 'booking' ),
431 );
432
433 if ( class_exists( 'WPBC_FE_Custom_Form_Helper' ) ) {
434 $owner_user_id = method_exists( 'WPBC_FE_Custom_Form_Helper', 'wpbc_mu__get_current__owner_user_id' ) ? WPBC_FE_Custom_Form_Helper::wpbc_mu__get_current__owner_user_id() : 0;
435 $forms_list = WPBC_FE_Custom_Form_Helper::get_custom_booking_forms_list(
436 array(
437 'include_standard' => true,
438 'owner_user_id' => $owner_user_id,
439 'statuses' => array( 'published' ),
440 'list_mode' => 'auto',
441 )
442 );
443
444 if ( is_array( $forms_list ) ) {
445 foreach ( $forms_list as $form_slug => $form_data ) {
446 $form_slug = sanitize_text_field( (string) $form_slug );
447 if ( '' === $form_slug ) {
448 continue;
449 }
450 $form_options[ $form_slug ] = isset( $form_data['title'] ) ? sanitize_text_field( (string) $form_data['title'] ) : $form_slug;
451 }
452 }
453 }
454
455 return $form_options;
456 }
457
458 /**
459 * Sanitize custom booking form.
460 *
461 * @param string $custom_booking_form Custom booking form slug.
462 *
463 * @return string
464 */
465 function wpbc_settings_themes__sanitize_custom_booking_form( $custom_booking_form ) {
466
467 $custom_booking_form = sanitize_text_field( (string) $custom_booking_form );
468 $form_options = wpbc_settings_themes__get_booking_form_options();
469
470 return array_key_exists( $custom_booking_form, $form_options ) ? $custom_booking_form : 'standard';
471 }
472
473 /**
474 * Get custom booking form from request.
475 *
476 * @return string
477 */
478 function wpbc_settings_themes__get_custom_booking_form() {
479
480 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
481 $custom_booking_form = isset( $_REQUEST['custom_booking_form'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['custom_booking_form'] ) ) : 'standard';
482
483 return wpbc_settings_themes__sanitize_custom_booking_form( $custom_booking_form );
484 }
485
486 /**
487 * Get form theme options.
488 *
489 * @return array
490 */
491 function wpbc_settings_themes__get_form_theme_options() {
492
493 return array(
494 '' => __( 'Light', 'booking' ),
495 'wpbc_theme_dark_1' => __( 'Dark', 'booking' ),
496 );
497 }
498
499 /**
500 * Get booking form container preset options.
501 *
502 * @return array
503 */
504 function wpbc_settings_themes__get_form_appearance_preset_options() {
505
506 return array(
507 'bordered' => __( 'Bordered', 'booking' ),
508 'none' => __( 'No border', 'booking' ),
509 'soft' => __( 'Soft background', 'booking' ),
510 'custom' => __( 'Custom per form', 'booking' ),
511 );
512 }
513
514 /**
515 * Get combined booking form style choices for the visual selector.
516 *
517 * @return array
518 */
519 function wpbc_settings_themes__get_form_style_options() {
520
521 return wpbc_bfb_settings__get_form_style_options();
522 }
523
524 /**
525 * Resolve the combined visual form style value from saved settings.
526 *
527 * @param string $theme Form theme option.
528 * @param string $preset Form appearance preset option.
529 *
530 * @return string
531 */
532 function wpbc_settings_themes__get_form_style_value( $theme, $preset ) {
533
534 $theme = ( 'wpbc_theme_dark_1' === (string) $theme ) ? 'dark' : 'light';
535 $preset = (string) $preset;
536
537 if ( 'custom' === $preset ) {
538 return 'custom';
539 }
540 if ( ! in_array( $preset, array( 'bordered', 'none', 'soft' ), true ) ) {
541 $preset = 'bordered';
542 }
543
544 return $theme . '_' . $preset;
545 }
546
547 /**
548 * Map the combined visual form style value to existing saved options.
549 *
550 * @param string $style Combined style value.
551 * @param string $current_theme Current theme fallback.
552 *
553 * @return array
554 */
555 function wpbc_settings_themes__map_form_style_to_options( $style, $current_theme = '' ) {
556
557 $style = sanitize_key( (string) $style );
558 $current_theme = ( 'wpbc_theme_dark_1' === (string) $current_theme ) ? 'wpbc_theme_dark_1' : '';
559
560 if ( 'custom' === $style ) {
561 return array(
562 'booking_form_theme' => $current_theme,
563 'booking_form_appearance_preset' => 'custom',
564 );
565 }
566
567 $parts = explode( '_', $style );
568 $theme = ( isset( $parts[0] ) && 'dark' === $parts[0] ) ? 'wpbc_theme_dark_1' : '';
569 $preset = isset( $parts[1] ) ? (string) $parts[1] : 'bordered';
570 $preset = in_array( $preset, array( 'bordered', 'none', 'soft' ), true ) ? $preset : 'bordered';
571
572 return array(
573 'booking_form_theme' => $theme,
574 'booking_form_appearance_preset' => $preset,
575 );
576 }
577
578 /**
579 * Get time picker skin options.
580 *
581 * @return array
582 */
583 function wpbc_settings_themes__get_time_picker_skin_options() {
584
585 $timeslot_picker_skins_options = array();
586 $upload_dir = wp_upload_dir();
587
588 if ( function_exists( 'wpbc_dir_list' ) ) {
589 $files_in_folder = wpbc_dir_list(
590 array(
591 WPBC_PLUGIN_DIR . '/css/time_picker_skins/',
592 $upload_dir['basedir'] . '/wpbc_time_picker_skins/',
593 )
594 );
595
596 foreach ( $files_in_folder as $skin_file ) {
597 $skin_file[1] = str_replace( array( WPBC_PLUGIN_DIR, WPBC_PLUGIN_URL, $upload_dir['basedir'] ), '', $skin_file[1] );
598 $timeslot_picker_skins_options[ $skin_file[1] ] = $skin_file[2];
599 }
600 }
601
602 if ( empty( $timeslot_picker_skins_options ) ) {
603 $default_options_values = wpbc_get_default_options();
604 $default_skin = isset( $default_options_values['booking_timeslot_picker_skin'] ) ? $default_options_values['booking_timeslot_picker_skin'] : '/css/time_picker_skins/grey.css';
605 $timeslot_picker_skins_options[ $default_skin ] = __( 'Default', 'booking' );
606 }
607
608 return $timeslot_picker_skins_options;
609 }
610
611 /**
612 * Normalize calendar skin option value to a relative path.
613 *
614 * @param string $skin_value Calendar skin value.
615 *
616 * @return string
617 */
618 function wpbc_settings_themes__normalize_calendar_skin_value( $skin_value ) {
619
620 $skin_value = (string) $skin_value;
621 $upload_dir = wp_upload_dir();
622 $upload_url = ( ! empty( $upload_dir['baseurl'] ) ) ? $upload_dir['baseurl'] : '';
623
624 return str_replace(
625 array(
626 WPBC_PLUGIN_URL,
627 $upload_url,
628 ),
629 '',
630 $skin_value
631 );
632 }
633
634 /**
635 * Get URL for a relative calendar skin path.
636 *
637 * @param string $relative_skin Relative skin path.
638 *
639 * @return string
640 */
641 function wpbc_settings_themes__get_calendar_skin_url( $relative_skin ) {
642
643 $relative_skin = wpbc_settings_themes__normalize_calendar_skin_value( $relative_skin );
644 $upload_dir = wp_upload_dir();
645 $upload_url = ( ! empty( $upload_dir['baseurl'] ) ) ? $upload_dir['baseurl'] : '';
646
647 if ( 0 === strpos( $relative_skin, '/wpbc_skins/' ) && ! empty( $upload_url ) ) {
648 return $upload_url . $relative_skin;
649 }
650
651 return WPBC_PLUGIN_URL . $relative_skin;
652 }
653
654 /**
655 * Build calendar skin options for selectbox with live-preview URL metadata.
656 *
657 * @return array
658 */
659 function wpbc_settings_themes__get_calendar_skin_options_for_select() {
660
661 $options = function_exists( 'wpbc_get_calendar_skin_options' ) ? wpbc_get_calendar_skin_options() : array();
662
663 foreach ( $options as $option_value => $option_label ) {
664 if ( is_array( $option_label ) && ! empty( $option_label['optgroup'] ) ) {
665 continue;
666 }
667
668 $relative_skin = wpbc_settings_themes__normalize_calendar_skin_value( $option_value );
669 $skin_url = wpbc_settings_themes__get_calendar_skin_url( $relative_skin );
670
671 if ( is_array( $option_label ) ) {
672 $option_label['attr'] = ( isset( $option_label['attr'] ) && is_array( $option_label['attr'] ) ) ? $option_label['attr'] : array();
673 $option_label['attr']['data-wpbc-calendar-skin-url'] = $skin_url;
674 $options[ $relative_skin ] = $option_label;
675 } else {
676 $options[ $relative_skin ] = array(
677 'title' => $option_label,
678 'attr' => array(
679 'data-wpbc-calendar-skin-url' => $skin_url,
680 ),
681 );
682 }
683
684 if ( $relative_skin !== $option_value ) {
685 unset( $options[ $option_value ] );
686 }
687 }
688
689 return $options;
690 }
691
692 /**
693 * Get current settings prepared for JavaScript and AJAX responses.
694 *
695 * @return array
696 */
697 function wpbc_settings_themes__get_settings_response() {
698
699 $form_style = wpbc_bfb_settings__get_current_form_style();
700 $transition_values = wpbc_settings_themes__map_form_style_to_options( $form_style, '' );
701 $custom_values = wpbc_bfb_settings__get_custom_form_style_options();
702
703 return array_merge(
704 array(
705 'booking_form_style' => $form_style,
706 'booking_form_theme' => $transition_values['booking_form_theme'],
707 'booking_form_appearance_preset' => $transition_values['booking_form_appearance_preset'],
708 'booking_form_appearance_background_color' => get_bk_option( 'booking_form_appearance_background_color' ) ? get_bk_option( 'booking_form_appearance_background_color' ) : '#ffffff',
709 'booking_form_appearance_border_color' => get_bk_option( 'booking_form_appearance_border_color' ) ? get_bk_option( 'booking_form_appearance_border_color' ) : '#cccccc',
710 'booking_form_appearance_border_width' => get_bk_option( 'booking_form_appearance_border_width' ) ? get_bk_option( 'booking_form_appearance_border_width' ) : '1px',
711 'booking_form_appearance_border_radius' => get_bk_option( 'booking_form_appearance_border_radius' ) ? get_bk_option( 'booking_form_appearance_border_radius' ) : '2px',
712 'booking_form_appearance_padding' => get_bk_option( 'booking_form_appearance_padding' ) ? get_bk_option( 'booking_form_appearance_padding' ) : '10px 30px',
713 'booking_skin' => wpbc_settings_themes__normalize_calendar_skin_value( get_bk_option( 'booking_skin' ) ),
714 'booking_timeslot_picker_skin' => get_bk_option( 'booking_timeslot_picker_skin' ),
715 'booking_timeslot_picker' => get_bk_option( 'booking_timeslot_picker' ),
716 ),
717 $custom_values
718 );
719 }
720
721 /**
722 * Override option values while rendering the live Appearance / Theme preview.
723 *
724 * @param mixed $value Current filter value.
725 * @param string $option Option name.
726 * @param mixed $default Default option value.
727 *
728 * @return mixed
729 */
730 function wpbc_settings_themes__preview_get_bk_option( $value, $option, $default ) {
731
732 global $wpbc_settings_themes__preview_options;
733
734 if (
735 is_array( $wpbc_settings_themes__preview_options )
736 && array_key_exists( $option, $wpbc_settings_themes__preview_options )
737 ) {
738 return $wpbc_settings_themes__preview_options[ $option ];
739 }
740
741 return $value;
742 }
743 add_bk_filter( 'wpdev_bk_get_option', 'wpbc_settings_themes__preview_get_bk_option' );
744
745 /**
746 * Prepare option overrides for the live preview renderer.
747 *
748 * @param array $current_settings Current preview settings.
749 *
750 * @return array
751 */
752 function wpbc_settings_themes__get_preview_option_overrides( $current_settings ) {
753
754 $option_names = array(
755 'booking_form_style',
756 'booking_form_custom_background_color',
757 'booking_form_custom_border_color',
758 'booking_form_custom_border_width',
759 'booking_form_custom_border_radius',
760 'booking_form_custom_padding_vertical',
761 'booking_form_custom_padding_horizontal',
762 'booking_form_custom_text_color',
763 'booking_form_custom_field_background_color',
764 'booking_form_custom_field_text_color',
765 'booking_form_custom_field_border_color',
766 'booking_form_custom_button_background_color',
767 'booking_form_custom_button_text_color',
768 'booking_form_custom_button_border_color',
769 'booking_form_custom_button_hover_background_color',
770 'booking_form_custom_button_hover_text_color',
771 'booking_form_custom_button_hover_border_color',
772 'booking_form_custom_secondary_button_background_color',
773 'booking_form_custom_secondary_button_text_color',
774 'booking_form_custom_secondary_button_border_color',
775 'booking_form_custom_secondary_button_hover_background_color',
776 'booking_form_custom_secondary_button_hover_text_color',
777 'booking_form_custom_secondary_button_hover_border_color',
778 'booking_skin',
779 'booking_timeslot_picker_skin',
780 'booking_timeslot_picker',
781 );
782 $overrides = array();
783
784 foreach ( $option_names as $option_name ) {
785 if ( array_key_exists( $option_name, $current_settings ) ) {
786 $overrides[ $option_name ] = $current_settings[ $option_name ];
787 }
788 }
789
790 if ( isset( $overrides['booking_form_style'] ) ) {
791 $style = wpbc_bfb_settings__sanitize_form_style( $overrides['booking_form_style'] );
792 $preset = wpbc_bfb_settings__get_form_style_preset( $style );
793 $legacy_theme = isset( $preset['theme_class'] ) ? sanitize_html_class( (string) $preset['theme_class'] ) : '';
794 $legacy_container = isset( $preset['container_style'] ) ? sanitize_key( (string) $preset['container_style'] ) : 'bordered';
795 $legacy_container = in_array( $legacy_container, array( 'bordered', 'none', 'soft', 'custom' ), true ) ? $legacy_container : 'bordered';
796
797 $overrides['booking_form_theme'] = $legacy_theme;
798 $overrides['booking_form_appearance_preset'] = $legacy_container;
799 }
800
801 return $overrides;
802 }
803
804 /**
805 * Validate posted Appearance / Theme settings.
806 *
807 * @param array $post_data Raw post data.
808 *
809 * @return array
810 */
811 function wpbc_settings_themes__validate_data( $post_data ) {
812
813 $default_options_values = wpbc_get_default_options();
814 $calendar_skin_options = wpbc_settings_themes__get_calendar_skin_options_for_select();
815 $time_skin_options = wpbc_settings_themes__get_time_picker_skin_options();
816 $custom_values = wpbc_bfb_settings__get_custom_form_style_options();
817
818 $cleaned = array_merge(
819 array(
820 'booking_form_style' => isset( $default_options_values['booking_form_style'] ) ? wpbc_bfb_settings__sanitize_form_style( $default_options_values['booking_form_style'] ) : wpbc_bfb_settings__get_default_form_style(),
821 'booking_skin' => isset( $default_options_values['booking_skin'] ) ? $default_options_values['booking_skin'] : '',
822 'booking_timeslot_picker_skin' => isset( $default_options_values['booking_timeslot_picker_skin'] ) ? $default_options_values['booking_timeslot_picker_skin'] : '',
823 'booking_timeslot_picker' => isset( $default_options_values['booking_timeslot_picker'] ) ? $default_options_values['booking_timeslot_picker'] : 'Off',
824 ),
825 $custom_values
826 );
827
828 if ( isset( $post_data['booking_form_style'] ) ) {
829 $cleaned['booking_form_style'] = wpbc_bfb_settings__sanitize_form_style( wp_unslash( $post_data['booking_form_style'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
830 }
831
832 $sanitize_color = function ( $value, $fallback ) {
833 $value = trim( sanitize_text_field( wp_unslash( $value ) ) );
834 if ( preg_match( '/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i', $value ) || 'transparent' === $value ) {
835 return $value;
836 }
837 return $fallback;
838 };
839 $sanitize_length = function ( $value, $fallback ) {
840 $value = trim( sanitize_text_field( wp_unslash( $value ) ) );
841 if ( preg_match( '/^-?\d+(?:\.\d+)?(?:px|rem|em|%)$/i', $value ) ) {
842 return $value;
843 }
844 return $fallback;
845 };
846 $sanitize_spacing = function ( $value, $fallback ) {
847 $value = preg_replace( '/\s+/', ' ', trim( sanitize_text_field( wp_unslash( $value ) ) ) );
848 if ( '' === $value ) {
849 return $fallback;
850 }
851 $parts = explode( ' ', $value );
852 if ( count( $parts ) < 1 || count( $parts ) > 4 ) {
853 return $fallback;
854 }
855 foreach ( $parts as $part ) {
856 if ( ! preg_match( '/^-?\d+(?:\.\d+)?(?:px|rem|em|%)$/i', $part ) ) {
857 return $fallback;
858 }
859 }
860 return implode( ' ', $parts );
861 };
862
863 if ( 'custom' === $cleaned['booking_form_style'] ) {
864 if ( isset( $post_data['booking_form_custom_background_color'] ) ) {
865 $cleaned['booking_form_custom_background_color'] = $sanitize_color( $post_data['booking_form_custom_background_color'], '#ffffff' );
866 }
867 if ( isset( $post_data['booking_form_custom_border_color'] ) ) {
868 $cleaned['booking_form_custom_border_color'] = $sanitize_color( $post_data['booking_form_custom_border_color'], '#cccccc' );
869 }
870 if ( isset( $post_data['booking_form_custom_border_width'] ) ) {
871 $cleaned['booking_form_custom_border_width'] = $sanitize_length( $post_data['booking_form_custom_border_width'], '1px' );
872 }
873 if ( isset( $post_data['booking_form_custom_border_radius'] ) ) {
874 $cleaned['booking_form_custom_border_radius'] = $sanitize_length( $post_data['booking_form_custom_border_radius'], '2px' );
875 }
876 if ( isset( $post_data['booking_form_custom_padding_vertical'] ) ) {
877 $cleaned['booking_form_custom_padding_vertical'] = $sanitize_length( $post_data['booking_form_custom_padding_vertical'], '10px' );
878 }
879 if ( isset( $post_data['booking_form_custom_padding_horizontal'] ) ) {
880 $cleaned['booking_form_custom_padding_horizontal'] = $sanitize_length( $post_data['booking_form_custom_padding_horizontal'], '30px' );
881 }
882 if ( isset( $post_data['booking_form_custom_text_color'] ) ) {
883 $cleaned['booking_form_custom_text_color'] = $sanitize_color( $post_data['booking_form_custom_text_color'], '#1d2327' );
884 }
885 if ( isset( $post_data['booking_form_custom_field_background_color'] ) ) {
886 $cleaned['booking_form_custom_field_background_color'] = $sanitize_color( $post_data['booking_form_custom_field_background_color'], '#ffffff' );
887 }
888 if ( isset( $post_data['booking_form_custom_field_text_color'] ) ) {
889 $cleaned['booking_form_custom_field_text_color'] = $sanitize_color( $post_data['booking_form_custom_field_text_color'], '#3c434a' );
890 }
891 if ( isset( $post_data['booking_form_custom_field_border_color'] ) ) {
892 $cleaned['booking_form_custom_field_border_color'] = $sanitize_color( $post_data['booking_form_custom_field_border_color'], '#cccccc' );
893 }
894 if ( isset( $post_data['booking_form_custom_button_background_color'] ) ) {
895 $cleaned['booking_form_custom_button_background_color'] = $sanitize_color( $post_data['booking_form_custom_button_background_color'], '#066aab' );
896 }
897 if ( isset( $post_data['booking_form_custom_button_text_color'] ) ) {
898 $cleaned['booking_form_custom_button_text_color'] = $sanitize_color( $post_data['booking_form_custom_button_text_color'], '#ffffff' );
899 }
900 if ( isset( $post_data['booking_form_custom_button_border_color'] ) ) {
901 $cleaned['booking_form_custom_button_border_color'] = $sanitize_color( $post_data['booking_form_custom_button_border_color'], '#066aab' );
902 }
903 if ( isset( $post_data['booking_form_custom_button_hover_background_color'] ) ) {
904 $cleaned['booking_form_custom_button_hover_background_color'] = $sanitize_color( $post_data['booking_form_custom_button_hover_background_color'], '#055589' );
905 }
906 if ( isset( $post_data['booking_form_custom_button_hover_text_color'] ) ) {
907 $cleaned['booking_form_custom_button_hover_text_color'] = $sanitize_color( $post_data['booking_form_custom_button_hover_text_color'], '#ffffff' );
908 }
909 if ( isset( $post_data['booking_form_custom_button_hover_border_color'] ) ) {
910 $cleaned['booking_form_custom_button_hover_border_color'] = $sanitize_color( $post_data['booking_form_custom_button_hover_border_color'], '#055589' );
911 }
912 if ( isset( $post_data['booking_form_custom_secondary_button_background_color'] ) ) {
913 $cleaned['booking_form_custom_secondary_button_background_color'] = $sanitize_color( $post_data['booking_form_custom_secondary_button_background_color'], '#fdfdfd' );
914 }
915 if ( isset( $post_data['booking_form_custom_secondary_button_text_color'] ) ) {
916 $cleaned['booking_form_custom_secondary_button_text_color'] = $sanitize_color( $post_data['booking_form_custom_secondary_button_text_color'], '#444444' );
917 }
918 if ( isset( $post_data['booking_form_custom_secondary_button_border_color'] ) ) {
919 $cleaned['booking_form_custom_secondary_button_border_color'] = $sanitize_color( $post_data['booking_form_custom_secondary_button_border_color'], '#eeeeee' );
920 }
921 if ( isset( $post_data['booking_form_custom_secondary_button_hover_background_color'] ) ) {
922 $cleaned['booking_form_custom_secondary_button_hover_background_color'] = $sanitize_color( $post_data['booking_form_custom_secondary_button_hover_background_color'], '#fdfdfd' );
923 }
924 if ( isset( $post_data['booking_form_custom_secondary_button_hover_text_color'] ) ) {
925 $cleaned['booking_form_custom_secondary_button_hover_text_color'] = $sanitize_color( $post_data['booking_form_custom_secondary_button_hover_text_color'], '#444444' );
926 }
927 if ( isset( $post_data['booking_form_custom_secondary_button_hover_border_color'] ) ) {
928 $cleaned['booking_form_custom_secondary_button_hover_border_color'] = $sanitize_color( $post_data['booking_form_custom_secondary_button_hover_border_color'], '#4d91cd' );
929 }
930 }
931
932 if ( isset( $post_data['booking_skin'] ) ) {
933 $value = wpbc_settings_themes__normalize_calendar_skin_value( sanitize_text_field( wp_unslash( $post_data['booking_skin'] ) ) );
934 if ( array_key_exists( $value, $calendar_skin_options ) ) {
935 $cleaned['booking_skin'] = $value;
936 }
937 }
938
939 if ( isset( $post_data['booking_timeslot_picker_skin'] ) ) {
940 $value = sanitize_text_field( wp_unslash( $post_data['booking_timeslot_picker_skin'] ) );
941 if ( array_key_exists( $value, $time_skin_options ) ) {
942 $cleaned['booking_timeslot_picker_skin'] = $value;
943 }
944 }
945
946 $timeslot_picker_value = isset( $post_data['booking_timeslot_picker'] ) ? sanitize_text_field( wp_unslash( $post_data['booking_timeslot_picker'] ) ) : '';
947
948 $cleaned['booking_timeslot_picker'] = ( 'On' === $timeslot_picker_value ) ? 'On' : 'Off';
949
950 return $cleaned;
951 }
952
953 /**
954 * Update Appearance / Theme settings.
955 *
956 * @param array $cleaned_data Cleaned settings.
957 *
958 * @return void
959 */
960 function wpbc_settings_themes__update_settings( $cleaned_data ) {
961
962 update_bk_option( 'booking_form_style', $cleaned_data['booking_form_style'] );
963 update_bk_option( 'booking_form_custom_background_color', $cleaned_data['booking_form_custom_background_color'] );
964 update_bk_option( 'booking_form_custom_border_color', $cleaned_data['booking_form_custom_border_color'] );
965 update_bk_option( 'booking_form_custom_border_width', $cleaned_data['booking_form_custom_border_width'] );
966 update_bk_option( 'booking_form_custom_border_radius', $cleaned_data['booking_form_custom_border_radius'] );
967 update_bk_option( 'booking_form_custom_padding_vertical', $cleaned_data['booking_form_custom_padding_vertical'] );
968 update_bk_option( 'booking_form_custom_padding_horizontal', $cleaned_data['booking_form_custom_padding_horizontal'] );
969 update_bk_option( 'booking_form_custom_text_color', $cleaned_data['booking_form_custom_text_color'] );
970 update_bk_option( 'booking_form_custom_field_background_color', $cleaned_data['booking_form_custom_field_background_color'] );
971 update_bk_option( 'booking_form_custom_field_text_color', $cleaned_data['booking_form_custom_field_text_color'] );
972 update_bk_option( 'booking_form_custom_field_border_color', $cleaned_data['booking_form_custom_field_border_color'] );
973 update_bk_option( 'booking_form_custom_button_background_color', $cleaned_data['booking_form_custom_button_background_color'] );
974 update_bk_option( 'booking_form_custom_button_text_color', $cleaned_data['booking_form_custom_button_text_color'] );
975 update_bk_option( 'booking_form_custom_button_border_color', $cleaned_data['booking_form_custom_button_border_color'] );
976 update_bk_option( 'booking_form_custom_button_hover_background_color', $cleaned_data['booking_form_custom_button_hover_background_color'] );
977 update_bk_option( 'booking_form_custom_button_hover_text_color', $cleaned_data['booking_form_custom_button_hover_text_color'] );
978 update_bk_option( 'booking_form_custom_button_hover_border_color', $cleaned_data['booking_form_custom_button_hover_border_color'] );
979 update_bk_option( 'booking_form_custom_secondary_button_background_color', $cleaned_data['booking_form_custom_secondary_button_background_color'] );
980 update_bk_option( 'booking_form_custom_secondary_button_text_color', $cleaned_data['booking_form_custom_secondary_button_text_color'] );
981 update_bk_option( 'booking_form_custom_secondary_button_border_color', $cleaned_data['booking_form_custom_secondary_button_border_color'] );
982 update_bk_option( 'booking_form_custom_secondary_button_hover_background_color', $cleaned_data['booking_form_custom_secondary_button_hover_background_color'] );
983 update_bk_option( 'booking_form_custom_secondary_button_hover_text_color', $cleaned_data['booking_form_custom_secondary_button_hover_text_color'] );
984 update_bk_option( 'booking_form_custom_secondary_button_hover_border_color', $cleaned_data['booking_form_custom_secondary_button_hover_border_color'] );
985 update_bk_option( 'booking_skin', $cleaned_data['booking_skin'] );
986 update_bk_option( 'booking_timeslot_picker_skin', $cleaned_data['booking_timeslot_picker_skin'] );
987 update_bk_option( 'booking_timeslot_picker', $cleaned_data['booking_timeslot_picker'] );
988 }
989
990 /**
991 * Render select field.
992 *
993 * @param string $name Field name.
994 * @param array $options Options.
995 * @param string $selected Selected value.
996 * @param array $args Extra args.
997 *
998 * @return void
999 */
1000 function wpbc_settings_themes__render_select( $name, $options, $selected, $args = array() ) {
1001
1002 $args = wp_parse_args(
1003 $args,
1004 array(
1005 'id' => $name,
1006 'class' => '',
1007 'data_attrs' => array(),
1008 )
1009 );
1010
1011 $data_attrs = '';
1012 foreach ( $args['data_attrs'] as $attr_name => $attr_value ) {
1013 $data_attrs .= ' ' . esc_attr( $attr_name ) . '="' . esc_attr( $attr_value ) . '"';
1014 }
1015 ?>
1016 <select id="<?php echo esc_attr( $args['id'] ); ?>" name="<?php echo esc_attr( $name ); ?>" class="<?php echo esc_attr( $args['class'] ); ?>"<?php echo $data_attrs; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1017 <?php
1018 foreach ( $options as $option_value => $option_data ) :
1019 if ( ! is_array( $option_data ) ) {
1020 $option_data = array( 'title' => $option_data );
1021 }
1022
1023 $option_data = wp_parse_args(
1024 $option_data,
1025 array(
1026 'title' => '',
1027 'style' => '',
1028 'class' => '',
1029 'disabled' => false,
1030 'selected' => false,
1031 'attr' => array(),
1032 'optgroup' => false,
1033 'close' => false,
1034 )
1035 );
1036
1037 if ( ! empty( $option_data['optgroup'] ) ) :
1038 if ( empty( $option_data['close'] ) ) :
1039 ?>
1040 <optgroup label="<?php echo esc_attr( $option_data['title'] ); ?>">
1041 <?php
1042 else :
1043 ?>
1044 </optgroup>
1045 <?php
1046 endif;
1047 continue;
1048 endif;
1049
1050 $option_attrs = '';
1051 if ( ! empty( $option_data['attr'] ) && is_array( $option_data['attr'] ) ) {
1052 foreach ( $option_data['attr'] as $attr_name => $attr_value ) {
1053 $option_attrs .= ' ' . esc_attr( $attr_name ) . '="' . esc_attr( $attr_value ) . '"';
1054 }
1055 }
1056 ?>
1057 <option
1058 value="<?php echo esc_attr( $option_value ); ?>"
1059 <?php selected( (string) $selected, (string) $option_value ); ?>
1060 <?php selected( ! empty( $option_data['selected'] ), true ); ?>
1061 <?php disabled( ! empty( $option_data['disabled'] ), true ); ?>
1062 <?php echo ( '' !== $option_data['class'] ) ? ' class="' . esc_attr( $option_data['class'] ) . '"' : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1063 <?php echo ( '' !== $option_data['style'] ) ? ' style="' . esc_attr( $option_data['style'] ) . '"' : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1064 <?php echo $option_attrs; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1065 ><?php echo wp_kses_post( html_entity_decode( (string) $option_data['title'], ENT_QUOTES, get_bloginfo( 'charset' ) ) ); ?></option>
1066 <?php
1067 endforeach;
1068 ?>
1069 </select>
1070 <?php
1071 }
1072
1073 /**
1074 * Render booking resource calendar preview.
1075 *
1076 * @param int $resource_id Resource ID.
1077 * @param int $months_count Number of months.
1078 * @param array $preview_settings Optional settings.
1079 *
1080 * @return void
1081 */
1082 function wpbc_settings_themes__render_calendar_preview( $resource_id, $months_count, $preview_settings = array(), $preview_mode = 'calendar', $custom_booking_form = 'standard' ) {
1083
1084 global $wpbc_settings_themes__preview_options;
1085
1086 $resource_id = wpbc_settings_themes__sanitize_preview_resource_id( $resource_id );
1087 $months_count = wpbc_settings_themes__sanitize_preview_months_count( $months_count );
1088 $current_settings = wp_parse_args( $preview_settings, wpbc_settings_themes__get_settings_response() );
1089 $form_style = isset( $current_settings['booking_form_style'] ) ? wpbc_bfb_settings__sanitize_form_style( $current_settings['booking_form_style'] ) : wpbc_bfb_settings__get_default_form_style();
1090 $form_style_preset = wpbc_bfb_settings__get_form_style_preset( $form_style );
1091 $form_theme = isset( $form_style_preset['theme_class'] ) ? sanitize_html_class( (string) $form_style_preset['theme_class'] ) : '';
1092 $preview_mode = wpbc_settings_themes__sanitize_preview_mode( $preview_mode );
1093 $custom_booking_form = wpbc_settings_themes__sanitize_custom_booking_form( $custom_booking_form );
1094 $previous_preview_options = isset( $wpbc_settings_themes__preview_options ) ? $wpbc_settings_themes__preview_options : null;
1095 $wpbc_settings_themes__preview_options = wpbc_settings_themes__get_preview_option_overrides( $current_settings );
1096 ?>
1097 <div class="wpbc_theme_preview <?php echo esc_attr( $form_theme ); ?> wpbc_theme_preview_mode_<?php echo esc_attr( $preview_mode ); ?>" data-wpbc-admin-calendar-preview="1" data-wpbc-theme-preview="1" data-resource-id="<?php echo esc_attr( $resource_id ); ?>" data-months-count="<?php echo esc_attr( $months_count ); ?>" data-preview-mode="<?php echo esc_attr( $preview_mode ); ?>" data-custom-booking-form="<?php echo esc_attr( $custom_booking_form ); ?>">
1098 <div class="wpbc_theme_real_preview" data-wpbc-theme-calendar-panel="1">
1099 <?php
1100 if ( class_exists( 'WPBC_FE_Render' ) ) {
1101 if ( 'form' === $preview_mode ) {
1102 WPBC_FE_Render::render_booking_form(
1103 array(
1104 'resource_id' => $resource_id,
1105 'cal_count' => $months_count,
1106 'is_echo' => 1,
1107 'custom_booking_form' => $custom_booking_form,
1108 )
1109 );
1110 } else {
1111 WPBC_FE_Render::render_calendar_only(
1112 array(
1113 'resource_id' => $resource_id,
1114 'cal_count' => $months_count,
1115 'is_echo' => 1,
1116 )
1117 );
1118 }
1119 } elseif ( function_exists( 'wpbc__calendar__load' ) ) {
1120 echo wpbc__calendar__load( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1121 array(
1122 'resource_id' => $resource_id,
1123 'aggregate_resource_id_arr' => array(),
1124 'selected_dates_without_calendar' => '',
1125 'calendar_number_of_months' => $months_count,
1126 'start_month_calendar' => false,
1127 'shortcode_options' => '',
1128 'custom_form' => $custom_booking_form,
1129 'skip_general_availability' => 1,
1130 )
1131 );
1132 }
1133 ?>
1134 </div>
1135 </div>
1136 <?php
1137
1138 if ( null === $previous_preview_options ) {
1139 unset( $wpbc_settings_themes__preview_options );
1140 } else {
1141 $wpbc_settings_themes__preview_options = $previous_preview_options;
1142 }
1143 }
1144
1145 /**
1146 * Show Appearance / Theme save button in top toolbar.
1147 *
1148 * @param string $page_tag Current page tag.
1149 * @param string $active_page_tab Current tab.
1150 * @param string $active_page_subtab Current subtab.
1151 *
1152 * @return void
1153 */
1154 function wpbc_settings_themes__top_toolbar__show_save_button( $page_tag, $active_page_tab, $active_page_subtab ) {
1155
1156 if ( ( 'wpbc-settings' !== $page_tag ) || ( 'themes' !== $active_page_tab ) ) {
1157 return;
1158 }
1159
1160 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_themes__get_manage_cap() ) ) {
1161 return;
1162 }
1163 ?>
1164 <div class="wpbc_ui_el__buttons_group wpbc_themes__top_toolbar_group">
1165 <a href="javascript:void(0);"
1166 class="button button-primary wpbc_themes__top_btn_save"
1167 data-wpbc-theme-save="1"
1168 data-wpbc-u-busy-text="<?php esc_attr_e( 'Saving', 'booking' ); ?>...">
1169 <i class="menu_icon icon-1x wpbc-bi-check2-circle"></i>
1170 <span class="in-button-text">&nbsp;&nbsp;<?php esc_html_e( 'Save Changes', 'booking' ); ?></span>
1171 </a>
1172 </div>
1173 <?php
1174 }
1175 add_action( 'wpbc_ui_el__top_nav__content_end', 'wpbc_settings_themes__top_toolbar__show_save_button', 20, 3 );
1176
1177 /**
1178 * Block direct access for regular users in MultiUser context.
1179 *
1180 * @param bool $is_show_this_page Whether to show page.
1181 * @param string $page_tag Current page.
1182 * @param string $active_page_tab Active tab.
1183 * @param string $active_page_subtab Active subtab.
1184 *
1185 * @return bool
1186 */
1187 function wpbc_settings_themes__check_showing_page( $is_show_this_page, $page_tag, $active_page_tab, $active_page_subtab ) {
1188
1189 if ( ( 'wpbc-settings' === $page_tag ) && ( 'themes' === $active_page_tab ) && ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_themes__get_manage_cap() ) ) ) {
1190 return false;
1191 }
1192
1193 return $is_show_this_page;
1194 }
1195 add_filter( 'wpbc_before_showing_settings_page_is_show_page', 'wpbc_settings_themes__check_showing_page', 20, 4 );
1196
1197 /**
1198 * Appearance / Theme tab.
1199 */
1200 class WPBC_Page_Settings_Themes extends WPBC_Page_Structure {
1201
1202 /**
1203 * Whether settings were saved during this request.
1204 *
1205 * @var bool
1206 */
1207 private $is_updated = false;
1208
1209 /**
1210 * Menu slug.
1211 *
1212 * @return string
1213 */
1214 public function in_page() {
1215
1216 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_themes__get_manage_cap() ) ) {
1217 return (string) wp_rand( 100000, 1000000 );
1218 }
1219
1220 return 'wpbc-settings';
1221 }
1222
1223 /**
1224 * Register tab.
1225 *
1226 * @return array
1227 */
1228 public function tabs() {
1229
1230 $tabs = array();
1231
1232 $tabs['themes'] = array(
1233 'is_show_top_path' => true,
1234 'right_vertical_sidebar__is_show' => true,
1235 'right_vertical_sidebar__default_view_mode' => '',
1236 'right_vertical_sidebar_compact__is_show' => true,
1237 'left_navigation__default_view_mode' => 'compact',
1238 'top_path_title' => __( 'Appearance', 'booking' ) . ' / ' . __( 'Theme', 'booking' ),
1239 'title' => __( 'Appearance', 'booking' ) . ' / ' . __( 'Theme', 'booking' ) .
1240 '<span class="wpbc_new_label" style="margin-left: auto;">' . esc_html__( 'New', 'booking' ) . '</span>',
1241 'hint' => __( 'Preview and configure the booking form theme, calendar skin, and time slot appearance.', 'booking' ),
1242 'page_title' => __( 'Appearance', 'booking' ) . ' / ' . __( 'Theme', 'booking' ),
1243 'link' => function_exists( 'wpbc_get_settings_themes_url' ) ? wpbc_get_settings_themes_url() : admin_url( 'admin.php?page=wpbc-settings&tab=themes' ),
1244 'position' => '',
1245 'css_classes' => 'wpbc_top_tab__themes',
1246 'icon' => '',
1247 'font_icon' => 'wpbc-bi-palette-fill',
1248 'font_icon_right' => '',
1249 'default' => false,
1250 'disabled' => false,
1251 'hided' => false,
1252 'subtabs' => array(),
1253 'folder_style' => 'order:94;',
1254 );
1255
1256 return $tabs;
1257 }
1258
1259 /**
1260 * Save settings.
1261 *
1262 * @return void
1263 */
1264 public function maybe_update() {
1265
1266 $form_name = 'wpbc_settings_themes_form';
1267
1268 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1269 if ( ! isset( $_POST[ 'is_form_submitted_' . $form_name ] ) ) {
1270 return;
1271 }
1272
1273 check_admin_referer( 'wpbc_settings_page_' . $form_name );
1274
1275 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_themes__get_manage_cap() ) ) {
1276 return;
1277 }
1278
1279 $cleaned_data = wpbc_settings_themes__validate_data( $_POST ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1280 wpbc_settings_themes__update_settings( $cleaned_data );
1281
1282 $this->is_updated = true;
1283 }
1284
1285 /**
1286 * Right compact sidebar tabs.
1287 *
1288 * @return void
1289 */
1290 public function right_sidebar_compact_content() {
1291
1292 WPBC_UI_Sidebar_Panels::render_rightbar_tabs(
1293 array(
1294 array(
1295 'id' => 'wpbc_tab_theme_settings',
1296 'panel_id' => 'wpbc_theme__inspector_settings',
1297 'title' => __( 'Settings', 'booking' ),
1298 'icon' => 'wpbc_icn_tune',
1299 'selected' => true,
1300 ),
1301 array(
1302 'id' => 'wpbc_tab_theme_notes',
1303 'panel_id' => 'wpbc_theme__inspector_notes',
1304 'title' => __( 'Notes', 'booking' ),
1305 'icon' => 'wpbc-bi-info-circle',
1306 ),
1307 ),
1308 array(
1309 'aria_label' => __( 'Appearance Panels', 'booking' ),
1310 'context' => 'settings_themes',
1311 'class' => 'wpbc_theme_rightbar_tabs',
1312 )
1313 );
1314 }
1315
1316 /**
1317 * Right sidebar panels.
1318 *
1319 * @return void
1320 */
1321 public function right_sidebar_content() {
1322 ?>
1323 <div class="wpbc_bfb__panel--library wpbc_rightbar_palette wpbc_theme_rightbar_panels">
1324 <?php
1325 WPBC_UI_Sidebar_Panels::render_panel(
1326 array(
1327 'id' => 'wpbc_theme__inspector_settings',
1328 'labelledby' => 'wpbc_tab_theme_settings',
1329 'class' => 'wpbc_theme__inspector_settings',
1330 ),
1331 array( $this, 'right_panel_settings_content' )
1332 );
1333
1334 WPBC_UI_Sidebar_Panels::render_panel(
1335 array(
1336 'id' => 'wpbc_theme__inspector_notes',
1337 'labelledby' => 'wpbc_tab_theme_notes',
1338 'class' => 'wpbc_theme__inspector_notes',
1339 'hidden' => true,
1340 ),
1341 array( $this, 'right_panel_notes_content' )
1342 );
1343 ?>
1344 </div>
1345 <?php
1346 }
1347
1348 /**
1349 * Settings panel content.
1350 *
1351 * @return void
1352 */
1353 public function right_panel_settings_content() {
1354
1355 $form_name = 'wpbc_settings_themes_form';
1356 $current_settings = wpbc_settings_themes__get_settings_response();
1357 $form_style_options = wpbc_settings_themes__get_form_style_options();
1358 $calendar_skin_options = wpbc_settings_themes__get_calendar_skin_options_for_select();
1359 $time_skin_options = wpbc_settings_themes__get_time_picker_skin_options();
1360 $current_form_style = wpbc_bfb_settings__sanitize_form_style( $current_settings['booking_form_style'] );
1361 $transition_values = wpbc_settings_themes__map_form_style_to_options( $current_form_style, '' );
1362
1363 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Appearance', 'booking' ) . ' / ' . __( 'Theme', 'booking' ), __( 'Visual settings for the booking form and calendar preview.', 'booking' ) );
1364 ?>
1365 <form method="post" id="<?php echo esc_attr( $form_name ); ?>" class="wpbc_theme_settings_form" data-wpbc-theme-settings-form="1">
1366 <?php wp_nonce_field( 'wpbc_settings_page_' . $form_name ); ?>
1367 <input type="hidden" name="is_form_submitted_<?php echo esc_attr( $form_name ); ?>" value="1" />
1368 <div class="wpbc_bfb__inspector__body wpbc_theme_inspector_body">
1369 <?php
1370 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1371 array(
1372 'id' => 'wpbc_theme_form_group',
1373 'group' => 'settings-theme-form',
1374 'title' => __( 'Form Style', 'booking' ),
1375 'open' => true,
1376 ),
1377 function () use ( $form_style_options, $current_form_style, $transition_values ) {
1378 $is_custom = ( 'custom' === (string) $current_form_style );
1379 $builder_url = add_query_arg(
1380 array(
1381 'page' => 'wpbc-settings',
1382 'tab' => 'builder_booking_form',
1383 'wpbc_bfb_panel' => 'form_settings',
1384 'wpbc_bfb_group' => 'settings-appearance',
1385 'wpbc_bfb_focus' => 'booking_form_custom_background_color',
1386 ),
1387 admin_url( 'admin.php' )
1388 );
1389 ?>
1390 <input type="hidden" id="booking_form_theme" value="<?php echo esc_attr( $transition_values['booking_form_theme'] ); ?>" />
1391 <input type="hidden" id="booking_form_appearance_preset" value="<?php echo esc_attr( $transition_values['booking_form_appearance_preset'] ); ?>" data-wpbc-theme-appearance-control="1" />
1392 <div class="wpbc_theme_choice_grid wpbc_theme_style_choice_grid">
1393 <?php foreach ( $form_style_options as $style_value => $style_title ) : ?>
1394 <label class="wpbc_theme_choice <?php echo ( (string) $current_form_style === (string) $style_value ) ? 'is-selected' : ''; ?>">
1395 <input type="radio" name="booking_form_style" value="<?php echo esc_attr( $style_value ); ?>" <?php checked( (string) $current_form_style, (string) $style_value ); ?> />
1396 <span class="wpbc_theme_choice_swatch wpbc_theme_choice_swatch_<?php echo esc_attr( sanitize_html_class( $style_value ) ); ?>"></span>
1397 <span class="wpbc_theme_choice_label"><?php echo esc_html( $style_title ); ?></span>
1398 </label>
1399 <?php endforeach; ?>
1400 </div>
1401 <p class="wpbc_theme_description"><?php esc_html_e( 'Used globally by all booking forms. Dark styles can also guide matching calendar and time slot skins.', 'booking' ); ?></p>
1402 <div class="wpbc_theme_notice" data-wpbc-theme-custom-appearance-notice="1" <?php echo $is_custom ? '' : 'style="display:none;"'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1403 <p style="margin:0 0 10px 0;"><?php esc_html_e( 'Configure the global Custom style, including its container, fields, and buttons, in Forms Builder.', 'booking' ); ?></p>
1404 <a class="button button-secondary" href="<?php echo esc_url( $builder_url ); ?>">
1405 <i class="menu_icon icon-1x wpbc-bi-input-cursor-text"></i>
1406 <span><?php esc_html_e( 'Edit in Forms Builder', 'booking' ); ?></span>
1407 </a>
1408 </div>
1409 <?php
1410 }
1411 );
1412
1413 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1414 array(
1415 'id' => 'wpbc_theme_calendar_group',
1416 'group' => 'settings-theme-calendar',
1417 'title' => __( 'Calendar Skin', 'booking' ),
1418 'open' => true,
1419 ),
1420 function () use ( $calendar_skin_options, $current_settings ) {
1421 ?>
1422 <div class="wpbc_theme_field_row">
1423 <label class="wpbc_theme_field_label" for="booking_skin"><?php esc_html_e( 'Calendar Skin', 'booking' ); ?></label>
1424 <div class="wpbc_ajx_toolbar wpbc_no_borders wpbc_theme_skin_toolbar">
1425 <div class="ui_container">
1426 <div class="ui_group">
1427 <div class="ui_element ui_nowrap">
1428 <?php
1429 if ( function_exists( 'wpbc_flex_select' ) ) {
1430 wpbc_flex_select(
1431 array(
1432 'id' => 'booking_skin',
1433 'name' => 'booking_skin',
1434 'label' => '',
1435 'class' => 'js-wpbc-bfb-calendar-skin wpbc_radio__set_days_customize_plugin',
1436 'value' => $current_settings['booking_skin'],
1437 'attr' => array( 'data-wpbc-theme-calendar-skin' => '1' ),
1438 'options' => $calendar_skin_options,
1439 )
1440 );
1441 } else {
1442 wpbc_settings_themes__render_select(
1443 'booking_skin',
1444 $calendar_skin_options,
1445 $current_settings['booking_skin'],
1446 array(
1447 'id' => 'booking_skin',
1448 'class' => 'js-wpbc-bfb-calendar-skin wpbc_radio__set_days_customize_plugin',
1449 'data_attrs' => array( 'data-wpbc-theme-calendar-skin' => '1' ),
1450 )
1451 );
1452 }
1453 $is_apply_rotating_icon = false;
1454 if ( function_exists( 'wpbc_smpl_form__ui__selectbox_prior_btn' ) ) {
1455 wpbc_smpl_form__ui__selectbox_prior_btn( 'booking_skin', $is_apply_rotating_icon );
1456 }
1457 if ( function_exists( 'wpbc_smpl_form__ui__selectbox_next_btn' ) ) {
1458 wpbc_smpl_form__ui__selectbox_next_btn( 'booking_skin', $is_apply_rotating_icon );
1459 }
1460 ?>
1461 </div>
1462 </div>
1463 </div>
1464 </div>
1465 </div>
1466 <?php
1467 }
1468 );
1469
1470 WPBC_UI_Sidebar_Panels::render_collapsible_group(
1471 array(
1472 'id' => 'wpbc_theme_time_slots_group',
1473 'group' => 'settings-theme-time-slots',
1474 'title' => __( 'Time Slot Appearance', 'booking' ),
1475 'open' => false,
1476 ),
1477 function () use ( $time_skin_options, $current_settings ) {
1478 ?>
1479 <div class="wpbc_theme_field_row">
1480 <label class="wpbc_theme_field_label" for="booking_timeslot_picker_skin"><?php esc_html_e( 'Time Picker Skin', 'booking' ); ?></label>
1481 <?php
1482 wpbc_settings_themes__render_select(
1483 'booking_timeslot_picker_skin',
1484 $time_skin_options,
1485 $current_settings['booking_timeslot_picker_skin'],
1486 array(
1487 'id' => 'booking_timeslot_picker_skin',
1488 'data_attrs' => array(
1489 'data-wpbc-theme-time-skin' => '1',
1490 'data-wpbc-theme-preview-notice' => 'form',
1491 ),
1492 )
1493 );
1494 ?>
1495 </div>
1496 <label class="wpbc_theme_switch wpbc_theme_switch_card">
1497 <input type="checkbox" name="booking_timeslot_picker" value="On" data-wpbc-theme-preview-notice="form" <?php checked( $current_settings['booking_timeslot_picker'], 'On' ); ?> />
1498 <span class="wpbc_theme_switch_control" aria-hidden="true"><span class="wpbc_theme_switch_knob"></span></span>
1499 <span class="wpbc_theme_switch_label"><?php esc_html_e( 'Show time slots as a time picker instead of a select box.', 'booking' ); ?></span>
1500 </label>
1501 <?php
1502 }
1503 );
1504 ?>
1505 </div>
1506 </form>
1507 <?php
1508 }
1509
1510 /**
1511 * Notes panel content.
1512 *
1513 * @return void
1514 */
1515 public function right_panel_notes_content() {
1516
1517 WPBC_UI_Sidebar_Panels::render_inspector_header( __( 'Notes', 'booking' ), __( 'How these appearance settings are applied.', 'booking' ) );
1518 ?>
1519 <div class="wpbc_bfb__inspector__body wpbc_theme_inspector_body">
1520 <div class="wpbc_theme_notice">
1521 <strong><?php esc_html_e( 'Note', 'booking' ); ?>!</strong>
1522 <?php esc_html_e( 'These options apply to front-end booking calendars and forms. The preview uses the selected booking resource from the toolbar.', 'booking' ); ?>
1523 </div>
1524 </div>
1525 <?php
1526 }
1527
1528 /**
1529 * Show page content.
1530 *
1531 * @return void|false
1532 */
1533 public function content() {
1534
1535 do_action( 'wpbc_hook_settings_page_header', 'page_settings_themes' );
1536
1537 if ( ! wpbc_is_mu_user_can_be_here( 'only_super_admin' ) || ! current_user_can( wpbc_settings_themes__get_manage_cap() ) ) {
1538 return false;
1539 }
1540
1541 if ( function_exists( 'wpbc_js_for_bookings_page' ) ) {
1542 wpbc_js_for_bookings_page();
1543 }
1544
1545 if ( $this->is_updated ) {
1546 wpbc_show_changes_saved_message();
1547 }
1548
1549 $resource_id = wpbc_settings_themes__get_preview_resource_id();
1550 $months_count = wpbc_settings_themes__get_preview_months_count();
1551 $preview_mode = wpbc_settings_themes__get_preview_mode();
1552 $custom_booking_form = wpbc_settings_themes__get_custom_booking_form();
1553 $resources = wpbc_settings_themes__get_resources();
1554 $form_options = wpbc_settings_themes__get_booking_form_options();
1555 $is_free_version = ! class_exists( 'wpdev_bk_personal' );
1556 ?>
1557 <div class="wpbc_theme_page wpdevelop" data-wpbc-theme-page="1" data-wpbc-theme-resource-id="<?php echo esc_attr( $resource_id ); ?>">
1558 <form method="get" class="wpbc_theme_toolbar wpbc_ts_toolbar wpbc_theme_preview_controls" data-wpbc-theme-preview-toolbar="1">
1559 <input type="hidden" name="page" value="wpbc-settings" />
1560 <input type="hidden" name="tab" value="themes" />
1561 <div class="wpbc_ts_control wpbc_theme_control_resource">
1562 <label for="wpbc_theme_resource_id"><?php esc_html_e( 'Booking resource', 'booking' ); ?></label>
1563 <?php if ( $is_free_version ) : ?>
1564 <input type="hidden" id="wpbc_theme_resource_id" name="resource_id" value="<?php echo esc_attr( $resource_id ); ?>" />
1565 <div class="wpbc_theme_toolbar_value">
1566 <i class="menu_icon icon-1x wpbc-bi-calendar2-day"></i>
1567 <span><?php echo esc_html( ! empty( $resources[0]['title'] ) ? $resources[0]['title'] : __( 'Default booking resource', 'booking' ) ); ?></span>
1568 </div>
1569 <?php
1570 $resource_dismiss_id = wpbc_settings_themes__get_premium_option_dismiss_id( 'booking_resources' );
1571 if ( wpbc_settings_themes__is_dismissed_visible( $resource_dismiss_id ) ) :
1572 ?>
1573 <div id="<?php echo esc_attr( $resource_dismiss_id ); ?>" class="wpbc_theme_upgrade_hint">
1574 <a class="wpbc_pro_label" href="<?php echo esc_url( 'https://wpbookingcalendar.com/features/' ); ?>" target="_blank">Pro</a>
1575 <?php wpbc_settings_themes__render_dismiss_button( $resource_dismiss_id ); ?>
1576 <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>
1577 </div>
1578 <?php endif; ?>
1579 <?php else : ?>
1580 <select id="wpbc_theme_resource_id" name="resource_id">
1581 <?php foreach ( $resources as $resource ) : ?>
1582 <option value="<?php echo esc_attr( $resource['id'] ); ?>" <?php selected( $resource_id, (int) $resource['id'] ); ?>><?php echo esc_html( $resource['title'] ); ?></option>
1583 <?php endforeach; ?>
1584 </select>
1585 <?php endif; ?>
1586 </div>
1587 <div class="wpbc_ts_control wpbc_theme_control_months">
1588 <label for="wpbc_theme_months_count"><?php esc_html_e( 'Months', 'booking' ); ?></label>
1589 <select id="wpbc_theme_months_count" name="months_count">
1590 <?php foreach ( array( 1, 2, 3, 4, 6, 12 ) as $month_option ) : ?>
1591 <option value="<?php echo esc_attr( $month_option ); ?>" <?php selected( $months_count, $month_option ); ?>><?php echo esc_html( $month_option ); ?></option>
1592 <?php endforeach; ?>
1593 </select>
1594 </div>
1595 <div class="wpbc_ts_control wpbc_theme_control_preview_mode">
1596 <label for="wpbc_theme_preview_mode"><?php esc_html_e( 'Preview', 'booking' ); ?></label>
1597 <select id="wpbc_theme_preview_mode" name="preview_mode">
1598 <?php foreach ( wpbc_settings_themes__get_preview_mode_options() as $mode_value => $mode_title ) : ?>
1599 <option value="<?php echo esc_attr( $mode_value ); ?>" <?php selected( $preview_mode, $mode_value ); ?>><?php echo esc_html( $mode_title ); ?></option>
1600 <?php endforeach; ?>
1601 </select>
1602 </div>
1603 <div class="wpbc_ts_control wpbc_theme_control_form <?php echo ( 'form' === $preview_mode ) ? 'is-visible' : ''; ?>" data-wpbc-theme-form-control="1">
1604 <label for="wpbc_theme_custom_form"><?php esc_html_e( 'Booking Form', 'booking' ); ?></label>
1605 <select id="wpbc_theme_custom_form" name="custom_booking_form">
1606 <?php foreach ( $form_options as $form_value => $form_title ) : ?>
1607 <option value="<?php echo esc_attr( $form_value ); ?>" <?php selected( $custom_booking_form, $form_value ); ?>><?php echo esc_html( $form_title ); ?></option>
1608 <?php endforeach; ?>
1609 </select>
1610 </div>
1611 </form>
1612 <?php wpbc_settings_themes__render_calendar_preview( $resource_id, $months_count, array(), $preview_mode, $custom_booking_form ); ?>
1613 <div class="wpbc_theme_calendar_notes" data-wpbc-theme-calendar-notes="1">
1614 <div class="wpbc_ts_hint wpbc_theme_hint_bar">
1615 <span class="wpbc_icn_info_outline"></span>
1616 <?php esc_html_e( 'Preview the selected appearance settings before saving them for front-end booking forms.', 'booking' ); ?>
1617 </div>
1618 </div>
1619 </div>
1620 <?php
1621
1622 do_action( 'wpbc_hook_settings_page_footer', 'page_settings_themes' );
1623 }
1624 }
1625 add_action( 'wpbc_menu_created', array( new WPBC_Page_Settings_Themes(), '__construct' ) );
1626