is_wp_inited() || did_action( 'init' ) ) { $this->init_steps_data(); } else { add_action( 'init', array( $this, 'init_steps_data' ) ); } if ( self::is_floating_setup_bar_enabled() && ! self::$is_top_bar_hook_registered ) { add_action( 'wpbc_after_wpbc_page_top__header_tabs', array( $this, 'show_top_right_wizard_button' ), 10, 3 ); self::$is_top_bar_hook_registered = true; } } /** * Check whether translated strings can be loaded without triggering WordPress just-in-time translation notices. * * @return bool */ private function is_i18n_ready() { return ( WPBC()->is_wp_inited() || did_action( 'init' ) ); } /** * Define Steps Data Structure - Init * * @return void */ public function init_steps_data(){ $is_i18n_ready = $this->is_i18n_ready(); $step_default_params = array( 'show_section_left' => false, 'show_section_right' => false, 'is_done' => false, 'do_action' => 'none', 'prior' => '', 'next' => '', 'prior_title' => $is_i18n_ready ? __( 'Go Back', 'booking' ) : 'Go Back', 'next_title' => $is_i18n_ready ? __( 'Save and Continue', 'booking' ) : 'Save and Continue' ); $steps_arr = array(); if ( function_exists( 'wpbc_setup_wizard__get_intro_route' ) ) { $route = wpbc_setup_wizard__get_intro_route(); } else { $route = array( 'welcome' ); if ( ! wpbc_is_this_demo() ) { $route[] = 'general_info'; } $route[] = 'date_time_formats'; $route[] = 'bookings_types'; } $route = array_merge( $route, wpbc_setup_wizard__get_profile_route() ); foreach ( $route as $step_index => $step_name ) { $steps_arr[ $step_name ] = $step_default_params; $steps_arr[ $step_name ]['do_action'] = 'save_and_continue__' . $step_name; $steps_arr[ $step_name ]['prior'] = ( 0 === $step_index ) ? '' : $route[ $step_index - 1 ]; $steps_arr[ $step_name ]['next'] = isset( $route[ $step_index + 1 ] ) ? $route[ $step_index + 1 ] : 'welcome'; if ( $is_i18n_ready && function_exists( 'wpbc_setup_wizard__get_step_route_metadata' ) ) { $steps_arr[ $step_name ] = array_merge( $steps_arr[ $step_name ], wpbc_setup_wizard__get_step_route_metadata( $step_name ) ); } } 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 ) { if ( isset( $steps_arr[ $continue_step_name ] ) ) { $steps_arr[ $continue_step_name ]['next_title'] = $is_i18n_ready ? __( 'Continue', 'booking' ) : 'Continue'; } } $this->steps_arr = $steps_arr; $this->is_steps_data_initialized = true; } /** * Ensure setup route data is available before this instance reads or normalizes step state. * * @return void */ private function ensure_steps_data_initialized() { if ( ! $this->is_steps_data_initialized ) { $this->init_steps_data(); } } /** * Get Steps Data Structure * @return array */ public function get_steps_arr(){ $this->ensure_steps_data_initialized(); return $this->steps_arr; } // ================================================================================================================= // == Steps STRUCTURE == // ================================================================================================================= /** * Actual Step Number -> 'general_info' or 'date_availability' * * @return int */ public function get_active_step_name() { $steps_arr = $this->db__get_steps_is_done(); $first_step_name = ''; foreach ( $steps_arr as $step_name => $step ) { $first_step_name = (empty($first_step_name)) ? $step_name : $first_step_name; if ( empty( $step ) ) { return $step_name; } } return $first_step_name; } /** * Actual Step Number -> 2 * * @return int */ public function get_active_step_num( $current_step = '' ) { if ( ! empty( $current_step ) ) { return $this->get_step_num_by_name( $current_step ); } $steps_arr = $this->db__get_steps_is_done(); $total_steps = count( $steps_arr ); $completed_steps = 0; foreach ( $steps_arr as $step ) { if ( ! empty( $step ) ) { $completed_steps++; } } if ( $completed_steps >= $total_steps ) { return $total_steps; } return min( $completed_steps + 1, $total_steps ); } /** * Get Step Number by step name. * * @param string $current_step Step name. * * @return int */ public function get_step_num_by_name( $current_step ) { $step_num = 1; foreach ( array_keys( $this->get_steps_arr() ) as $step_name ) { if ( $step_name === $current_step ) { return $step_num; } $step_num++; } return 1; } /** * Get the last wizard step saved in the setup wizard request history. * * @return string */ public function get_saved_current_step_name() { $steps_arr = $this->get_steps_arr(); $current_step = $this->get_active_step_name(); if ( function_exists( 'wpbc_setup_wizard_page__get_cleaned_params__saved_request_default' ) ) { $saved_request_params = wpbc_setup_wizard_page__get_cleaned_params__saved_request_default(); if ( is_array( $saved_request_params ) && ( ! empty( $saved_request_params['current_step'] ) ) && isset( $steps_arr[ $saved_request_params['current_step'] ] ) ) { $current_step = $saved_request_params['current_step']; } } return $current_step; } /** * Get target URL for a setup step. * * @param string $step_name Step name. * * @return string */ public function get_step_target_url( $step_name ) { $steps_arr = $this->get_steps_arr(); if ( isset( $steps_arr[ $step_name ]['target_url'] ) && ( ! empty( $steps_arr[ $step_name ]['target_url'] ) ) ) { return $steps_arr[ $step_name ]['target_url']; } return function_exists( 'wpbc_setup_wizard__get_step_target_url' ) ? wpbc_setup_wizard__get_step_target_url( $step_name ) : wpbc_get_setup_wizard_page_url(); } /** * Get Continue URL for the floating setup bar. * * @param string $step_name Step name. * * @return string */ public function get_step_continue_url( $step_name ) { return function_exists( 'wpbc_setup_wizard__get_step_continue_url' ) ? wpbc_setup_wizard__get_step_continue_url( $step_name ) : $this->get_step_target_url( $step_name ); } /** * Get step name from setup URL context or first incomplete setup step. * * @return string */ public function get_context_step_name() { $steps_arr = $this->get_steps_arr(); $current_step = $this->get_saved_current_step_name(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing if ( isset( $_REQUEST['wpbc_setup_step'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing $request_step = sanitize_key( wp_unslash( $_REQUEST['wpbc_setup_step'] ) ); if ( isset( $steps_arr[ $request_step ] ) ) { $current_step = $request_step; $this->db__save_current_step_name( $current_step ); return $current_step; } } if ( $this->db__is_step_completed( 'bookings_types' ) && function_exists( 'wpbc_setup_wizard__detect_step_from_admin_request' ) ) { $detected_step = wpbc_setup_wizard__detect_step_from_admin_request(); if ( ! empty( $detected_step ) && isset( $steps_arr[ $detected_step ] ) ) { $current_step = $detected_step; $this->db__save_current_step_name( $current_step ); return $current_step; } } return $current_step; } /** * Save the current setup step into the per-user wizard request state. * * @param string $step_name Step name. * * @return bool */ public function db__save_current_step_name( $step_name ) { $steps_arr = $this->get_steps_arr(); if ( empty( $step_name ) || ! isset( $steps_arr[ $step_name ] ) || ! function_exists( 'wpbc_setup_wizard_page__request_rules_structure' ) ) { return false; } $request_params_to_save = function_exists( 'wpbc_setup_wizard_page__get_cleaned_params__saved_request_default' ) ? wpbc_setup_wizard_page__get_cleaned_params__saved_request_default() : array(); if ( ! is_array( $request_params_to_save ) || empty( $request_params_to_save ) ) { $request_params_to_save = function_exists( 'wpbc_setup_wizard_page__get__request_values__default' ) ? wpbc_setup_wizard_page__get__request_values__default() : array(); } $request_params_to_save['current_step'] = $step_name; $user_request = new WPBC_AJX__REQUEST( array( 'db_option_name' => 'booking_setup_wizard_page_request_params', 'user_id' => wpbc_get_current_user_id(), 'request_rules_structure' => wpbc_setup_wizard_page__request_rules_structure() ) ); return (bool) $user_request->user_request_params__db_save( $request_params_to_save ); } /** * Get target URL for prior setup step. * * @param string $step_name Step name. * * @return string */ public function get_step_prior_url( $step_name ) { $steps_arr = $this->get_steps_arr(); $prior = isset( $steps_arr[ $step_name ]['prior'] ) ? $steps_arr[ $step_name ]['prior'] : ''; return ( empty( $prior ) ) ? '' : $this->get_step_target_url( $prior ); } /** * Get step title for setup bar. * * @param string $step_name Step name. * * @return string */ public function get_step_title( $step_name ) { $steps_arr = $this->get_steps_arr(); if ( isset( $steps_arr[ $step_name ]['title'] ) ) { return $steps_arr[ $step_name ]['title']; } return function_exists( 'wpbc_setup_wizard__get_step_title' ) ? wpbc_setup_wizard__get_step_title( $step_name ) : $step_name; } /** * Get action-oriented setup step heading. * * @param string $step_name Step name. * * @return string */ public function get_step_heading( $step_name ) { $steps_arr = $this->get_steps_arr(); if ( isset( $steps_arr[ $step_name ]['heading'] ) ) { return $steps_arr[ $step_name ]['heading']; } return function_exists( 'wpbc_setup_wizard__get_step_heading' ) ? wpbc_setup_wizard__get_step_heading( $step_name ) : $this->get_step_title( $step_name ); } /** * Get setup step description. * * @param string $step_name Step name. * * @return string */ public function get_step_description( $step_name ) { $steps_arr = $this->get_steps_arr(); if ( isset( $steps_arr[ $step_name ]['description'] ) ) { return $steps_arr[ $step_name ]['description']; } return function_exists( 'wpbc_setup_wizard__get_step_description' ) ? wpbc_setup_wizard__get_step_description( $step_name ) : ''; } /** * Get setup step save behavior. * * @param string $step_name Step name. * * @return string */ public function get_step_save_behavior( $step_name ) { $steps_arr = $this->get_steps_arr(); if ( isset( $steps_arr[ $step_name ]['save_behavior'] ) ) { return $steps_arr[ $step_name ]['save_behavior']; } return function_exists( 'wpbc_setup_wizard__get_step_save_behavior' ) ? wpbc_setup_wizard__get_step_save_behavior( $step_name ) : 'link_only'; } /** * Get route metadata value. * * @param string $step_name Step name. * @param string $key Metadata key. * * @return string */ public function get_step_meta_value( $step_name, $key ) { $steps_arr = $this->get_steps_arr(); return ( isset( $steps_arr[ $step_name ][ $key ] ) ) ? (string) $steps_arr[ $step_name ][ $key ] : ''; } /** * Get Steps Count -> 9 * * @return int */ public function get_total_steps_count(){ $steps_arr = $this->db__get_steps_is_done(); return count($steps_arr); } /** * Get % Progress for Setup Steps -> 30 * @return int */ public function get_progess_value( $current_step = '' ) { $total_steps = $this->get_total_steps_count(); if ( $total_steps <= 0 ) { return 0; } $progess_value = ( $this->get_active_step_num( $current_step ) * 100 ) / $total_steps; $progess_value = intval( $progess_value ); return $progess_value; } // ================================================================================================================= // == DB :: "Set Wizard Steps as Done" == // ================================================================================================================= /** * Get all Steps from DB and from Structure, * * If not saved yet to DB, then get default structure * * And if later Wizard structure ->init_steps_data() was extended, then system get such steps as uncompleted. * * @return array|mixed */ public function db__get_steps_is_done() { $steps_is_done = get_bk_option( 'booking_setup_wizard_page_steps_is_done' ); $is_completed = ( 'On' === get_bk_option( 'booking_setup_wizard_page_is_completed' ) ); $active_steps_names = array_keys( $this->get_steps_arr() ); $normalized_steps = array(); if ( empty( $active_steps_names ) ) { return is_array( $steps_is_done ) ? $steps_is_done : array(); } foreach ( $active_steps_names as $step_name ) { $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 ); } if ( $steps_is_done !== $normalized_steps ) { $this->db__save_steps_is_done( $normalized_steps ); } return $normalized_steps; } /** * Save statuses to all steps * * @param $steps_arr * * @return void */ public function db__save_steps_is_done( $steps_arr ) { update_bk_option( 'booking_setup_wizard_page_steps_is_done', $steps_arr ); } /** * Set specific step as Completed * * @param $step_name * * @return void */ public function db__set_step_as_completed( $step_name ) { $steps_arr = $this->db__get_steps_is_done(); $steps_arr[ $step_name ] = true; $this->db__save_steps_is_done( $steps_arr ); $this->db__set_step_as_saved( $step_name, true ); if ( ! in_array( false, $steps_arr, true ) ) { update_bk_option( 'booking_setup_wizard_page_is_completed', 'On' ); } } /** * Set specific step as Uncompleted * * @param $step_name * * @return void */ public function db__set_step_as_uncompleted( $step_name ) { $steps_arr = $this->db__get_steps_is_done(); $steps_arr[ $step_name ] = false; delete_bk_option( 'booking_setup_wizard_page_is_completed' ); $this->db__save_steps_is_done( $steps_arr ); } /** * Reset a step and all following steps in the active route. * * Older wizard versions could leave later steps marked as completed, which made the continue handler think setup * was finished too early after Step 5. * * @param string $first_step_name First step to reset. * * @return bool */ public function db__reset_steps_from( $first_step_name ) { $steps_is_done = $this->db__get_steps_is_done(); $steps_is_saved = $this->db__get_steps_is_saved(); $should_reset = false; if ( ! array_key_exists( $first_step_name, $steps_is_done ) ) { return false; } foreach ( array_keys( $steps_is_done ) as $step_name ) { if ( $first_step_name === $step_name ) { $should_reset = true; } if ( $should_reset ) { $steps_is_done[ $step_name ] = false; if ( array_key_exists( $step_name, $steps_is_saved ) ) { $steps_is_saved[ $step_name ] = false; } } } delete_bk_option( 'booking_setup_wizard_page_is_completed' ); $this->db__save_steps_is_done( $steps_is_done ); $this->db__save_steps_is_saved( $steps_is_saved ); return true; } /** * Check if specific step 'Is completed' ? * * @param string $step_name * * @return bool */ public function db__is_step_completed( $step_name ) { $steps_arr = $this->db__get_steps_is_done(); if ( empty( $steps_arr[ $step_name ] ) ) { return false; } else { return true; } } /** * Mark All Steps as Completed or Uncompleted * * @param $is_completed bool (default true) * * @return void */ public function db__set_all_steps_as( $is_completed = true ) { if ( false === $is_completed ) { delete_bk_option( 'booking_setup_wizard_page_steps_is_done' ); delete_bk_option( 'booking_setup_wizard_page_is_completed' ); } else { update_bk_option( 'booking_setup_wizard_page_is_completed', 'On' ); } $steps_names = $this->db__get_steps_is_done(); $steps_names = array_keys( $steps_names ); $steps_values = array_fill( 0, count( $steps_names ), $is_completed ); $steps_is_done = array_combine( $steps_names, $steps_values ); // Set all steps as not completed $this->db__save_steps_is_done( $steps_is_done ); $this->db__save_steps_is_saved( $steps_is_done ); } /** * Get saved state for setup steps. * * @return array */ public function db__get_steps_is_saved() { $steps_is_saved = get_bk_option( 'booking_setup_wizard_page_steps_is_saved' ); $is_completed = ( 'On' === get_bk_option( 'booking_setup_wizard_page_is_completed' ) ); $normalized = array(); foreach ( array_keys( $this->get_steps_arr() ) as $step_name ) { $normalized[ $step_name ] = $is_completed ? true : ( ( is_array( $steps_is_saved ) && isset( $steps_is_saved[ $step_name ] ) ) ? (bool) $steps_is_saved[ $step_name ] : false ); } if ( $steps_is_saved !== $normalized ) { $this->db__save_steps_is_saved( $normalized ); } return $normalized; } /** * Save setup step saved states. * * @param array $steps_arr Saved states. * * @return void */ public function db__save_steps_is_saved( $steps_arr ) { update_bk_option( 'booking_setup_wizard_page_steps_is_saved', $steps_arr ); } /** * Mark a setup step as saved or unsaved. * * @param string $step_name Step name. * @param bool $is_saved Saved flag. * * @return bool */ public function db__set_step_as_saved( $step_name, $is_saved = true ) { $steps_arr = $this->db__get_steps_is_saved(); if ( ! array_key_exists( $step_name, $steps_arr ) ) { return false; } $steps_arr[ $step_name ] = (bool) $is_saved; $this->db__save_steps_is_saved( $steps_arr ); return true; } /** * Check whether a setup step has been saved. * * @param string $step_name Step name. * * @return bool */ public function db__is_step_saved( $step_name ) { if ( 'manual_save_required' !== $this->get_step_save_behavior( $step_name ) ) { return true; } $steps_arr = $this->db__get_steps_is_saved(); return ! empty( $steps_arr[ $step_name ] ); } /** * Check Is all steps Completed * @return bool */ public function db__is_all_steps_completed() { if ( 'On' === get_bk_option( 'booking_setup_wizard_page_is_completed' ) ) { return true; } $steps_arr = $this->db__get_steps_is_done(); if ( empty( $steps_arr ) ) { return false; } foreach ( $steps_arr as $step_name => $steps_val ) { if ( empty( $steps_val ) ) { return false; } } return true; } // ================================================================================================================= // == C O N T E N T == // ================================================================================================================= // ---------------------------------------------------------- // == Left Plugin Menu --> "Setup" with Progress Bar == // ---------------------------------------------------------- /** * Main Left Menu Title - "Setup" with Progress Bar * * @return false|string */ public function get_plugin_menu_title__setup_progress( $current_step = '' ){ $current_step_for_progress = ( ! empty( $current_step ) ) ? $current_step : $this->get_context_step_name(); ob_start(); ?>
get_active_step_num( $current_step_for_progress ) . ' / ' . $this->get_total_steps_count() ); ?>
steps_arr[ $request_step ] ) && function_exists( 'wpbc_setup_wizard_page__has_explicit_step_context' ) && wpbc_setup_wizard_page__has_explicit_step_context( $request_step ); } if ( ( ! wpbc_is_user_can_access_wizard_page() ) || ( $this->db__is_all_steps_completed() && ! $explicit_step_context ) ) { return false; } if ( self::$is_top_bar_rendered ) { return false; } self::$is_top_bar_rendered = true; $current_step = $this->get_context_step_name(); $is_external_setup_flow_started = $this->db__is_step_completed( 'bookings_types' ); $detected_page_step = ( $is_external_setup_flow_started && function_exists( 'wpbc_setup_wizard__detect_step_from_admin_request' ) ) ? wpbc_setup_wizard__detect_step_from_admin_request() : ''; $continue_url = $this->get_step_continue_url( $current_step ); if ( ! empty( $detected_page_step ) && isset( $this->steps_arr[ $detected_page_step ] ) ) { $continue_url = add_query_arg( 'wpbc_setup_from_page_step', $detected_page_step, $continue_url ); } $prior_url = $this->get_step_prior_url( $current_step ); $step_title = $this->get_step_title( $current_step ); $step_heading = $this->get_step_heading( $current_step ); $step_save_page_title = ( 'form_structure' === $current_step ) ? __( 'Form Builder', 'booking' ) : $step_title; $description = $this->get_step_description( $current_step ); $save_behavior = $this->get_step_save_behavior( $current_step ); $target_selector = $this->get_step_meta_value( $current_step, 'target_selector' ); $scroll_selector = $this->get_step_meta_value( $current_step, 'scroll_selector' ); $highlight_selector = $this->get_step_meta_value( $current_step, 'highlight_selector' ); $highlight_disabled = $this->get_step_meta_value( $current_step, 'highlight_disabled' ); $highlight_all = $this->get_step_meta_value( $current_step, 'highlight_all' ); $form_selector = $this->get_step_meta_value( $current_step, 'form_selector' ); $save_selector = $this->get_step_meta_value( $current_step, 'save_selector' ); $save_ajax_action = $this->get_step_meta_value( $current_step, 'save_ajax_action' ); $save_events = $this->get_step_meta_value( $current_step, 'save_events' ); $open_action = $this->get_step_meta_value( $current_step, 'open_action' ); $secondary_action_url = $this->get_step_meta_value( $current_step, 'secondary_action_url' ); $secondary_action_label = $this->get_step_meta_value( $current_step, 'secondary_action_label' ); $can_save_from_bar = ( 'manual_save_required' === $save_behavior && ! empty( $save_selector ) ); $continue_title = ( 'complete' === $save_behavior ) ? __( 'Finish Setup', 'booking' ) : __( 'Continue', 'booking' ); if ( $can_save_from_bar ) { $continue_title = __( 'Save and Continue', 'booking' ); } $is_step_saved = $this->db__is_step_saved( $current_step ); $is_step_unsaved = ( 'manual_save_required' === $save_behavior && ! $is_step_saved ); $is_continue_disabled = ( $is_step_unsaved && ! $can_save_from_bar ); $continue_href = $is_step_unsaved ? '#wpbc_setup_save_required' : $continue_url; $mark_saved_nonce = wp_create_nonce( 'wpbc_setup_wizard_mark_step_saved' ); $step_target_url = $this->get_step_target_url( $current_step ); $skip_wizard_url = add_query_arg( 'wpbc_setup_wizard', 'completed', wpbc_get_bookings_url() ); $reset_wizard_url = add_query_arg( 'wpbc_setup_wizard', 'reset', wpbc_get_setup_wizard_page_url() ); $save_required_note = sprintf( /* translators: %s: setup target page title. */ __( 'Save changes on the %s page before continuing.', 'booking' ), '' . esc_html( $step_save_page_title ) . '' ); $test_page_links = ( 'wizard_publish' === $current_step && function_exists( 'wpbc_booking_modes_get_setup_test_page_links' ) ) ? wpbc_booking_modes_get_setup_test_page_links() : array(); // FixIn: 10.12.1.1. ?>
get_active_step_num( $current_step ) . ' / ' . $this->get_total_steps_count() ); ?>
>
db__set_all_steps_as( $is_completed ); } } add_bk_action( 'wpbc_other_versions_activation', 'wpbc_booking_activate_plugin__wizard' );