PluginProbe
Booking Calendar / 11.8
Booking Calendar v11.8
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 10.11.3 All 202 releases
booking / includes / page-setup / setup_steps.php

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

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