PluginProbe
Booking Calendar / 11.7
Booking Calendar v11.7
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 10.11.2 10.11.3 10.11.4 All 201 releases
booking / includes / page-setup / setup_steps.php

setup_steps.php in Booking Calendar 11.7, at includes/page-setup/setup_steps.php

2,279 lines 79.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php /**
2 * @version 1.0
3 * @description Steps Structure for Setup Wizard Page
4 * @category Setup Class
5 * @author wpdevelop
6 *
7 * @web-site http://oplugins.com/
8 * @email info@oplugins.com
9 *
10 * @modified 2024-09-06
11 */
12
13 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
14
15
16 class WPBC_SETUP_WIZARD_STEPS {
17
18 private $steps_arr = array();
19
20 /**
21 * Whether setup route data has been initialized for this instance.
22 *
23 * The class is used both as a renderer and as an early setup-state helper. Some callers can reach it before the
24 * WordPress init hook, so route data must be available before any DB normalization or status checks run.
25 *
26 * @var bool
27 */
28 private $is_steps_data_initialized = false;
29
30 /**
31 * Whether the setup bar render hook has already been registered.
32 *
33 * This class is also used as a setup-state helper in AJAX and routing code, so multiple instances can exist during
34 * one request. Only one of them should render the floating setup bar.
35 *
36 * @var bool
37 */
38 private static $is_top_bar_hook_registered = false;
39
40 /**
41 * Whether the setup bar has already been printed in the current request.
42 *
43 * @var bool
44 */
45 private static $is_top_bar_rendered = false;
46
47 public function __construct() {
48
49 if ( WPBC()->is_wp_inited() || did_action( 'init' ) ) {
50 $this->init_steps_data();
51 } else {
52 add_action( 'init', array( $this, 'init_steps_data' ) );
53 }
54
55 if ( ! self::$is_top_bar_hook_registered ) {
56 add_action( 'wpbc_after_wpbc_page_top__header_tabs', array( $this, 'show_top_right_wizard_button' ), 10, 3 );
57 self::$is_top_bar_hook_registered = true;
58 }
59
60 }
61
62 /**
63 * Check whether translated strings can be loaded without triggering WordPress just-in-time translation notices.
64 *
65 * @return bool
66 */
67 private function is_i18n_ready() {
68
69 return ( WPBC()->is_wp_inited() || did_action( 'init' ) );
70 }
71
72
73 /**
74 * Define Steps Data Structure - Init
75 *
76 * @return void
77 */
78 public function init_steps_data(){
79
80 $is_i18n_ready = $this->is_i18n_ready();
81
82 $step_default_params = array(
83 'show_section_left' => false,
84 'show_section_right' => false,
85 'is_done' => false,
86 'do_action' => 'none',
87 'prior' => '',
88 'next' => '',
89 'prior_title' => $is_i18n_ready ? __( 'Go Back', 'booking' ) : 'Go Back',
90 'next_title' => $is_i18n_ready ? __( 'Save and Continue', 'booking' ) : 'Save and Continue'
91 );
92 $steps_arr = array();
93
94 if ( function_exists( 'wpbc_setup_wizard__get_intro_route' ) ) {
95 $route = wpbc_setup_wizard__get_intro_route();
96 } else {
97 $route = array( 'welcome' );
98 if ( ! wpbc_is_this_demo() ) {
99 $route[] = 'general_info';
100 }
101 $route[] = 'date_time_formats';
102 $route[] = 'bookings_types';
103 }
104 $route = array_merge( $route, wpbc_setup_wizard__get_profile_route() );
105
106 foreach ( $route as $step_index => $step_name ) {
107 $steps_arr[ $step_name ] = $step_default_params;
108 $steps_arr[ $step_name ]['do_action'] = 'save_and_continue__' . $step_name;
109 $steps_arr[ $step_name ]['prior'] = ( 0 === $step_index ) ? '' : $route[ $step_index - 1 ];
110 $steps_arr[ $step_name ]['next'] = isset( $route[ $step_index + 1 ] ) ? $route[ $step_index + 1 ] : 'welcome';
111
112 if ( $is_i18n_ready && function_exists( 'wpbc_setup_wizard__get_step_route_metadata' ) ) {
113 $steps_arr[ $step_name ] = array_merge(
114 $steps_arr[ $step_name ],
115 wpbc_setup_wizard__get_step_route_metadata( $step_name )
116 );
117 }
118 }
119
120 foreach ( array( 'service_provider', 'date_selection', 'changeover_days', 'working_time', 'time_slots_availability', 'date_availability', 'form_structure', 'color_theme', 'wizard_publish' ) as $continue_step_name ) {
121 if ( isset( $steps_arr[ $continue_step_name ] ) ) {
122 $steps_arr[ $continue_step_name ]['next_title'] = $is_i18n_ready ? __( 'Continue', 'booking' ) : 'Continue';
123 }
124 }
125
126 $this->steps_arr = $steps_arr;
127 $this->is_steps_data_initialized = true;
128 }
129
130 /**
131 * Ensure setup route data is available before this instance reads or normalizes step state.
132 *
133 * @return void
134 */
135 private function ensure_steps_data_initialized() {
136
137 if ( ! $this->is_steps_data_initialized ) {
138 $this->init_steps_data();
139 }
140 }
141
142 /**
143 * Get Steps Data Structure
144 * @return array
145 */
146 public function get_steps_arr(){
147 $this->ensure_steps_data_initialized();
148
149 return $this->steps_arr;
150 }
151
152
153 // =================================================================================================================
154 // == Steps STRUCTURE ==
155 // =================================================================================================================
156
157 /**
158 * Actual Step Number -> 'general_info' or 'date_availability'
159 *
160 * @return int
161 */
162 public function get_active_step_name() {
163
164 $steps_arr = $this->db__get_steps_is_done();
165
166 $first_step_name = '';
167 foreach ( $steps_arr as $step_name => $step ) {
168
169 $first_step_name = (empty($first_step_name)) ? $step_name : $first_step_name;
170
171 if ( empty( $step ) ) {
172 return $step_name;
173 }
174 }
175 return $first_step_name;
176 }
177
178
179 /**
180 * Actual Step Number -> 2
181 *
182 * @return int
183 */
184 public function get_active_step_num( $current_step = '' ) {
185
186 if ( ! empty( $current_step ) ) {
187 return $this->get_step_num_by_name( $current_step );
188 }
189
190 $steps_arr = $this->db__get_steps_is_done();
191 $total_steps = count( $steps_arr );
192 $completed_steps = 0;
193
194 foreach ( $steps_arr as $step ) {
195 if ( ! empty( $step ) ) {
196 $completed_steps++;
197 }
198 }
199
200 if ( $completed_steps >= $total_steps ) {
201 return $total_steps;
202 }
203
204 return min( $completed_steps + 1, $total_steps );
205 }
206
207 /**
208 * Get Step Number by step name.
209 *
210 * @param string $current_step Step name.
211 *
212 * @return int
213 */
214 public function get_step_num_by_name( $current_step ) {
215
216 $step_num = 1;
217
218 foreach ( array_keys( $this->get_steps_arr() ) as $step_name ) {
219 if ( $step_name === $current_step ) {
220 return $step_num;
221 }
222 $step_num++;
223 }
224
225 return 1;
226 }
227
228 /**
229 * Get the last wizard step saved in the setup wizard request history.
230 *
231 * @return string
232 */
233 public function get_saved_current_step_name() {
234
235 $steps_arr = $this->get_steps_arr();
236 $current_step = $this->get_active_step_name();
237
238 if ( function_exists( 'wpbc_setup_wizard_page__get_cleaned_params__saved_request_default' ) ) {
239 $saved_request_params = wpbc_setup_wizard_page__get_cleaned_params__saved_request_default();
240
241 if (
242 is_array( $saved_request_params )
243 && ( ! empty( $saved_request_params['current_step'] ) )
244 && isset( $steps_arr[ $saved_request_params['current_step'] ] )
245 ) {
246 $current_step = $saved_request_params['current_step'];
247 }
248 }
249
250 return $current_step;
251 }
252
253 /**
254 * Get target URL for a setup step.
255 *
256 * @param string $step_name Step name.
257 *
258 * @return string
259 */
260 public function get_step_target_url( $step_name ) {
261
262 $steps_arr = $this->get_steps_arr();
263
264 if ( isset( $steps_arr[ $step_name ]['target_url'] ) && ( ! empty( $steps_arr[ $step_name ]['target_url'] ) ) ) {
265 return $steps_arr[ $step_name ]['target_url'];
266 }
267
268 return function_exists( 'wpbc_setup_wizard__get_step_target_url' )
269 ? wpbc_setup_wizard__get_step_target_url( $step_name )
270 : wpbc_get_setup_wizard_page_url();
271 }
272
273 /**
274 * Get Continue URL for the floating setup bar.
275 *
276 * @param string $step_name Step name.
277 *
278 * @return string
279 */
280 public function get_step_continue_url( $step_name ) {
281
282 return function_exists( 'wpbc_setup_wizard__get_step_continue_url' )
283 ? wpbc_setup_wizard__get_step_continue_url( $step_name )
284 : $this->get_step_target_url( $step_name );
285 }
286
287 /**
288 * Get step name from setup URL context or first incomplete setup step.
289 *
290 * @return string
291 */
292 public function get_context_step_name() {
293
294 $steps_arr = $this->get_steps_arr();
295 $current_step = $this->get_saved_current_step_name();
296
297 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
298 if ( isset( $_REQUEST['wpbc_setup_step'] ) ) {
299 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
300 $request_step = sanitize_key( wp_unslash( $_REQUEST['wpbc_setup_step'] ) );
301 if ( isset( $steps_arr[ $request_step ] ) ) {
302 $current_step = $request_step;
303 $this->db__save_current_step_name( $current_step );
304 return $current_step;
305 }
306 }
307
308 if ( $this->db__is_step_completed( 'bookings_types' ) && function_exists( 'wpbc_setup_wizard__detect_step_from_admin_request' ) ) {
309 $detected_step = wpbc_setup_wizard__detect_step_from_admin_request();
310 if ( ! empty( $detected_step ) && isset( $steps_arr[ $detected_step ] ) ) {
311 $current_step = $detected_step;
312 $this->db__save_current_step_name( $current_step );
313 return $current_step;
314 }
315 }
316
317 return $current_step;
318 }
319
320 /**
321 * Save the current setup step into the per-user wizard request state.
322 *
323 * @param string $step_name Step name.
324 *
325 * @return bool
326 */
327 public function db__save_current_step_name( $step_name ) {
328
329 $steps_arr = $this->get_steps_arr();
330 if ( empty( $step_name ) || ! isset( $steps_arr[ $step_name ] ) || ! function_exists( 'wpbc_setup_wizard_page__request_rules_structure' ) ) {
331 return false;
332 }
333
334 $request_params_to_save = function_exists( 'wpbc_setup_wizard_page__get_cleaned_params__saved_request_default' )
335 ? wpbc_setup_wizard_page__get_cleaned_params__saved_request_default()
336 : array();
337
338 if ( ! is_array( $request_params_to_save ) || empty( $request_params_to_save ) ) {
339 $request_params_to_save = function_exists( 'wpbc_setup_wizard_page__get__request_values__default' )
340 ? wpbc_setup_wizard_page__get__request_values__default()
341 : array();
342 }
343
344 $request_params_to_save['current_step'] = $step_name;
345
346 $user_request = new WPBC_AJX__REQUEST( array(
347 'db_option_name' => 'booking_setup_wizard_page_request_params',
348 'user_id' => wpbc_get_current_user_id(),
349 'request_rules_structure' => wpbc_setup_wizard_page__request_rules_structure()
350 )
351 );
352
353 return (bool) $user_request->user_request_params__db_save( $request_params_to_save );
354 }
355
356 /**
357 * Get target URL for prior setup step.
358 *
359 * @param string $step_name Step name.
360 *
361 * @return string
362 */
363 public function get_step_prior_url( $step_name ) {
364
365 $steps_arr = $this->get_steps_arr();
366 $prior = isset( $steps_arr[ $step_name ]['prior'] ) ? $steps_arr[ $step_name ]['prior'] : '';
367
368 return ( empty( $prior ) ) ? '' : $this->get_step_target_url( $prior );
369 }
370
371 /**
372 * Get step title for setup bar.
373 *
374 * @param string $step_name Step name.
375 *
376 * @return string
377 */
378 public function get_step_title( $step_name ) {
379
380 $steps_arr = $this->get_steps_arr();
381
382 if ( isset( $steps_arr[ $step_name ]['title'] ) ) {
383 return $steps_arr[ $step_name ]['title'];
384 }
385
386 return function_exists( 'wpbc_setup_wizard__get_step_title' )
387 ? wpbc_setup_wizard__get_step_title( $step_name )
388 : $step_name;
389 }
390
391 /**
392 * Get action-oriented setup step heading.
393 *
394 * @param string $step_name Step name.
395 *
396 * @return string
397 */
398 public function get_step_heading( $step_name ) {
399
400 $steps_arr = $this->get_steps_arr();
401
402 if ( isset( $steps_arr[ $step_name ]['heading'] ) ) {
403 return $steps_arr[ $step_name ]['heading'];
404 }
405
406 return function_exists( 'wpbc_setup_wizard__get_step_heading' )
407 ? wpbc_setup_wizard__get_step_heading( $step_name )
408 : $this->get_step_title( $step_name );
409 }
410
411 /**
412 * Get setup step description.
413 *
414 * @param string $step_name Step name.
415 *
416 * @return string
417 */
418 public function get_step_description( $step_name ) {
419
420 $steps_arr = $this->get_steps_arr();
421
422 if ( isset( $steps_arr[ $step_name ]['description'] ) ) {
423 return $steps_arr[ $step_name ]['description'];
424 }
425
426 return function_exists( 'wpbc_setup_wizard__get_step_description' )
427 ? wpbc_setup_wizard__get_step_description( $step_name )
428 : '';
429 }
430
431 /**
432 * Get setup step save behavior.
433 *
434 * @param string $step_name Step name.
435 *
436 * @return string
437 */
438 public function get_step_save_behavior( $step_name ) {
439
440 $steps_arr = $this->get_steps_arr();
441
442 if ( isset( $steps_arr[ $step_name ]['save_behavior'] ) ) {
443 return $steps_arr[ $step_name ]['save_behavior'];
444 }
445
446 return function_exists( 'wpbc_setup_wizard__get_step_save_behavior' )
447 ? wpbc_setup_wizard__get_step_save_behavior( $step_name )
448 : 'link_only';
449 }
450
451 /**
452 * Get route metadata value.
453 *
454 * @param string $step_name Step name.
455 * @param string $key Metadata key.
456 *
457 * @return string
458 */
459 public function get_step_meta_value( $step_name, $key ) {
460
461 $steps_arr = $this->get_steps_arr();
462
463 return ( isset( $steps_arr[ $step_name ][ $key ] ) ) ? (string) $steps_arr[ $step_name ][ $key ] : '';
464 }
465
466
467 /**
468 * Get Steps Count -> 9
469 *
470 * @return int
471 */
472 public function get_total_steps_count(){
473
474 $steps_arr = $this->db__get_steps_is_done();
475
476 return count($steps_arr);
477 }
478
479
480 /**
481 * Get % Progress for Setup Steps -> 30
482 * @return int
483 */
484 public function get_progess_value( $current_step = '' ) {
485
486 $total_steps = $this->get_total_steps_count();
487 if ( $total_steps <= 0 ) {
488 return 0;
489 }
490
491 $progess_value = ( $this->get_active_step_num( $current_step ) * 100 ) / $total_steps;
492 $progess_value = intval( $progess_value );
493
494 return $progess_value;
495 }
496
497
498 // =================================================================================================================
499 // == DB :: "Set Wizard Steps as Done" ==
500 // =================================================================================================================
501
502 /**
503 * Get all Steps from DB and from Structure,
504 *
505 * If not saved yet to DB, then get default structure
506 *
507 * And if later Wizard structure ->init_steps_data() was extended, then system get such steps as uncompleted.
508 *
509 * @return array|mixed
510 */
511 public function db__get_steps_is_done() {
512
513 $steps_is_done = get_bk_option( 'booking_setup_wizard_page_steps_is_done' );
514 $is_completed = ( 'On' === get_bk_option( 'booking_setup_wizard_page_is_completed' ) );
515
516 $active_steps_names = array_keys( $this->get_steps_arr() );
517 $normalized_steps = array();
518
519 if ( empty( $active_steps_names ) ) {
520 return is_array( $steps_is_done ) ? $steps_is_done : array();
521 }
522
523 foreach ( $active_steps_names as $step_name ) {
524 $normalized_steps[ $step_name ] = $is_completed ? true : ( ( is_array( $steps_is_done ) && isset( $steps_is_done[ $step_name ] ) ) ? (bool) $steps_is_done[ $step_name ] : false );
525 }
526
527 if ( $steps_is_done !== $normalized_steps ) {
528 $this->db__save_steps_is_done( $normalized_steps );
529 }
530
531 return $normalized_steps;
532 }
533
534
535 /**
536 * Save statuses to all steps
537 *
538 * @param $steps_arr
539 *
540 * @return void
541 */
542 public function db__save_steps_is_done( $steps_arr ) {
543 update_bk_option( 'booking_setup_wizard_page_steps_is_done', $steps_arr );
544 }
545
546 /**
547 * Set specific step as Completed
548 *
549 * @param $step_name
550 *
551 * @return void
552 */
553 public function db__set_step_as_completed( $step_name ) {
554
555 $steps_arr = $this->db__get_steps_is_done();
556
557 $steps_arr[ $step_name ] = true;
558
559 $this->db__save_steps_is_done( $steps_arr );
560 $this->db__set_step_as_saved( $step_name, true );
561
562 if ( ! in_array( false, $steps_arr, true ) ) {
563 update_bk_option( 'booking_setup_wizard_page_is_completed', 'On' );
564 }
565 }
566
567 /**
568 * Set specific step as Uncompleted
569 *
570 * @param $step_name
571 *
572 * @return void
573 */
574 public function db__set_step_as_uncompleted( $step_name ) {
575
576 $steps_arr = $this->db__get_steps_is_done();
577
578 $steps_arr[ $step_name ] = false;
579
580 delete_bk_option( 'booking_setup_wizard_page_is_completed' );
581
582 $this->db__save_steps_is_done( $steps_arr );
583 }
584
585 /**
586 * Reset a step and all following steps in the active route.
587 *
588 * Older wizard versions could leave later steps marked as completed, which made the continue handler think setup
589 * was finished too early after Step 5.
590 *
591 * @param string $first_step_name First step to reset.
592 *
593 * @return bool
594 */
595 public function db__reset_steps_from( $first_step_name ) {
596
597 $steps_is_done = $this->db__get_steps_is_done();
598 $steps_is_saved = $this->db__get_steps_is_saved();
599 $should_reset = false;
600
601 if ( ! array_key_exists( $first_step_name, $steps_is_done ) ) {
602 return false;
603 }
604
605 foreach ( array_keys( $steps_is_done ) as $step_name ) {
606 if ( $first_step_name === $step_name ) {
607 $should_reset = true;
608 }
609
610 if ( $should_reset ) {
611 $steps_is_done[ $step_name ] = false;
612 if ( array_key_exists( $step_name, $steps_is_saved ) ) {
613 $steps_is_saved[ $step_name ] = false;
614 }
615 }
616 }
617
618 delete_bk_option( 'booking_setup_wizard_page_is_completed' );
619 $this->db__save_steps_is_done( $steps_is_done );
620 $this->db__save_steps_is_saved( $steps_is_saved );
621
622 return true;
623 }
624
625 /**
626 * Check if specific step 'Is completed' ?
627 *
628 * @param string $step_name
629 *
630 * @return bool
631 */
632 public function db__is_step_completed( $step_name ) {
633
634 $steps_arr = $this->db__get_steps_is_done();
635
636 if ( empty( $steps_arr[ $step_name ] ) ) {
637 return false;
638 } else {
639 return true;
640 }
641 }
642
643
644 /**
645 * Mark All Steps as Completed or Uncompleted
646 *
647 * @param $is_completed bool (default true)
648 *
649 * @return void
650 */
651 public function db__set_all_steps_as( $is_completed = true ) {
652
653 if ( false === $is_completed ) {
654 delete_bk_option( 'booking_setup_wizard_page_steps_is_done' );
655 delete_bk_option( 'booking_setup_wizard_page_is_completed' );
656 } else {
657 update_bk_option( 'booking_setup_wizard_page_is_completed', 'On' );
658 }
659
660 $steps_names = $this->db__get_steps_is_done();
661
662 $steps_names = array_keys( $steps_names );
663 $steps_values = array_fill( 0, count( $steps_names ), $is_completed );
664 $steps_is_done = array_combine( $steps_names, $steps_values );
665
666 // Set all steps as not completed
667 $this->db__save_steps_is_done( $steps_is_done );
668 $this->db__save_steps_is_saved( $steps_is_done );
669 }
670
671 /**
672 * Get saved state for setup steps.
673 *
674 * @return array
675 */
676 public function db__get_steps_is_saved() {
677
678 $steps_is_saved = get_bk_option( 'booking_setup_wizard_page_steps_is_saved' );
679 $is_completed = ( 'On' === get_bk_option( 'booking_setup_wizard_page_is_completed' ) );
680 $normalized = array();
681
682 foreach ( array_keys( $this->get_steps_arr() ) as $step_name ) {
683 $normalized[ $step_name ] = $is_completed ? true : ( ( is_array( $steps_is_saved ) && isset( $steps_is_saved[ $step_name ] ) ) ? (bool) $steps_is_saved[ $step_name ] : false );
684 }
685
686 if ( $steps_is_saved !== $normalized ) {
687 $this->db__save_steps_is_saved( $normalized );
688 }
689
690 return $normalized;
691 }
692
693 /**
694 * Save setup step saved states.
695 *
696 * @param array $steps_arr Saved states.
697 *
698 * @return void
699 */
700 public function db__save_steps_is_saved( $steps_arr ) {
701 update_bk_option( 'booking_setup_wizard_page_steps_is_saved', $steps_arr );
702 }
703
704 /**
705 * Mark a setup step as saved or unsaved.
706 *
707 * @param string $step_name Step name.
708 * @param bool $is_saved Saved flag.
709 *
710 * @return bool
711 */
712 public function db__set_step_as_saved( $step_name, $is_saved = true ) {
713
714 $steps_arr = $this->db__get_steps_is_saved();
715 if ( ! array_key_exists( $step_name, $steps_arr ) ) {
716 return false;
717 }
718
719 $steps_arr[ $step_name ] = (bool) $is_saved;
720 $this->db__save_steps_is_saved( $steps_arr );
721
722 return true;
723 }
724
725 /**
726 * Check whether a setup step has been saved.
727 *
728 * @param string $step_name Step name.
729 *
730 * @return bool
731 */
732 public function db__is_step_saved( $step_name ) {
733
734 if ( 'manual_save_required' !== $this->get_step_save_behavior( $step_name ) ) {
735 return true;
736 }
737
738 $steps_arr = $this->db__get_steps_is_saved();
739
740 return ! empty( $steps_arr[ $step_name ] );
741 }
742
743 /**
744 * Check Is all steps Completed
745 * @return bool
746 */
747 public function db__is_all_steps_completed() {
748
749 if ( 'On' === get_bk_option( 'booking_setup_wizard_page_is_completed' ) ) {
750 return true;
751 }
752
753 $steps_arr = $this->db__get_steps_is_done();
754
755 if ( empty( $steps_arr ) ) {
756 return false;
757 }
758
759 foreach ( $steps_arr as $step_name => $steps_val ) {
760 if ( empty( $steps_val ) ) {
761 return false;
762 }
763 }
764
765 return true;
766 }
767
768
769
770 // =================================================================================================================
771 // == C O N T E N T ==
772 // =================================================================================================================
773
774 // ----------------------------------------------------------
775 // == Left Plugin Menu --> "Setup" with Progress Bar ==
776 // ----------------------------------------------------------
777
778 /**
779 * Main Left Menu Title - "Setup" with Progress Bar
780 *
781 * @return false|string
782 */
783 public function get_plugin_menu_title__setup_progress( $current_step = '' ){
784
785
786 $current_step_for_progress = ( ! empty( $current_step ) ) ? $current_step : $this->get_context_step_name();
787
788 ob_start();
789
790 ?><div class="setup_wizard_page_container" style="display: flex;flex-flow: row wrap;justify-content: flex-start;align-items: center;color: #fff;margin: 0 -5px 0 0;overflow: visible;">
791 <div class="name_item" style="margin-top: 0;white-space: nowrap;padding: 0 0 0 0;"><?php esc_html_e( 'Setup', 'booking' ); ?></div>
792 <div style="margin:3px 0px 0 0;margin-left: auto;font-size: 9px;background: var(--wpbc_admin-theme-color, #2271b1);height: 15px;" class="wpbc_badge_count name_item update-plugins">
793 <span class="update-count" style="white-space: nowrap;word-wrap: normal;"><?php
794 echo esc_html( $this->get_active_step_num( $current_step_for_progress ) . ' / ' . $this->get_total_steps_count() );
795 ?></span>
796 </div>
797 <div class="progress_line_container" style="width: 100%;border: 0px solid #757575;height: 3px;border-radius: 6px;margin: 7px 0 -3px -3px;overflow: hidden;background: #555;">
798 <div class="progress_line" style="font-size: 6px;font-weight: 600;word-wrap: normal;border-radius: 6px;white-space: nowrap;background: #8ECE01;width: <?php
799 echo esc_html( $this->get_progess_value( $current_step_for_progress ) ); ?>%;height: 3px;"></div>
800 </div>
801 </div><?php
802
803 return ob_get_clean();
804 }
805
806 // ----------------------------------------------------------
807 // == Content Top Wizard Button ==
808 // ----------------------------------------------------------
809
810 /**
811 * Black Button at Top Right Side in WPBC plugin menu ( except Wizard page )
812 *
813 * Show Continue Setup Wizard Button
814 * @return void
815 */
816 public function show_top_right_wizard_button() {
817
818 if ( ! wpbc_is_setup_wizard_page() ) {
819 $explicit_step_context = false;
820
821 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only Setup Wizard routing context.
822 if ( isset( $_GET['wpbc_setup_step'] ) && is_scalar( $_GET['wpbc_setup_step'] ) ) {
823 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only Setup Wizard routing context.
824 $request_step = sanitize_key( wp_unslash( $_GET['wpbc_setup_step'] ) );
825 $explicit_step_context = isset( $this->steps_arr[ $request_step ] )
826 && function_exists( 'wpbc_setup_wizard_page__has_explicit_step_context' )
827 && wpbc_setup_wizard_page__has_explicit_step_context( $request_step );
828 }
829
830 if (
831 ( ! wpbc_is_user_can_access_wizard_page() ) ||
832 ( $this->db__is_all_steps_completed() && ! $explicit_step_context )
833 ) {
834 return false;
835 }
836
837 if ( self::$is_top_bar_rendered ) {
838 return false;
839 }
840 self::$is_top_bar_rendered = true;
841
842 $current_step = $this->get_context_step_name();
843 $is_external_setup_flow_started = $this->db__is_step_completed( 'bookings_types' );
844 $detected_page_step = ( $is_external_setup_flow_started && function_exists( 'wpbc_setup_wizard__detect_step_from_admin_request' ) )
845 ? wpbc_setup_wizard__detect_step_from_admin_request()
846 : '';
847 $continue_url = $this->get_step_continue_url( $current_step );
848 if ( ! empty( $detected_page_step ) && isset( $this->steps_arr[ $detected_page_step ] ) ) {
849 $continue_url = add_query_arg( 'wpbc_setup_from_page_step', $detected_page_step, $continue_url );
850 }
851 $prior_url = $this->get_step_prior_url( $current_step );
852 $step_title = $this->get_step_title( $current_step );
853 $step_heading = $this->get_step_heading( $current_step );
854 $step_save_page_title = ( 'form_structure' === $current_step ) ? __( 'Form Builder', 'booking' ) : $step_title;
855 $description = $this->get_step_description( $current_step );
856 $save_behavior = $this->get_step_save_behavior( $current_step );
857 $target_selector = $this->get_step_meta_value( $current_step, 'target_selector' );
858 $scroll_selector = $this->get_step_meta_value( $current_step, 'scroll_selector' );
859 $highlight_selector = $this->get_step_meta_value( $current_step, 'highlight_selector' );
860 $highlight_disabled = $this->get_step_meta_value( $current_step, 'highlight_disabled' );
861 $highlight_all = $this->get_step_meta_value( $current_step, 'highlight_all' );
862 $form_selector = $this->get_step_meta_value( $current_step, 'form_selector' );
863 $save_selector = $this->get_step_meta_value( $current_step, 'save_selector' );
864 $save_ajax_action = $this->get_step_meta_value( $current_step, 'save_ajax_action' );
865 $save_events = $this->get_step_meta_value( $current_step, 'save_events' );
866 $open_action = $this->get_step_meta_value( $current_step, 'open_action' );
867 $secondary_action_url = $this->get_step_meta_value( $current_step, 'secondary_action_url' );
868 $secondary_action_label = $this->get_step_meta_value( $current_step, 'secondary_action_label' );
869 $can_save_from_bar = ( 'manual_save_required' === $save_behavior && ! empty( $save_selector ) );
870 $continue_title = ( 'complete' === $save_behavior ) ? __( 'Finish Setup', 'booking' ) : __( 'Continue', 'booking' );
871 if ( $can_save_from_bar ) {
872 $continue_title = __( 'Save and Continue', 'booking' );
873 }
874 $is_step_saved = $this->db__is_step_saved( $current_step );
875 $is_step_unsaved = ( 'manual_save_required' === $save_behavior && ! $is_step_saved );
876 $is_continue_disabled = ( $is_step_unsaved && ! $can_save_from_bar );
877 $continue_href = $is_step_unsaved ? '#wpbc_setup_save_required' : $continue_url;
878 $mark_saved_nonce = wp_create_nonce( 'wpbc_setup_wizard_mark_step_saved' );
879 $step_target_url = $this->get_step_target_url( $current_step );
880 $skip_wizard_url = add_query_arg( 'wpbc_setup_wizard', 'completed', wpbc_get_bookings_url() );
881 $reset_wizard_url = add_query_arg( 'wpbc_setup_wizard', 'reset', wpbc_get_setup_wizard_page_url() );
882 $save_required_note = sprintf(
883 /* translators: %s: setup target page title. */
884 __( 'Save changes on the %s page before continuing.', 'booking' ),
885 '<a href="' . esc_url( $step_target_url ) . '">' . esc_html( $step_save_page_title ) . '</a>'
886 );
887 $test_page_links = (
888 'wizard_publish' === $current_step
889 && function_exists( 'wpbc_booking_modes_get_setup_test_page_links' )
890 ) ? wpbc_booking_modes_get_setup_test_page_links() : array();
891
892 // FixIn: 10.12.1.1.
893 ?><style type="text/css">
894 @media screen and (max-width: 782px) {
895 .ui_element.wpbc_page_top__wizard_button {
896 /*top: 49px !important;*/
897 }
898 }
899 .wp-admin.wpbc_admin_full_screen .wpbc_header_news {
900 display: none !important;
901 }
902 .wpbc_page_top__wizard_button {
903 width: auto;
904 min-width: 330px;
905 max-width: min(420px, calc(100vw - 30px));
906 position: fixed;
907 z-index: 150000;
908 box-shadow: 0 0 10px #c1c1c1;
909 border-radius: 9px;
910 background: transparent;
911 right: 15px;
912 top: auto !important;
913 bottom: 15px !important;
914 }
915 .wpbc_page_top__wizard_button.wpbc_setup_wizard_bar_is_moved {
916 left: var(--wpbc-setup-bar-left, auto) !important;
917 top: auto !important;
918 right: auto !important;
919 bottom: var(--wpbc-setup-bar-bottom, auto) !important;
920 }
921 .wpbc_page_top__wizard_button.wpbc_setup_wizard_bar_auto_shifted {
922 left: auto !important;
923 top: auto !important;
924 right: var(--wpbc-setup-bar-auto-right, 15px) !important;
925 bottom: 15px !important;
926 }
927 .wpbc_page_top__wizard_button.wpbc_setup_wizard_bar_auto_top {
928 left: auto !important;
929 top: var(--wpbc-setup-bar-auto-top, 15px) !important;
930 right: var(--wpbc-setup-bar-auto-right, 15px) !important;
931 bottom: auto !important;
932 }
933 .wpbc_page_top__wizard_button.wpbc_setup_wizard_bar_is_dragging {
934 user-select: none;
935 }
936 .wpbc_page_top__wizard_button.wpbc_setup_wizard_bar_collapsed {
937 min-width: 260px;
938 }
939 .wpbc_page_top__wizard_button.wpbc_setup_wizard_bar_collapsed .wpbc_setup_wizard_bar_expandable {
940 display: none !important;
941 }
942 div .wpbc_admin_page__tab__builder_booking_form .wpbc_page_top__wizard_button {
943 top: calc(var(--wpbc_ui_top_nav__wp_top_menu_height) + var(--wpbc_ui_top_nav__height) + 10px) !important;
944 top: auto !important;
945 }
946 .ui_element.wpbc_page_top__wizard_button .wpbc_page_top__wizard_button_content,
947 .ui_element.wpbc_page_top__wizard_button .wpbc_page_top__wizard_button_content:hover {
948 border-radius: 5px;
949 border: none;
950 background: #535353; /* #6c9e00 #0b9300;*/
951 box-shadow: 0 0 10px #dbdbdb;
952 text-shadow: none;
953 color: #fff;
954 font-weight: 600;
955 padding: 8px 10px 8px 15px;
956 display: flex;
957 flex-flow: column nowrap;
958 justify-content: flex-start;
959 align-items: stretch;
960 gap: 8px;
961 }
962 .wpbc_setup_wizard_bar_title_row {
963 display: flex;
964 flex-flow: row nowrap;
965 justify-content: flex-start;
966 align-items: center;
967 gap: 8px;
968 width: 100%;
969 border-bottom: 2px solid #686868;
970 padding-bottom: 8px;
971 margin-bottom: 10px;
972 }
973 .wpbc_setup_wizard_bar_title {
974 flex: 1 1 auto;
975 min-width: 0;
976 white-space: nowrap;
977 overflow: hidden;
978 text-overflow: ellipsis;
979 margin-top: 0;
980 padding: 0;
981 }
982 .wpbc_setup_wizard_bar_header_actions {
983 display: flex;
984 flex: 0 0 auto;
985 flex-flow: row nowrap;
986 align-items: center;
987 gap: 2px;
988 margin-left: auto;
989 }
990 .wpbc_setup_wizard_bar_icon_button {
991 display: inline-flex;
992 align-items: center;
993 justify-content: center;
994 width: 24px;
995 height: 24px;
996 min-width: 24px;
997 min-height: 24px;
998 border: 0;
999 border-radius: 4px;
1000 background: transparent;
1001 color: #fff;
1002 cursor: pointer;
1003 padding: 0;
1004 margin: 0;
1005 }
1006 .wpbc_setup_wizard_bar_icon_button:hover,
1007 .wpbc_setup_wizard_bar_icon_button:focus {
1008 background: rgba(255,255,255,0.16);
1009 color: #fff;
1010 outline: none;
1011 box-shadow: none;
1012 }
1013 .wpbc_setup_wizard_bar_drag_handle {
1014 cursor: move;
1015 }
1016 .wpbc_page_top__wizard_button_actions {
1017 display: flex;
1018 flex-flow: row nowrap;
1019 justify-content: flex-end;
1020 align-items: center;
1021 gap: 8px;
1022 }
1023 .wpbc_page_top__wizard_button_actions .button {
1024 font-size: 11px;
1025 min-height: 10px;
1026 line-height: 1.8;
1027 margin: 0;
1028 }
1029 .wpbc_page_top__wizard_button_actions .button.button-secondary {
1030 background-color: #e4e4e4;
1031 }
1032 .wpbc_setup_wizard_test_page_actions {
1033 display: flex;
1034 flex-flow: row wrap;
1035 align-items: center;
1036 gap: 8px;
1037 font-size: 11px;
1038 font-weight: 400;
1039 line-height: 1.35;
1040 }
1041 .wpbc_page_top__wizard_button[data-wpbc-setup-step="wizard_publish"] .wpbc_page_top__wizard_button_actions {
1042 flex-flow: row wrap;
1043 }
1044 .wpbc_page_top__wizard_button_actions .button.wpbc_setup_wizard_test_page_button,
1045 .wpbc_page_top__wizard_button_actions .button.wpbc_setup_wizard_test_page_button:hover,
1046 .wpbc_page_top__wizard_button_actions .button.wpbc_setup_wizard_test_page_button:focus {
1047 margin: 20px 0;
1048 background: #71a501;
1049 border-color: #71a501;
1050 color: #f0ffce;
1051 }
1052 .wpbc_page_top__wizard_button_actions .button.wpbc_setup_wizard_test_page_button:first-child {
1053 margin-right: auto;
1054 margin-left: 0;
1055 }
1056 .wpbc_page_top__wizard_button[data-wpbc-setup-step="wizard_publish"] .wpbc_page_top__wizard_button_actions.wpbc_page_top__wizard_button_links {
1057 margin: 0;
1058 gap: 10px 15px;
1059 justify-content: flex-start;
1060 }
1061 .wpbc_page_top__wizard_button_actions.wpbc_page_top__wizard_button_links .button.wpbc_setup_wizard_test_page_button:first-child,
1062 .wpbc_page_top__wizard_button[data-wpbc-setup-step="wizard_publish"] .wpbc_page_top__wizard_button_actions.wpbc_page_top__wizard_button_links a {
1063 margin: 0;
1064 flex: 0 1 auto;
1065 }
1066 .wpbc_page_top__wizard_button_actions .button.disabled,
1067 .wpbc_page_top__wizard_button_actions .button[aria-disabled="true"] {
1068 cursor: not-allowed;
1069 opacity: 0.55;
1070 pointer-events: auto;
1071 }
1072 .wpbc_page_top__wizard_button_links {
1073 display: flex;
1074 flex-flow: row wrap;
1075 justify-content: flex-start;
1076 align-items: center;
1077 gap: 1.5em;
1078 font-size: 10px;
1079 font-weight: 400;
1080 line-height: 1.4;
1081 margin-top: -2px;
1082 }
1083 .wpbc_page_top__wizard_button_links a {
1084 color: #e6e6e6;
1085 text-decoration: underline;
1086 text-underline-offset: 2px;
1087 }
1088 .wpbc_page_top__wizard_button_links a:hover,
1089 .wpbc_page_top__wizard_button_links a:focus {
1090 color: #fff;
1091 }
1092 .wpbc_page_top__wizard_button_links a.wpbc_setup_wizard_bar_danger_link {
1093 /*color: #ff9b00;*/
1094 }
1095 .wpbc_page_top__wizard_button_links a.wpbc_setup_wizard_bar_danger_link:hover,
1096 .wpbc_page_top__wizard_button_links a.wpbc_setup_wizard_bar_danger_link:focus {
1097 color: #fff;
1098 }
1099 .wpbc_page_top__wizard_button_note {
1100 font-size: 12px;
1101 font-weight: 400;
1102 line-height: 1.35;
1103 color: #fff;
1104 background: rgb(160, 160, 95);
1105 background: rgb(160, 132, 95);
1106 background: rgb(160, 116, 95);
1107 border-radius: 4px;
1108 padding: 10px 14px;
1109 margin: 8px 0 5px;
1110 }
1111 .wpbc_page_top__wizard_button_note a {
1112 color: #fff;
1113 text-decoration: underline;
1114 text-underline-offset: 2px;
1115 }
1116 .wpbc_page_top__wizard_button_note.wpbc_setup_wizard_bar_note_saved {
1117 background: #4f8f16;
1118 }
1119 .wpbc_setup_wizard_attention_pulse {
1120 animation: wpbc_setup_wizard_attention_pulse 0.62s ease-in-out 3;
1121 }
1122 @keyframes wpbc_setup_wizard_attention_pulse {
1123 0% {
1124 box-shadow: 0 0 0 0 rgba(255, 196, 0, 0.82);
1125 transform: scale(1);
1126 }
1127 50% {
1128 box-shadow: 0 0 0 7px rgba(255, 196, 0, 0.2);
1129 transform: scale(1.025);
1130 }
1131 100% {
1132 box-shadow: 0 0 0 0 rgba(255, 196, 0, 0);
1133 transform: scale(1);
1134 }
1135 }
1136 .wpbc_setup_wizard__target_highlight {
1137 outline: 2px solid #8ECE01 !important;
1138 outline-offset: 3px !important;
1139 box-shadow: 0 0 0 5px rgba(142, 206, 1, 0.16) !important;
1140 transition: outline-color 0.2s ease, box-shadow 0.2s ease;
1141 }
1142 @media screen and (max-width: 782px) {
1143 .wpbc_page_top__wizard_button {
1144 left: 10px !important;
1145 right: 10px !important;
1146 bottom: 10px !important;
1147 top: auto !important;
1148 min-width: 0;
1149 max-width: none;
1150 }
1151 .wpbc_setup_wizard_bar_drag_handle,
1152 .wpbc_setup_wizard_bar_reset_button {
1153 display: none;
1154 }
1155 }
1156 </style>
1157 <div style="top: 35px;font-size: 15px;"
1158 class="ui_element wpbc_page_top__wizard_button"
1159 data-wpbc-setup-step="<?php echo esc_attr( $current_step ); ?>"
1160 data-wpbc-setup-save-behavior="<?php echo esc_attr( $save_behavior ); ?>"
1161 data-wpbc-setup-is-saved="<?php echo esc_attr( $is_step_saved ? '1' : '0' ); ?>"
1162 data-wpbc-setup-ajax-url="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
1163 data-wpbc-setup-mark-saved-nonce="<?php echo esc_attr( $mark_saved_nonce ); ?>"
1164 data-wpbc-setup-target-selector="<?php echo esc_attr( $target_selector ); ?>"
1165 data-wpbc-setup-scroll-selector="<?php echo esc_attr( $scroll_selector ); ?>"
1166 data-wpbc-setup-highlight-selector="<?php echo esc_attr( $highlight_selector ); ?>"
1167 data-wpbc-setup-highlight-disabled="<?php echo esc_attr( $highlight_disabled ); ?>"
1168 data-wpbc-setup-highlight-all="<?php echo esc_attr( $highlight_all ); ?>"
1169 data-wpbc-setup-form-selector="<?php echo esc_attr( $form_selector ); ?>"
1170 data-wpbc-setup-save-selector="<?php echo esc_attr( $save_selector ); ?>"
1171 data-wpbc-setup-save-ajax-action="<?php echo esc_attr( $save_ajax_action ); ?>"
1172 data-wpbc-setup-save-events="<?php echo esc_attr( $save_events ); ?>"
1173 data-wpbc-setup-open-action="<?php echo esc_attr( $open_action ); ?>">
1174 <div class="wpbc_ui_control wpbc_page_top__wizard_button_content">
1175 <div class="in-button-text"
1176 style="width: 100%;margin: 0;display: flex;flex-flow: column nowrap;justify-content: flex-start;align-items: stretch;gap:8px;">
1177 <div class="setup_wizard_page_container"
1178 style="display: flex;flex-flow: row wrap;justify-content: flex-start;align-items: center;color: #fff;overflow: visible;flex: 1 1 auto;">
1179 <div class="wpbc_setup_wizard_bar_title_row">
1180 <div class="wpbc_setup_wizard_bar_header_actions">
1181 <button type="button"
1182 style="margin: -1px 5px 0 -7px;"
1183 class="wpbc_setup_wizard_bar_icon_button wpbc_setup_wizard_bar_drag_handle"
1184 title="<?php esc_attr_e( 'Move setup bar', 'booking' ); ?>"
1185 aria-label="<?php esc_attr_e( 'Move setup bar', 'booking' ); ?>">
1186 <i class="menu_icon icon-1x wpbc_icn_drag_indicator"></i>
1187 </button>
1188 </div>
1189
1190 <div class="name_item wpbc_setup_wizard_bar_title">
1191 <i style="margin-right: 4px;" class="menu_icon icon-1x wpbc_icn_donut_large wpbc_icn_adjust0"></i> <?php echo esc_html( $step_title ); ?>
1192 </div>
1193 <div class="wpbc_setup_wizard_bar_header_actions">
1194 <button type="button"
1195 class="wpbc_setup_wizard_bar_icon_button wpbc_setup_wizard_bar_reset_button"
1196 title="<?php esc_attr_e( 'Reset setup bar position', 'booking' ); ?>"
1197 aria-label="<?php esc_attr_e( 'Reset setup bar position', 'booking' ); ?>">
1198 <i class="menu_icon icon-1x wpbc_icn_rotate_90 wpbc_icn_pin_invoke"></i>
1199 </button>
1200 <button type="button"
1201 class="wpbc_setup_wizard_bar_icon_button wpbc_setup_wizard_bar_toggle_button"
1202 title="<?php esc_attr_e( 'Collapse setup bar', 'booking' ); ?>"
1203 aria-label="<?php esc_attr_e( 'Collapse setup bar', 'booking' ); ?>"
1204 aria-expanded="true">
1205 <i class="menu_icon icon-1x wpbc_icn_minimize"></i>
1206 </button>
1207 </div>
1208 </div>
1209 <div class="name_item wpbc_setup_wizard_bar_expandable" style="flex:1 1 100%;font-size:13px;font-weight:600;line-height:1.35;margin:3px 0 0;color:#f1f1f1;">
1210 <?php echo esc_html( $step_heading ); ?>
1211 </div>
1212 <?php if ( ! empty( $description ) ) { ?>
1213 <div class="name_item wpbc_setup_wizard_bar_expandable" style="flex:1 1 100%;font-size:11px;font-weight:400;line-height:1.35;margin:2px 0 0;color:#e6e6e6;">
1214 <?php echo esc_html( $description ); ?>
1215 </div>
1216 <?php } ?>
1217 <div
1218 style="margin:2px 0px 0 9px;font-size: 9px;background: #3e3e3e;height: auto;border-radius: 5px;padding: 0px 7px 0px;margin-left: auto;"
1219 class="wpbc_badge_count name_item update-plugins">
1220 <span class="update-count"
1221 style="white-space: nowrap;word-wrap: normal;"><?php echo esc_html( $this->get_active_step_num( $current_step ) . ' / ' . $this->get_total_steps_count() ); ?></span>
1222 </div>
1223
1224 <div class="progress_line_container"
1225 style="width: 100%;border: 0px solid #757575;height: 3px;border-radius: 6px;margin: 7px 0 0 0;overflow: hidden;background: #202020;">
1226 <div class="progress_line"
1227 style="font-size: 6px;font-weight: 600;border-radius: 6px;word-wrap: normal;white-space: nowrap;background: #8ECE01;width: <?php echo esc_attr( $this->get_progess_value( $current_step ) ); ?>%;height: 3px;"></div>
1228 </div>
1229 </div>
1230 <?php if ( 'manual_save_required' === $save_behavior ) { ?>
1231 <div class="wpbc_page_top__wizard_button_note wpbc_setup_wizard_bar_expandable<?php echo $is_step_saved ? ' wpbc_setup_wizard_bar_note_saved' : ''; ?>">
1232 <?php
1233 if ( $is_step_saved ) {
1234 esc_html_e( 'Changes saved. You can continue.', 'booking' );
1235 } else {
1236 echo wp_kses_post( $save_required_note );
1237 }
1238 ?>
1239 </div>
1240 <?php } ?>
1241 <?php if ( 'wizard_publish' === $current_step && empty( $test_page_links ) ) { ?>
1242 <div class="wpbc_setup_wizard_test_page_actions wpbc_setup_wizard_bar_expandable">
1243 <span><?php esc_html_e( 'No published booking page was found yet. Use QuickStart or the page publishing controls, then return to this step.', 'booking' ); ?></span>
1244 </div>
1245 <?php } ?>
1246 <?php if ( 'wizard_publish' === $current_step && ! empty( $test_page_links ) ) { ?>
1247 <div class="wpbc_page_top__wizard_button_actions wpbc_setup_wizard_bar_expandable wpbc_page_top__wizard_button_links">
1248 <?php foreach ( $test_page_links as $test_page_link ) {
1249 if ( empty( $test_page_link['url'] ) || empty( $test_page_link['label'] ) ) {
1250 continue;
1251 }
1252 ?>
1253 <a class="button button-primary secondary wpbc_setup_wizard_test_page_button"
1254 href="<?php echo esc_url( $test_page_link['url'] ); ?>"
1255 target="_blank"
1256 rel="noopener noreferrer"><?php echo esc_html( $test_page_link['label'] ); ?></a>
1257 <?php } ?>
1258 </div>
1259 <?php } ?>
1260 <div class="wpbc_page_top__wizard_button_actions wpbc_setup_wizard_bar_expandable">
1261 <?php if ( ! empty( $secondary_action_url ) && ! empty( $secondary_action_label ) ) { ?>
1262 <a class="button button-secondary wpbc_setup_wizard_secondary_action"
1263 href="<?php echo esc_url( $secondary_action_url ); ?>"><?php echo esc_html( $secondary_action_label ); ?></a>
1264 <?php } ?>
1265 <?php if ( ! empty( $prior_url ) ) { ?>
1266 <a href="<?php echo esc_url( $prior_url ); ?>" class="button button-secondary"><?php esc_html_e( 'Back', 'booking' ); ?></a>
1267 <?php } ?>
1268 <a href="<?php echo esc_url( $continue_href ); ?>"
1269 class="button button-primary wpbc_setup_wizard_continue_button<?php echo $is_continue_disabled ? ' disabled' : ''; ?>"
1270 data-wpbc-setup-continue-url="<?php echo esc_url( $continue_url ); ?>"
1271 <?php echo $is_continue_disabled ? 'aria-disabled="true"' : ''; ?>><?php echo esc_html( $continue_title ); ?></a>
1272 </div>
1273 <div class="wpbc_page_top__wizard_button_links wpbc_setup_wizard_bar_expandable">
1274 <a href="<?php echo esc_url( $skip_wizard_url ); ?>"
1275 title="<?php esc_attr_e( 'Exit and skip the setup wizard', 'booking' ); ?>">
1276 <?php esc_html_e( 'Exit and skip the setup wizard', 'booking' ); ?>
1277 </a>
1278 <a href="<?php echo esc_url( $reset_wizard_url ); ?>"
1279 class="wpbc_setup_wizard_bar_danger_link"
1280 title="<?php esc_attr_e( 'Start Setup from Beginning', 'booking' ); ?>">
1281 <?php esc_html_e( 'Reset Wizard', 'booking' ); ?>
1282 </a>
1283 </div>
1284 </div>
1285 </div>
1286 </div>
1287 <script type="text/javascript">
1288 jQuery( document ).ready( function() {
1289 var $bar = jQuery( '.wpbc_page_top__wizard_button[data-wpbc-setup-step]' ).first();
1290 var step = $bar.attr( 'data-wpbc-setup-step' ) || '';
1291 var saveBehavior = $bar.attr( 'data-wpbc-setup-save-behavior' ) || '';
1292 var selector = $bar.attr( 'data-wpbc-setup-target-selector' ) || '';
1293 var scrollSelector = $bar.attr( 'data-wpbc-setup-scroll-selector' ) || selector;
1294 var highlightSelector = $bar.attr( 'data-wpbc-setup-highlight-selector' ) || selector;
1295 var highlightDisabled = ( '1' === ( $bar.attr( 'data-wpbc-setup-highlight-disabled' ) || '' ) );
1296 var highlightAll = ( '1' === ( $bar.attr( 'data-wpbc-setup-highlight-all' ) || '' ) );
1297 var formSelector = $bar.attr( 'data-wpbc-setup-form-selector' ) || '';
1298 var saveSelector = $bar.attr( 'data-wpbc-setup-save-selector' ) || '';
1299 var saveAjaxAction = $bar.attr( 'data-wpbc-setup-save-ajax-action' ) || '';
1300 var saveEvents = ( $bar.attr( 'data-wpbc-setup-save-events' ) || '' ).split( ',' );
1301 var openAction = $bar.attr( 'data-wpbc-setup-open-action' ) || '';
1302 var ajaxUrl = $bar.attr( 'data-wpbc-setup-ajax-url' ) || '';
1303 var nonce = $bar.attr( 'data-wpbc-setup-mark-saved-nonce' ) || '';
1304 var $continueButton = $bar.find( '.wpbc_setup_wizard_continue_button' ).first();
1305 var $note = $bar.find( '.wpbc_page_top__wizard_button_note' ).first();
1306 var savedNote = '<?php echo esc_js( __( 'Changes saved. You can continue.', 'booking' ) ); ?>';
1307 var saveRequiredNote = <?php echo wp_json_encode( wp_kses_post( $save_required_note ) ); ?>;
1308 var continueTitle = <?php echo wp_json_encode( ( 'complete' === $save_behavior ) ? __( 'Finish Setup', 'booking' ) : __( 'Continue', 'booking' ) ); ?>;
1309 var saveAndContinueTitle = <?php echo wp_json_encode( __( 'Save and Continue', 'booking' ) ); ?>;
1310 var savingTitle = <?php echo wp_json_encode( __( 'Saving', 'booking' ) . '...' ); ?>;
1311 var $toggleButton = $bar.find( '.wpbc_setup_wizard_bar_toggle_button' ).first();
1312 var $toggleIcon = $toggleButton.find( 'i' ).first();
1313 var $resetButton = $bar.find( '.wpbc_setup_wizard_bar_reset_button' ).first();
1314 var $dragHandle = $bar.find( '.wpbc_setup_wizard_bar_drag_handle' ).first();
1315 var positionStorageKey = 'wpbc_setup_wizard_bar_position';
1316 var collapsedStorageKey = 'wpbc_setup_wizard_bar_collapsed';
1317 var collapseLabel = <?php echo wp_json_encode( __( 'Collapse setup bar', 'booking' ) ); ?>;
1318 var expandLabel = <?php echo wp_json_encode( __( 'Expand setup bar', 'booking' ) ); ?>;
1319 var $target;
1320 var $highlightTargets = jQuery();
1321 var saveClicked = false;
1322 var saveAndContinueRequested = false;
1323 var saveAndContinueRedirecting = false;
1324
1325 function wpbcSetupWizardStorageGet( key ) {
1326 try {
1327 return window.localStorage.getItem( key );
1328 } catch ( _e ) {
1329 return null;
1330 }
1331 }
1332
1333 function wpbcSetupWizardStorageSet( key, value ) {
1334 try {
1335 window.localStorage.setItem( key, value );
1336 } catch ( _e ) {}
1337 }
1338
1339 function wpbcSetupWizardStorageRemove( key ) {
1340 try {
1341 window.localStorage.removeItem( key );
1342 } catch ( _e ) {}
1343 }
1344
1345 function wpbcSetupWizardIsSmallViewport() {
1346 return window.matchMedia && window.matchMedia( '(max-width: 782px)' ).matches;
1347 }
1348
1349 function wpbcSetupWizardClampPosition( left, bottom ) {
1350 var margin = 10;
1351 var barWidth = $bar.outerWidth() || 330;
1352 var barHeight = $bar.outerHeight() || 120;
1353 var maxLeft = Math.max( margin, jQuery( window ).width() - barWidth - margin );
1354 var maxBottom = Math.max( margin, jQuery( window ).height() - barHeight - margin );
1355
1356 return {
1357 left: Math.min( Math.max( margin, left ), maxLeft ),
1358 bottom: Math.min( Math.max( margin, bottom ), maxBottom )
1359 };
1360 }
1361
1362 function wpbcSetupWizardApplyPosition( position ) {
1363 var clampedPosition;
1364 var positionBottom;
1365
1366 if ( wpbcSetupWizardIsSmallViewport() || ! position ) {
1367 $bar
1368 .removeClass( 'wpbc_setup_wizard_bar_is_moved' )
1369 .removeClass( 'wpbc_setup_wizard_bar_auto_shifted' )
1370 .removeClass( 'wpbc_setup_wizard_bar_auto_top' )
1371 .css( {
1372 '--wpbc-setup-bar-left': '',
1373 '--wpbc-setup-bar-bottom': '',
1374 '--wpbc-setup-bar-auto-right': '',
1375 '--wpbc-setup-bar-auto-top': ''
1376 } );
1377 return;
1378 }
1379
1380 positionBottom = parseFloat( position.bottom );
1381 if ( isNaN( positionBottom ) && ! isNaN( parseFloat( position.top ) ) ) {
1382 positionBottom = jQuery( window ).height() - parseFloat( position.top ) - ( $bar.outerHeight() || 120 );
1383 }
1384
1385 clampedPosition = wpbcSetupWizardClampPosition( parseFloat( position.left ) || 15, isNaN( positionBottom ) ? 15 : positionBottom );
1386 $bar
1387 .addClass( 'wpbc_setup_wizard_bar_is_moved' )
1388 .removeClass( 'wpbc_setup_wizard_bar_auto_shifted' )
1389 .removeClass( 'wpbc_setup_wizard_bar_auto_top' )
1390 .css( {
1391 '--wpbc-setup-bar-left': clampedPosition.left + 'px',
1392 '--wpbc-setup-bar-bottom': clampedPosition.bottom + 'px',
1393 '--wpbc-setup-bar-auto-right': '',
1394 '--wpbc-setup-bar-auto-top': ''
1395 } );
1396 }
1397
1398 function wpbcSetupWizardShouldUseTopDefault() {
1399 return -1 !== jQuery.inArray( step, [
1400 'date_selection',
1401 'changeover_days',
1402 'working_time',
1403 'time_slots_availability',
1404 'date_availability'
1405 ] );
1406 }
1407
1408 function wpbcSetupWizardGetRightSidebarOffset() {
1409 var viewportWidth = jQuery( window ).width();
1410 var viewportHeight = jQuery( window ).height();
1411 var $sidebar = jQuery();
1412 var sidebarSelectors = [
1413 '.wpbc_ui_el__vert_right_bar__wrapper',
1414 '.wpbc_ui_el__vert_right_bar',
1415 '.wpbc_ui_el__vert_right_bar__content',
1416 '.wpbc_ui_el__vert_right_bar__content .simplebar-content-wrapper'
1417 ].join( ',' );
1418
1419 jQuery( sidebarSelectors ).filter( ':visible' ).each( function() {
1420 var rect = this.getBoundingClientRect();
1421
1422 if (
1423 rect.width >= 140
1424 && rect.left > ( viewportWidth * 0.45 )
1425 && rect.right > ( viewportWidth - 80 )
1426 && rect.top < ( viewportHeight - 90 )
1427 && rect.bottom > ( viewportHeight * 0.35 )
1428 ) {
1429 $sidebar = jQuery( this );
1430 return false;
1431 }
1432 } );
1433
1434 if ( ! $sidebar.length ) {
1435 return 0;
1436 }
1437
1438 return Math.max( 0, viewportWidth - $sidebar[0].getBoundingClientRect().left + 15 );
1439 }
1440
1441 function wpbcSetupWizardApplyDefaultPosition() {
1442 var rightOffset;
1443 var maxRight;
1444 var barWidth = $bar.outerWidth() || 330;
1445
1446 if ( wpbcSetupWizardIsSmallViewport() ) {
1447 wpbcSetupWizardApplyPosition( null );
1448 return;
1449 }
1450
1451 // Clear any visible inspector while retaining the minimum offset used by the Days Availability page.
1452 rightOffset = wpbcSetupWizardGetRightSidebarOffset();
1453 if ( 'date_availability' === step ) {
1454 rightOffset = Math.max( rightOffset, 60 );
1455 }
1456 maxRight = Math.max( 15, jQuery( window ).width() - barWidth - 10 );
1457
1458 if ( wpbcSetupWizardShouldUseTopDefault() ) {
1459 $bar
1460 .removeClass( 'wpbc_setup_wizard_bar_is_moved' )
1461 .addClass( 'wpbc_setup_wizard_bar_auto_shifted' )
1462 .addClass( 'wpbc_setup_wizard_bar_auto_top' )
1463 .css( {
1464 '--wpbc-setup-bar-left': '',
1465 '--wpbc-setup-bar-bottom': '',
1466 '--wpbc-setup-bar-auto-right': Math.min( Math.max( rightOffset, 15 ), maxRight ) + 'px',
1467 '--wpbc-setup-bar-auto-top': '15px'
1468 } );
1469 return;
1470 }
1471
1472 if ( rightOffset > 15 ) {
1473 $bar
1474 .removeClass( 'wpbc_setup_wizard_bar_is_moved' )
1475 .removeClass( 'wpbc_setup_wizard_bar_auto_top' )
1476 .addClass( 'wpbc_setup_wizard_bar_auto_shifted' )
1477 .css( {
1478 '--wpbc-setup-bar-left': '',
1479 '--wpbc-setup-bar-bottom': '',
1480 '--wpbc-setup-bar-auto-right': Math.min( rightOffset, maxRight ) + 'px',
1481 '--wpbc-setup-bar-auto-top': ''
1482 } );
1483 return;
1484 }
1485
1486 wpbcSetupWizardApplyPosition( null );
1487 }
1488
1489 function wpbcSetupWizardSavePosition( left, bottom ) {
1490 var clampedPosition = wpbcSetupWizardClampPosition( left, bottom );
1491
1492 wpbcSetupWizardStorageSet( positionStorageKey, JSON.stringify( clampedPosition ) );
1493 wpbcSetupWizardApplyPosition( clampedPosition );
1494 }
1495
1496 function wpbcSetupWizardApplySavedPosition() {
1497 var savedPosition = wpbcSetupWizardStorageGet( positionStorageKey );
1498 var rightSidebarOffset;
1499 var barRect;
1500 var sidebarLeft;
1501
1502 if ( ! savedPosition ) {
1503 wpbcSetupWizardApplyDefaultPosition();
1504 return;
1505 }
1506
1507 try {
1508 wpbcSetupWizardApplyPosition( JSON.parse( savedPosition ) );
1509 } catch ( _e ) {
1510 wpbcSetupWizardStorageRemove( positionStorageKey );
1511 wpbcSetupWizardApplyDefaultPosition();
1512 return;
1513 }
1514
1515 rightSidebarOffset = wpbcSetupWizardGetRightSidebarOffset();
1516 if ( 'service_provider' === step && rightSidebarOffset > 15 ) {
1517 barRect = $bar[0].getBoundingClientRect();
1518 sidebarLeft = jQuery( window ).width() - rightSidebarOffset + 15;
1519
1520 if ( barRect.right > ( sidebarLeft - 10 ) ) {
1521 wpbcSetupWizardApplyDefaultPosition();
1522 }
1523 }
1524 }
1525
1526 function wpbcSetupWizardResetPosition() {
1527 wpbcSetupWizardStorageRemove( positionStorageKey );
1528 wpbcSetupWizardApplyDefaultPosition();
1529 }
1530
1531 function wpbcSetupWizardSetCollapsed( isCollapsed ) {
1532 $bar.toggleClass( 'wpbc_setup_wizard_bar_collapsed', !! isCollapsed );
1533 $toggleButton
1534 .attr( 'aria-expanded', isCollapsed ? 'false' : 'true' )
1535 .attr( 'title', isCollapsed ? expandLabel : collapseLabel )
1536 .attr( 'aria-label', isCollapsed ? expandLabel : collapseLabel );
1537 $toggleIcon
1538 .toggleClass( 'wpbc_icn_minimize', ! isCollapsed )
1539 .toggleClass( 'wpbc_icn_fullscreen', !! isCollapsed );
1540 wpbcSetupWizardStorageSet( collapsedStorageKey, isCollapsed ? '1' : '0' );
1541 wpbcSetupWizardApplySavedPosition();
1542 }
1543
1544 $toggleButton.on( 'click', function() {
1545 wpbcSetupWizardSetCollapsed( ! $bar.hasClass( 'wpbc_setup_wizard_bar_collapsed' ) );
1546 } );
1547
1548 $resetButton.on( 'click', function() {
1549 wpbcSetupWizardResetPosition();
1550 } );
1551
1552 $dragHandle.on( 'mousedown', function( event ) {
1553 var startX;
1554 var startY;
1555 var startLeft;
1556 var startBottom;
1557 var rect;
1558 var barHeight;
1559
1560 if ( wpbcSetupWizardIsSmallViewport() || ( event.which && 1 !== event.which ) ) {
1561 return;
1562 }
1563
1564 event.preventDefault();
1565 rect = $bar[0].getBoundingClientRect();
1566 startX = event.clientX;
1567 startY = event.clientY;
1568 startLeft = rect.left;
1569 barHeight = $bar.outerHeight() || rect.height || 120;
1570 startBottom = jQuery( window ).height() - rect.top - barHeight;
1571 $bar.addClass( 'wpbc_setup_wizard_bar_is_dragging' );
1572
1573 jQuery( document )
1574 .off( '.wpbc_setup_wizard_bar_drag' )
1575 .on( 'mousemove.wpbc_setup_wizard_bar_drag', function( moveEvent ) {
1576 wpbcSetupWizardApplyPosition( {
1577 left: startLeft + moveEvent.clientX - startX,
1578 bottom: startBottom - moveEvent.clientY + startY
1579 } );
1580 } )
1581 .on( 'mouseup.wpbc_setup_wizard_bar_drag', function( upEvent ) {
1582 var movedRect = $bar[0].getBoundingClientRect();
1583 var movedBottom = jQuery( window ).height() - movedRect.top - ( $bar.outerHeight() || movedRect.height || 120 );
1584
1585 wpbcSetupWizardSavePosition( movedRect.left, movedBottom );
1586 $bar.removeClass( 'wpbc_setup_wizard_bar_is_dragging' );
1587 jQuery( document ).off( '.wpbc_setup_wizard_bar_drag' );
1588 } );
1589 } );
1590
1591 wpbcSetupWizardSetCollapsed( '1' === wpbcSetupWizardStorageGet( collapsedStorageKey ) );
1592 wpbcSetupWizardApplySavedPosition();
1593 setTimeout( wpbcSetupWizardApplySavedPosition, 400 );
1594 setTimeout( wpbcSetupWizardApplySavedPosition, 1000 );
1595 jQuery( window ).on( 'resize.wpbc_setup_wizard_bar', wpbcSetupWizardApplySavedPosition );
1596 jQuery( document ).on( 'wpbc_setup_wizard_layout_changed.wpbc_setup_wizard_bar', wpbcSetupWizardApplySavedPosition );
1597
1598 function wpbcSetupWizardOpenPublishArea() {
1599 var currentUrl = new window.URL( window.location.href );
1600 var currentResourcesTab = currentUrl.searchParams.get( 'tab' ) || '';
1601 var isResourcesPage = 'wpbc-resources' === currentUrl.searchParams.get( 'page' )
1602 && ( '' === currentResourcesTab || 'resources' === currentResourcesTab );
1603 var catalogMount = document.getElementById( 'wpbc_catalog_booking_resources' );
1604 var publishTabSelectors = [
1605 '.wpdvlp-sub-tabs .nav-tab',
1606 '.wpdvlp-top-tabs .nav-tab',
1607 '.wpbc_settings_navigation_item a',
1608 '.wpbc_ui_el__vert_nav_item a',
1609 '[role="tab"]',
1610 '[data-tab]',
1611 '[data-subtab]'
1612 ].join( ',' );
1613 var publishToggleSelectors = [
1614 '.wpbc_resource_field__switchable a',
1615 '.wpbc_resource_field__switchable button',
1616 '.wpbc_ajx_toolbar a',
1617 '.wpbc_ajx_toolbar button',
1618 'a.button',
1619 'button.button'
1620 ].join( ',' );
1621 var publishTargetSelector = [
1622 '.wpbc_resources_table .ui_group__publish_btn:visible',
1623 '#wpbc_booking_resource_table .ui_group__publish_btn:visible',
1624 '.wpbc_resource_field__switchable.wpbc_resource_field__publish:visible',
1625 '.wpbc_resource_field__publish:visible',
1626 '.wpbc_resource_publish:visible',
1627 '.wpbc_publish_resources:visible',
1628 '[data-wpbc-resource-publish]:visible'
1629 ].join( ',' );
1630 var $publishTab;
1631 var $publishToggle;
1632
1633 if ( 'wizard_publish' !== step || ! isResourcesPage ) {
1634 return;
1635 }
1636
1637 if ( 'catalog_publish' === openAction && catalogMount ) {
1638 var catalogPublishRequested = false;
1639 /**
1640 * Open the first authorized Resource at its publishing inspector section.
1641 *
1642 * @param {CustomEvent|null} renderEvent Shared catalog render event.
1643 * @return {void}
1644 */
1645 var openCatalogPublishing = function( renderEvent ) {
1646 var catalogResponse = renderEvent && renderEvent.detail ? renderEvent.detail.response : null;
1647 var publishAction = catalogMount.querySelector( '[data-wpbc-booking-resource-action="publish_resource"][data-wpbc-booking-resource-id]' );
1648 var resourceId = publishAction ? Number( publishAction.getAttribute( 'data-wpbc-booking-resource-id' ) || 0 ) : 0;
1649
1650 if ( ! resourceId && catalogResponse && Array.isArray( catalogResponse.items ) ) {
1651 catalogResponse.items.some( function( resource ) {
1652 var isPublishAuthorized = Array.isArray( resource.action_items ) && resource.action_items.some( function( resourceAction ) {
1653 return resourceAction && 'publish_resource' === resourceAction.id;
1654 } );
1655
1656 if ( ! isPublishAuthorized ) {
1657 return false;
1658 }
1659
1660 resourceId = Number( resource.id || 0 );
1661 return 0 < resourceId;
1662 } );
1663 }
1664 if ( catalogPublishRequested || ! resourceId ) {
1665 return;
1666 }
1667
1668 catalogPublishRequested = true;
1669 catalogMount.removeEventListener( 'wpbc:ui-catalog-rendered', openCatalogPublishing );
1670
1671 // Defer until the domain catalog has completed its synchronous mount listeners.
1672 window.setTimeout( function() {
1673 var resourceActionEvent;
1674
1675 if ( 'function' === typeof window.CustomEvent ) {
1676 resourceActionEvent = new window.CustomEvent( 'wpbc:booking-resource-action', {
1677 bubbles: false,
1678 detail: {
1679 action: 'publish_resource',
1680 resource_id: resourceId,
1681 source: 'setup_wizard'
1682 }
1683 } );
1684 } else {
1685 resourceActionEvent = document.createEvent( 'CustomEvent' );
1686 resourceActionEvent.initCustomEvent( 'wpbc:booking-resource-action', false, false, {
1687 action: 'publish_resource',
1688 resource_id: resourceId,
1689 source: 'setup_wizard'
1690 } );
1691 }
1692 document.dispatchEvent( resourceActionEvent );
1693 }, 0 );
1694 };
1695
1696 catalogMount.addEventListener( 'wpbc:ui-catalog-rendered', openCatalogPublishing );
1697 openCatalogPublishing( null );
1698 return;
1699 }
1700
1701 if ( 'publish_area' !== openAction ) {
1702 return;
1703 }
1704
1705 $publishTab = jQuery( publishTabSelectors ).filter( ':visible' ).filter( function() {
1706 var $element = jQuery( this );
1707 var text = $element.text() || '';
1708 var href = $element.attr( 'href' ) || '';
1709 var dataTab = $element.attr( 'data-tab' ) || '';
1710 var dataSubtab = $element.attr( 'data-subtab' ) || '';
1711 var haystack = ( text + ' ' + href + ' ' + dataTab + ' ' + dataSubtab ).toLowerCase();
1712
1713 if ( $element.closest( '.wpbc_page_top__wizard_button' ).length ) {
1714 return false;
1715 }
1716
1717 return (
1718 -1 !== haystack.indexOf( 'publish' )
1719 || -1 !== haystack.indexOf( 'shortcode' )
1720 || -1 !== haystack.indexOf( 'embed' )
1721 );
1722 } ).first();
1723
1724 if ( $publishTab.length && ! $publishTab.hasClass( 'nav-tab-active' ) && ! $publishTab.parent().hasClass( 'active' ) ) {
1725 $publishTab.trigger( 'click' );
1726 }
1727
1728 if ( ! $publishTab.length ) {
1729 $publishToggle = jQuery( publishToggleSelectors ).filter( ':visible' ).filter( function() {
1730 var $element = jQuery( this );
1731 var text = $element.text() || '';
1732 var title = $element.attr( 'title' ) || $element.attr( 'data-original-title' ) || '';
1733 var onclick = $element.attr( 'onclick' ) || '';
1734 var className = $element.attr( 'class' ) || '';
1735 var haystack = ( text + ' ' + title + ' ' + className ).toLowerCase();
1736
1737 if ( $element.closest( '.wpbc_page_top__wizard_button' ).length ) {
1738 return false;
1739 }
1740
1741 if ( -1 !== onclick.indexOf( 'wpbc_modal_dialog__show__resource_publish' ) ) {
1742 return false;
1743 }
1744
1745 return (
1746 -1 !== haystack.indexOf( 'show publish' )
1747 || -1 !== haystack.indexOf( 'publish option' )
1748 || -1 !== haystack.indexOf( 'shortcode' )
1749 || -1 !== haystack.indexOf( 'resource_field__publish' )
1750 );
1751 } ).first();
1752
1753 if ( $publishToggle.length ) {
1754 $publishToggle.trigger( 'click' );
1755 }
1756 }
1757
1758 setTimeout( function() {
1759 var $publishTarget = jQuery( publishTargetSelector ).first();
1760
1761 if ( ! $publishTarget.length ) {
1762 $publishTarget = jQuery( selector ).filter( ':visible' ).first();
1763 }
1764
1765 if ( ! $publishTarget.length ) {
1766 return;
1767 }
1768
1769 if ( typeof wpbc_scroll_to === 'function' ) {
1770 wpbc_scroll_to( $publishTarget );
1771 } else if ( $publishTarget.offset() ) {
1772 jQuery( 'html, body' ).animate( { scrollTop: $publishTarget.offset().top - 80 }, 300 );
1773 }
1774
1775 if ( typeof wpbc_blink_element === 'function' ) {
1776 wpbc_blink_element( $publishTarget, 3, 300 );
1777 }
1778 }, 450 );
1779 }
1780
1781 wpbcSetupWizardOpenPublishArea();
1782
1783 function wpbcSetupWizardGetFirstElement( selectors ) {
1784 var $element = jQuery();
1785
1786 if ( ! selectors ) {
1787 return $element;
1788 }
1789
1790 try {
1791 $element = jQuery( selectors ).filter( ':visible' ).first();
1792 if ( $element.length ) {
1793 return $element;
1794 }
1795 return jQuery( selectors ).first();
1796 } catch ( _e ) {
1797 return jQuery();
1798 }
1799 }
1800
1801 function wpbcSetupWizardGetScrollableParent( $element ) {
1802 var $scrollParent;
1803
1804 if ( ! $element || ! $element.length ) {
1805 return jQuery();
1806 }
1807
1808 $scrollParent = $element.parents().filter( function() {
1809 var $parent = jQuery( this );
1810 var overflowY = $parent.css( 'overflow-y' );
1811
1812 return (
1813 /(auto|scroll)/.test( overflowY )
1814 && this.scrollHeight > Math.ceil( $parent.innerHeight() ) + 5
1815 );
1816 } ).first();
1817
1818 return $scrollParent;
1819 }
1820
1821 function wpbcSetupWizardScrollToElement( $element ) {
1822 var $scrollParent;
1823 var targetTop;
1824
1825 if ( ! $element || ! $element.length || ! $element.offset() ) {
1826 return;
1827 }
1828
1829 $scrollParent = wpbcSetupWizardGetScrollableParent( $element );
1830 if ( $scrollParent.length && ! $scrollParent.is( 'html, body' ) ) {
1831 targetTop = $element.offset().top - $scrollParent.offset().top + $scrollParent.scrollTop() - 40;
1832 $scrollParent.stop().animate( {
1833 scrollTop: Math.max( 0, targetTop )
1834 }, 350 );
1835 return;
1836 }
1837
1838 if ( typeof wpbc_scroll_to === 'function' ) {
1839 wpbc_scroll_to( $element );
1840 } else {
1841 jQuery( 'html, body' ).stop().animate( {
1842 scrollTop: Math.max( 0, $element.offset().top - 90 )
1843 }, 350 );
1844 }
1845 }
1846
1847 function wpbcSetupWizardHighlightElement( $element ) {
1848 if ( ! $element || ! $element.length ) {
1849 return;
1850 }
1851
1852 $element.addClass( 'wpbc_setup_wizard__target_highlight' );
1853 if ( typeof wpbc_blink_element === 'function' ) {
1854 wpbc_blink_element( $element, 3, 300 );
1855 }
1856 }
1857
1858 function wpbcSetupWizardPulseElement( $element ) {
1859 if ( ! $element || ! $element.length ) {
1860 return;
1861 }
1862
1863 $element
1864 .removeClass( 'wpbc_setup_wizard_attention_pulse' )
1865 .each( function() {
1866 // Restart the CSS animation when the user clicks Continue repeatedly.
1867 void this.offsetWidth;
1868 } )
1869 .addClass( 'wpbc_setup_wizard_attention_pulse' );
1870
1871 setTimeout( function() {
1872 $element.removeClass( 'wpbc_setup_wizard_attention_pulse' );
1873 }, 2100 );
1874 }
1875
1876 function wpbcSetupWizardPulseSaveRequiredMessage() {
1877 if ( $bar.hasClass( 'wpbc_setup_wizard_bar_collapsed' ) ) {
1878 wpbcSetupWizardSetCollapsed( false );
1879 }
1880
1881 if ( $note.length ) {
1882 wpbcSetupWizardPulseElement( $note );
1883 }
1884
1885 setTimeout( function() {
1886 wpbcSetupWizardPulseElement( jQuery( '#ajax_working .wpbc_inner_message.notice-warning' ).last() );
1887 }, 50 );
1888 }
1889
1890 function wpbcSetupWizardSetSaved() {
1891 $bar.attr( 'data-wpbc-setup-is-saved', '1' );
1892 $continueButton
1893 .removeClass( 'disabled' )
1894 .removeAttr( 'aria-disabled' )
1895 .attr( 'href', $continueButton.attr( 'data-wpbc-setup-continue-url' ) || '#' )
1896 .text( continueTitle );
1897 if ( $note.length ) {
1898 $note
1899 .addClass( 'wpbc_setup_wizard_bar_note_saved' )
1900 .text( savedNote );
1901 }
1902 }
1903
1904 function wpbcSetupWizardSetUnsaved() {
1905 $bar.attr( 'data-wpbc-setup-is-saved', '0' );
1906 $continueButton.attr( 'href', '#wpbc_setup_save_required' ).text( saveSelector ? saveAndContinueTitle : continueTitle );
1907 if ( saveSelector ) {
1908 $continueButton.removeClass( 'disabled' ).removeAttr( 'aria-disabled' );
1909 } else {
1910 $continueButton.addClass( 'disabled' ).attr( 'aria-disabled', 'true' );
1911 }
1912 if ( $note.length ) {
1913 $note
1914 .removeClass( 'wpbc_setup_wizard_bar_note_saved' )
1915 .html( saveRequiredNote );
1916 }
1917 }
1918
1919 function wpbcSetupWizardSetSaveAndContinueBusy( isBusy ) {
1920 if ( ! saveSelector ) {
1921 return;
1922 }
1923
1924 $continueButton.toggleClass( 'disabled', !! isBusy ).text( isBusy ? savingTitle : saveAndContinueTitle );
1925 if ( isBusy ) {
1926 $continueButton.attr( 'aria-disabled', 'true' );
1927 } else {
1928 $continueButton.removeAttr( 'aria-disabled' );
1929 }
1930 }
1931
1932 function wpbcSetupWizardGetContinueUrl() {
1933 return $continueButton.attr( 'data-wpbc-setup-continue-url' ) || $continueButton.attr( 'href' ) || '';
1934 }
1935
1936 function wpbcSetupWizardContinueAfterSave() {
1937 var continueUrl;
1938
1939 if ( saveAndContinueRedirecting ) {
1940 return;
1941 }
1942
1943 continueUrl = wpbcSetupWizardGetContinueUrl();
1944 if ( ! continueUrl || '#wpbc_setup_save_required' === continueUrl ) {
1945 wpbcSetupWizardSetSaveAndContinueBusy( false );
1946 return;
1947 }
1948
1949 saveAndContinueRedirecting = true;
1950 window.location.href = continueUrl;
1951 }
1952
1953 function wpbcSetupWizardMarkSaved( afterSavedCallback ) {
1954 if ( ! step || ! ajaxUrl || ! nonce ) {
1955 wpbcSetupWizardSetSaved();
1956 if ( 'function' === typeof afterSavedCallback ) {
1957 afterSavedCallback();
1958 }
1959 return;
1960 }
1961
1962 jQuery.post( ajaxUrl, {
1963 action: 'WPBC_AJX_SETUP_WIZARD_MARK_STEP_SAVED',
1964 nonce: nonce,
1965 wpbc_setup_step: step
1966 } ).done( function( response ) {
1967 if ( 'string' === typeof response ) {
1968 try {
1969 response = JSON.parse( response );
1970 } catch ( _e ) {}
1971 }
1972 if ( response && response.success ) {
1973 wpbcSetupWizardSetSaved();
1974 if ( 'function' === typeof afterSavedCallback ) {
1975 afterSavedCallback();
1976 }
1977 }
1978 } ).fail( function() {
1979 if ( saveAndContinueRequested ) {
1980 wpbcSetupWizardSetSaveAndContinueBusy( false );
1981 saveAndContinueRequested = false;
1982 }
1983 } );
1984 }
1985
1986 function wpbcSetupWizardSaveStarted() {
1987 saveClicked = true;
1988 }
1989
1990 function wpbcSetupWizardLooksSuccessfulResponse( response ) {
1991 if ( ! response ) {
1992 return false;
1993 }
1994
1995 return (
1996 !! response.success
1997 || 'success' === response.status
1998 || '1' === String( response.ajx_after_action_result || '' )
1999 || ( response.ajx_data && '1' === String( response.ajx_data.ajx_after_action_result || '' ) )
2000 || ( response.data && response.data.setup_step_saved )
2001 );
2002 }
2003
2004 function wpbcSetupWizardGetAjaxAction( ajaxSettings ) {
2005 var data = ajaxSettings && ajaxSettings.data ? ajaxSettings.data : '';
2006 var matches;
2007
2008 if ( ! data ) {
2009 return '';
2010 }
2011
2012 if ( 'string' === typeof data ) {
2013 matches = data.match( /(?:^|&)action=([^&]+)/ );
2014 return matches && matches[1] ? decodeURIComponent( matches[1].replace( /\+/g, ' ' ) ) : '';
2015 }
2016
2017 if ( window.FormData && data instanceof window.FormData && 'function' === typeof data.get ) {
2018 return data.get( 'action' ) || '';
2019 }
2020
2021 if ( 'object' === typeof data && data.action ) {
2022 return data.action;
2023 }
2024
2025 return '';
2026 }
2027
2028 function wpbcSetupWizardIsExpectedSaveAjax( ajaxSettings ) {
2029 var ajaxAction;
2030
2031 if ( ! saveAjaxAction ) {
2032 return true;
2033 }
2034
2035 ajaxAction = wpbcSetupWizardGetAjaxAction( ajaxSettings );
2036
2037 return saveAjaxAction === ajaxAction;
2038 }
2039
2040 function wpbcSetupWizardHandleSavedEvent() {
2041 saveClicked = false;
2042 wpbcSetupWizardSetSaved();
2043 if ( saveAndContinueRequested ) {
2044 wpbcSetupWizardMarkSaved( wpbcSetupWizardContinueAfterSave );
2045 return;
2046 }
2047 wpbcSetupWizardMarkSaved();
2048 }
2049
2050 function wpbcSetupWizardRegisterSavedEvent( eventName ) {
2051 eventName = ( eventName || '' ).replace( /^\s+|\s+$/g, '' );
2052 if ( ! eventName ) {
2053 return;
2054 }
2055
2056 document.addEventListener( eventName, wpbcSetupWizardHandleSavedEvent, true );
2057 jQuery( document ).on( eventName + '.wpbc_setup_wizard', wpbcSetupWizardHandleSavedEvent );
2058 }
2059
2060 function wpbcSetupWizardFindSaveControl() {
2061 var $saveControl = wpbcSetupWizardGetFirstElement( saveSelector );
2062
2063 if ( $saveControl.length ) {
2064 return $saveControl;
2065 }
2066
2067 if ( ! formSelector ) {
2068 return jQuery();
2069 }
2070
2071 return wpbcSetupWizardGetFirstElement(
2072 formSelector + ' button[type="submit"],' +
2073 formSelector + ' input[type="submit"],' +
2074 formSelector + ' .wpbc_submit_button_trigger,' +
2075 formSelector + ' .wpbc_submit_button'
2076 );
2077 }
2078
2079 function wpbcSetupWizardTriggerSaveAndContinue() {
2080 var $saveControl = wpbcSetupWizardFindSaveControl();
2081
2082 if ( saveAndContinueRequested ) {
2083 return;
2084 }
2085
2086 if ( ! $saveControl.length || $saveControl.hasClass( 'disabled' ) || 'true' === $saveControl.attr( 'aria-disabled' ) ) {
2087 if ( typeof wpbc_admin_show_message === 'function' ) {
2088 wpbc_admin_show_message( '<?php echo esc_js( __( 'Please save changes on this page before continuing setup.', 'booking' ) ); ?>', 'warning', 4000, false );
2089 }
2090 wpbcSetupWizardPulseSaveRequiredMessage();
2091 return;
2092 }
2093
2094 saveAndContinueRequested = true;
2095 wpbcSetupWizardSaveStarted();
2096 wpbcSetupWizardSetSaveAndContinueBusy( true );
2097 if ( formSelector ) {
2098 jQuery( formSelector ).find( 'input[name="wpbc_setup_continue_after_save"]' ).val( '1' );
2099 }
2100 $saveControl.trigger( 'click' );
2101 }
2102
2103 if ( 'manual_save_required' === saveBehavior ) {
2104 window.wpbc_setup_wizard_set_current_step_saved = wpbcSetupWizardSetSaved;
2105 window.wpbc_setup_wizard_mark_current_step_saved = wpbcSetupWizardMarkSaved;
2106
2107 document.addEventListener( 'wpbc:bfb:form:before_save_payload', function( event ) {
2108 if ( ! event || ! event.detail || ! event.detail.payload || ! step ) {
2109 return;
2110 }
2111 wpbcSetupWizardSaveStarted();
2112 event.detail.payload.wpbc_setup = '1';
2113 event.detail.payload.wpbc_setup_step = step;
2114 if ( saveAndContinueRequested ) {
2115 event.detail.payload.wpbc_setup_continue_after_save = '1';
2116 }
2117 }, true );
2118
2119 saveEvents.forEach( wpbcSetupWizardRegisterSavedEvent );
2120
2121 if ( formSelector ) {
2122 jQuery( formSelector ).each( function() {
2123 var $form = jQuery( this );
2124 if ( ! $form.is( 'form' ) ) {
2125 return;
2126 }
2127 if ( ! $form.find( 'input[name="wpbc_setup_saved_step"]' ).length ) {
2128 $form.append( '<input type="hidden" name="wpbc_setup_saved_step" value="" />' );
2129 }
2130 if ( ! $form.find( 'input[name="wpbc_setup_step"]' ).length ) {
2131 $form.append( '<input type="hidden" name="wpbc_setup_step" value="" />' );
2132 }
2133 if ( ! $form.find( 'input[name="wpbc_setup"]' ).length ) {
2134 $form.append( '<input type="hidden" name="wpbc_setup" value="" />' );
2135 }
2136 if ( ! $form.find( 'input[name="wpbc_setup_continue_after_save"]' ).length ) {
2137 $form.append( '<input type="hidden" name="wpbc_setup_continue_after_save" value="" />' );
2138 }
2139 $form.find( 'input[name="wpbc_setup_saved_step"]' ).val( step );
2140 $form.find( 'input[name="wpbc_setup_step"]' ).val( step );
2141 $form.find( 'input[name="wpbc_setup"]' ).val( '1' );
2142 $form.find( 'input[name="wpbc_setup_continue_after_save"]' ).val( '0' );
2143 $form
2144 .off( 'change.wpbc_setup_wizard input.wpbc_setup_wizard', ':input' )
2145 .on( 'change.wpbc_setup_wizard input.wpbc_setup_wizard', ':input', function() {
2146 if ( jQuery( this ).is( '[name="wpbc_setup_saved_step"],[name="wpbc_setup_step"],[name="wpbc_setup"],[name="wpbc_setup_continue_after_save"],[name="form_visible_section"]' ) ) {
2147 return;
2148 }
2149 wpbcSetupWizardSetUnsaved();
2150 } );
2151 $form
2152 .off( 'submit.wpbc_setup_wizard' )
2153 .on( 'submit.wpbc_setup_wizard', function() {
2154 wpbcSetupWizardSaveStarted();
2155 $form.find( 'input[name="wpbc_setup_saved_step"]' ).val( step );
2156 $form.find( 'input[name="wpbc_setup_step"]' ).val( step );
2157 $form.find( 'input[name="wpbc_setup"]' ).val( '1' );
2158 $form.find( 'input[name="wpbc_setup_continue_after_save"]' ).val( saveAndContinueRequested ? '1' : '0' );
2159 } );
2160 } );
2161 }
2162
2163 $continueButton.on( 'click', function( event ) {
2164 if ( '1' !== $bar.attr( 'data-wpbc-setup-is-saved' ) ) {
2165 event.preventDefault();
2166 if ( saveSelector ) {
2167 wpbcSetupWizardTriggerSaveAndContinue();
2168 return;
2169 }
2170 if ( typeof wpbc_admin_show_message === 'function' ) {
2171 wpbc_admin_show_message( '<?php echo esc_js( __( 'Please save changes on this page before continuing setup.', 'booking' ) ); ?>', 'warning', 4000, false );
2172 }
2173 wpbcSetupWizardPulseSaveRequiredMessage();
2174 }
2175 } );
2176
2177 if ( saveSelector ) {
2178 jQuery( document )
2179 .on( 'mousedown.wpbc_setup_wizard click.wpbc_setup_wizard', saveSelector, wpbcSetupWizardSaveStarted )
2180 .on( 'keydown.wpbc_setup_wizard', saveSelector, function( event ) {
2181 if ( 13 === event.which || 32 === event.which ) {
2182 wpbcSetupWizardSaveStarted();
2183 }
2184 } );
2185 }
2186
2187 jQuery( document ).ajaxComplete( function( _event, xhr, ajaxSettings ) {
2188 var response;
2189 if ( ! saveClicked ) {
2190 return;
2191 }
2192 if ( ! wpbcSetupWizardIsExpectedSaveAjax( ajaxSettings ) ) {
2193 return;
2194 }
2195 saveClicked = false;
2196
2197 response = xhr && xhr.responseJSON ? xhr.responseJSON : null;
2198 if ( ! response && xhr && xhr.responseText ) {
2199 try {
2200 response = JSON.parse( xhr.responseText );
2201 } catch ( _e ) {}
2202 }
2203 if ( response && response.data && response.data.setup_step_saved ) {
2204 wpbcSetupWizardSetSaved();
2205 if ( saveAndContinueRequested ) {
2206 wpbcSetupWizardContinueAfterSave();
2207 }
2208 } else if ( wpbcSetupWizardLooksSuccessfulResponse( response ) ) {
2209 if ( saveAndContinueRequested ) {
2210 wpbcSetupWizardMarkSaved( wpbcSetupWizardContinueAfterSave );
2211 } else {
2212 wpbcSetupWizardMarkSaved();
2213 }
2214 } else if ( saveAndContinueRequested ) {
2215 wpbcSetupWizardSetSaveAndContinueBusy( false );
2216 saveAndContinueRequested = false;
2217 }
2218 } );
2219 }
2220
2221 if ( highlightDisabled ) {
2222 highlightSelector = '';
2223 }
2224
2225 if ( ! selector && ! scrollSelector && ! highlightSelector ) {
2226 return;
2227 }
2228
2229 if ( ! highlightDisabled && highlightAll ) {
2230 try {
2231 $highlightTargets = jQuery( highlightSelector || selector ).filter( ':visible' );
2232 } catch ( _e ) {
2233 $highlightTargets = jQuery();
2234 }
2235
2236 $highlightTargets.each( function() {
2237 wpbcSetupWizardHighlightElement( jQuery( this ) );
2238 } );
2239 } else if ( ! highlightDisabled ) {
2240 $highlightTargets = wpbcSetupWizardGetFirstElement( highlightSelector || selector );
2241 wpbcSetupWizardHighlightElement( $highlightTargets );
2242 }
2243
2244 $target = $highlightTargets.first();
2245
2246 setTimeout( function() {
2247 var $scrollTarget = wpbcSetupWizardGetFirstElement( scrollSelector || ( highlightDisabled ? selector : highlightSelector ) || selector );
2248 if ( ! $scrollTarget.length ) {
2249 $scrollTarget = $target;
2250 }
2251 wpbcSetupWizardScrollToElement( $scrollTarget );
2252 }, 250 );
2253 } );
2254 </script><?php
2255 }
2256 }
2257
2258 }
2259 function wpbc_init_setup_wizard(){
2260 $setup_steps = new WPBC_SETUP_WIZARD_STEPS();
2261 }
2262 // $setup_steps = new WPBC_SETUP_WIZARD_STEPS();
2263 add_action( 'init', 'wpbc_init_setup_wizard' );
2264
2265
2266
2267 /**
2268 * On plugin activation set all steps as completed in Live Demos
2269 * @return void
2270 */
2271 function wpbc_booking_activate_plugin__wizard() {
2272 if ( wpbc_is_this_demo() ) {
2273 $setup_steps = new WPBC_SETUP_WIZARD_STEPS();
2274 $is_completed = true;
2275 $setup_steps->db__set_all_steps_as( $is_completed );
2276 }
2277 }
2278 add_bk_action( 'wpbc_other_versions_activation', 'wpbc_booking_activate_plugin__wizard' );
2279