<?php /** * WooCommerce Onboarding Setup Wizard */ namespace Automattic\WooCommerce\Internal\Admin\Onboarding; use Automattic\WooCommerce\Admin\PageController; use Automattic\WooCommerce\Admin\WCAdminHelper; use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile; use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists; /** * Contains backend logic for the onboarding profile and checklist feature. */ class OnboardingSetupWizard { /** * Class instance. * * @var OnboardingSetupWizard instance */ private static $instance = null; /** * Get class instance. */ final public static function instance() { if ( ! static::$instance ) { static::$instance = new static(); } return static::$instance; } /** * Add onboarding actions. */ public function init() { if ( ! is_admin() ) { return; } // Old settings injection. // Run after Automattic\WooCommerce\Internal\Admin\Loader. add_filter( 'woocommerce_components_settings', array( $this, 'component_settings' ), 20 ); // New settings injection. add_filter( 'woocommerce_admin_shared_settings', array( $this, 'component_settings' ), 20 ); add_filter( 'woocommerce_admin_preload_settings', array( $this, 'preload_settings' ) ); add_filter( 'admin_body_class', array( $this, 'add_loading_classes' ) ); add_action( 'admin_init', array( $this, 'do_admin_redirects' ) ); add_action( 'current_screen', array( $this, 'redirect_to_profiler' ) ); add_filter( 'woocommerce_show_admin_notice', array( $this, 'remove_old_install_notice' ), 10, 2 ); } /** * Test whether the context of execution comes from async action scheduler. * Note: this is a polyfill for wc_is_running_from_async_action_scheduler() * which was introduced in WC 4.0. * * @return bool */ private function is_running_from_async_action_scheduler() { if ( function_exists( '\wc_is_running_from_async_action_scheduler' ) ) { return \wc_is_running_from_async_action_scheduler(); } // phpcs:ignore WordPress.Security.NonceVerification.Recommended return isset( $_REQUEST['action'] ) && 'as_async_request_queue_runner' === $_REQUEST['action']; } /** * Handle redirects to setup/welcome page after install and updates. * * For setup wizard, transient must be present, the user must have access rights, and we must ignore the network/bulk plugin updaters. */ public function do_admin_redirects() { // Don't run this fn from Action Scheduler requests, as it would clear _wc_activation_redirect transient. // That means OBW would never be shown. if ( $this->is_running_from_async_action_scheduler() ) { return; } // Setup wizard redirect. if ( get_transient( '_wc_activation_redirect' ) && apply_filters( 'woocommerce_enable_setup_wizard', true ) ) { $do_redirect = true; $current_page = isset( $_GET['page'] ) ? wc_clean( wp_unslash( $_GET['page'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification $is_onboarding_path = ! isset( $_GET['path'] ) || '/setup-wizard' === wc_clean( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification // On these pages, or during these events, postpone the redirect. if ( wp_doing_ajax() || is_network_admin() || ! current_user_can( 'manage_woocommerce' ) ) { $do_redirect = false; } // On these pages, or during these events, disable the redirect. if ( ( 'wc-admin' === $current_page && $is_onboarding_path ) || apply_filters( 'woocommerce_prevent_automatic_wizard_redirect', false ) || isset( $_GET['activate-multi'] ) // phpcs:ignore WordPress.Security.NonceVerification ) { delete_transient( '_wc_activation_redirect' ); $do_redirect = false; } if ( $do_redirect ) { delete_transient( '_wc_activation_redirect' ); wp_safe_redirect( wc_admin_url() ); exit; } } } /** * Trigger the woocommerce_onboarding_profile_completed action * * @param array $old_value Previous value. * @param array $value Current value. */ public function trigger_profile_completed_action( $old_value, $value ) { if ( isset( $old_value['completed'] ) && $old_value['completed'] ) { return; } if ( ! isset( $value['completed'] ) || ! $value['completed'] ) { return; } /** * Action hook fired when the onboarding profile (or onboarding wizard, * or profiler) is completed. * * @since 1.5.0 */ do_action( 'woocommerce_onboarding_profile_completed' ); } /** * Returns true if the profiler should be displayed (not completed and not skipped). * * @return bool */ private function should_show() { if ( $this->is_setup_wizard() ) { return true; } return OnboardingProfile::needs_completion(); } /** * Redirect to the profiler on homepage if completion is needed. */ public function redirect_to_profiler() { if ( ! $this->is_homepage() || ! OnboardingProfile::needs_completion() ) { return; } wp_safe_redirect( wc_admin_url( '&path=/setup-wizard' ) ); exit; } /** * Check if the current page is the profile wizard. * * @return bool */ private function is_setup_wizard() { /* phpcs:disable WordPress.Security.NonceVerification */ return isset( $_GET['page'] ) && 'wc-admin' === $_GET['page'] && isset( $_GET['path'] ) && '/setup-wizard' === $_GET['path']; /* phpcs: enable */ } /** * Check if the current page is the homepage. * * @return bool */ private function is_homepage() { /* phpcs:disable WordPress.Security.NonceVerification */ return isset( $_GET['page'] ) && 'wc-admin' === $_GET['page'] && ! isset( $_GET['path'] ); /* phpcs: enable */ } /** * Determine if the current page is one of the WC Admin pages. * * @return bool */ private function is_woocommerce_page() { $current_page = PageController::get_instance()->get_current_page(); if ( ! $current_page || ! isset( $current_page['path'] ) ) { return false; } return 0 === strpos( $current_page['path'], 'wc-admin' ); } /** * Add profiler items to component settings. * * @param array $settings Component settings. * * @return array */ public function component_settings( $settings ) { $profile = (array) get_option( OnboardingProfile::DATA_OPTION, array() ); $settings['onboarding'] = array( 'profile' => $profile, ); // Only fetch if the onboarding wizard OR the task list is incomplete or currently shown // or the current page is one of the WooCommerce Admin pages. if ( ( ! $this->should_show() && ! count( TaskLists::get_visible() ) || ! $this->is_woocommerce_page() ) ) { return $settings; } include_once WC_ABSPATH . 'includes/admin/helper/class-wc-helper-options.php'; $wccom_auth = \WC_Helper_Options::get( 'auth' ); $profile['wccom_connected'] = empty( $wccom_auth['access_token'] ) ? false : true; $settings['onboarding']['currencySymbols'] = get_woocommerce_currency_symbols(); $settings['onboarding']['euCountries'] = WC()->countries->get_european_union_countries(); $settings['onboarding']['localeInfo'] = include WC()->plugin_path() . '/i18n/locale-info.php'; $settings['onboarding']['profile'] = $profile; return apply_filters( 'woocommerce_admin_onboarding_preloaded_data', $settings ); } /** * Preload WC setting options to prime state of the application. * * @param array $options Array of options to preload. * @return array */ public function preload_settings( $options ) { $options[] = 'general'; return $options; } /** * Set the admin full screen class when loading to prevent flashes of unstyled content. * * @param bool $classes Body classes. * @return array */ public function add_loading_classes( $classes ) { /* phpcs:disable WordPress.Security.NonceVerification */ if ( $this->is_setup_wizard() ) { $classes .= ' woocommerce-admin-full-screen'; } /* phpcs: enable */ return $classes; } /** * Remove the install notice that prompts the user to visit the old onboarding setup wizard. * * @param bool $show Show or hide the notice. * @param string $notice The slug of the notice. * @return bool */ public function remove_old_install_notice( $show, $notice ) { if ( 'install' === $notice ) { return false; } return $show; } }