PluginProbe
Booking Calendar / 11.2
Booking Calendar v11.2
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 10.11.2 All 203 releases
booking / includes / page-setup / setup_steps.php

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

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