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

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

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