From 14d25b5f887c4fb7e5b4879d61f431c6a651136e Mon Sep 17 00:00:00 2001 From: arunshenoy99 Date: Mon, 17 Apr 2023 22:07:47 +0530 Subject: [PATCH 1/3] switch to commerce flow when selling is top priority --- includes/Data/Data.php | 29 +-- includes/Data/Flows.php | 13 ++ includes/Data/Plugins.php | 14 +- includes/Data/Preview.php | 55 +++-- includes/RestApi/FlowController.php | 214 +++++------------- includes/Services/FlowService.php | 202 +++++++++++++++++ includes/Services/PluginInstaller.php | 131 ++++++----- .../TaskManagers/PluginInstallTaskManager.php | 127 +++++++---- src/OnboardingSPA/components/Content/index.js | 28 +-- .../Loaders/Step/Ecommerce/contents.js | 22 ++ .../Loaders/Step/Ecommerce/index.js | 19 ++ .../Sidebar/components/LearnMore/Menu.js | 2 +- .../components/SkipButton/index.js | 14 +- .../StateHandlers/Ecommerce/contents.js | 17 +- .../StateHandlers/Ecommerce/index.js | 12 +- .../components/StateHandlers/Flow/index.js | 90 ++++++++ .../data/routes/ecommerce-flow.js | 9 +- .../pages/Steps/TopPriority/index.js | 74 ++++-- src/OnboardingSPA/utils/api/flow.js | 12 + src/OnboardingSPA/utils/index.js | 23 +- src/constants.js | 1 + 21 files changed, 738 insertions(+), 370 deletions(-) create mode 100644 includes/Services/FlowService.php create mode 100644 src/OnboardingSPA/components/Loaders/Step/Ecommerce/contents.js create mode 100644 src/OnboardingSPA/components/Loaders/Step/Ecommerce/index.js create mode 100644 src/OnboardingSPA/components/StateHandlers/Flow/index.js diff --git a/includes/Data/Data.php b/includes/Data/Data.php index ea316b139..bba53189e 100644 --- a/includes/Data/Data.php +++ b/includes/Data/Data.php @@ -80,6 +80,15 @@ public static function current_plan() { } } + $current_flow = Flows::get_flow_from_top_priority(); + if ( false !== $current_flow ) { + return array( + 'flow' => 'ecommerce', + 'subtype' => 'wc_priority', + 'type' => null, + ); + } + return array( 'flow' => Flows::get_default_flow(), 'subtype' => null, @@ -93,24 +102,8 @@ public static function current_plan() { * @return string */ public static function current_flow() { - - $current_flow = Flows::get_flow_from_params(); - if ( false !== $current_flow ) { - return $current_flow; - } - - $current_flow = Flows::get_flow_from_plugins(); - if ( false !== $current_flow ) { - return $current_flow; - } - - $customer_data = self::customer_data(); - $current_flow = Flows::get_flow_from_customer_data( $customer_data ); - if ( false !== $current_flow ) { - return $current_flow; - } - - return Flows::get_default_flow(); + $current_plan = self::current_plan(); + return $current_plan['flow']; } /** diff --git a/includes/Data/Flows.php b/includes/Data/Flows.php index 128b78bce..7a531aabf 100644 --- a/includes/Data/Flows.php +++ b/includes/Data/Flows.php @@ -1,6 +1,7 @@ 'jetpack/jetpack.php', ), 'woocommerce' => array( - 'approved' => true, - 'path' => 'woocommerce/woocommerce.php', + 'approved' => true, + 'path' => 'woocommerce/woocommerce.php', + 'post_install_callback' => array( __CLASS__, 'wc_prevent_redirect_on_activation' ), ), 'wordpress-seo' => array( 'approved' => true, @@ -420,4 +421,13 @@ public static function get_init() { return $init_list; } + /** + * Prevent redirect to woo wizard after activation of woocommerce. + * + * @return void + */ + public static function wc_prevent_redirect_on_activation() { + \delete_transient( '_wc_activation_redirect' ); + } + } diff --git a/includes/Data/Preview.php b/includes/Data/Preview.php index c4f7930b8..886994f35 100644 --- a/includes/Data/Preview.php +++ b/includes/Data/Preview.php @@ -4,12 +4,25 @@ use NewfoldLabs\WP\Module\Onboarding\Services\PluginInstaller; use NewfoldLabs\WP\Module\Onboarding\Services\ThemeInstaller; +/** + * Class Preview + */ final class Preview { - + /** + * Convert boolean to plugin/theme status. + * + * @param boolean $boolean The boolean value. + * @return string + */ private static function boolean_to_status( $boolean ) { - return $boolean ? 'activated' : 'init'; + return $boolean ? 'activated' : 'init'; } + /** + * Map of pre requisites to show the live preview successfully for a flow. + * + * @return array + */ private static function pre_requisites() { $theme_map = Themes::get(); return array( @@ -30,21 +43,35 @@ private static function pre_requisites() { ); } - public static function get_pre_requisites() { - $pre_requisites = self::pre_requisites(); - return isset( $pre_requisites[ Data::current_flow() ] ) ? $pre_requisites[ Data::current_flow() ] : array(); + /** + * Get the pre requisites for a given flow. + * + * @param string $flow A valid Onboarding flow. + * @return array + */ + public static function get_pre_requisites( $flow = null ) { + $pre_requisites = self::pre_requisites(); + if ( ! isset( $flow ) ) { + $flow = Data::current_flow(); + } + return isset( $pre_requisites[ $flow ] ) ? $pre_requisites[ $flow ] : array(); } + /** + * Get all the settings necessary to load the live preview + * + * @return array + */ public static function get_settings() { - $block_editor_context = new \WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) ); - $custom_settings = array( - 'siteUrl' => \site_url(), - ); + $block_editor_context = new \WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) ); + $custom_settings = array( + 'siteUrl' => \site_url(), + ); - return array( - 'settings' => \get_block_editor_settings( $custom_settings, $block_editor_context ), - 'globalStyles' => \wp_get_global_styles(), - 'preRequisites' => self::get_pre_requisites(), - ); + return array( + 'settings' => \get_block_editor_settings( $custom_settings, $block_editor_context ), + 'globalStyles' => \wp_get_global_styles(), + 'preRequisites' => self::get_pre_requisites(), + ); } } diff --git a/includes/RestApi/FlowController.php b/includes/RestApi/FlowController.php index 363ebd113..34fed044b 100644 --- a/includes/RestApi/FlowController.php +++ b/includes/RestApi/FlowController.php @@ -1,11 +1,8 @@ namespace, + $this->rest_base . '/switch', + array( + array( + 'methods' => \WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'switch' ), + 'permission_callback' => array( Permissions::class, 'rest_is_authorized_admin' ), + 'args' => $this->get_switch_args(), + ), + ) + ); } /** - * Fetch onboarding flow details from database. + * Get the valid request params for the switch endpoint. * - * @param \WP_REST_Request $request Request model. + * @return array + */ + public function get_switch_args() { + return array( + 'flow' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + ); + } + + /** + * Get Onboarding flow data. * * @return \WP_REST_Response */ - public function get_onboarding_flow_data( \WP_REST_Request $request ) { - // check if data is available in the database if not then fetch the default dataset - $result = $this->read_details_from_wp_options(); - if ( ! $result ) { - $result = Flows::get_data(); - $result['createdAt'] = time(); - // update default data if flow type is ecommerce - $result = $this->update_default_data_for_ecommerce( $result ); - $this->save_details_to_wp_options( $result ); - } - + public function get_onboarding_flow_data() { return new \WP_REST_Response( - $result, + FlowService::get_flow_data(), 200 ); } /** - * Save / Update onboarding flow details to database. + * Update the Onboarding flow data. * - * @param \WP_REST_Request $request Request model. + * @param \WP_REST_Request $request The incoming request. * - * @return \WP_REST_Response|\WP_Error + * @return \WP_Error|\WP_REST_Response */ public function save_onboarding_flow_data( \WP_REST_Request $request ) { - $flow_data = array(); - $params = json_decode( $request->get_body(), true ); - - if ( is_null( $params ) ) { - return new \WP_Error( - 'no_post_data', - 'No Data Provided', - array( 'status' => 404 ) - ); - } - - $flow_data = $this->read_details_from_wp_options(); - if ( ! $flow_data ) { - $flow_data = Flows::get_data(); - $flow_data['createdAt'] = time(); - // update default data if flow type is ecommerce - $flow_data = $this->update_default_data_for_ecommerce( $flow_data ); - $this->save_details_to_wp_options( $flow_data ); - } - - foreach ( $params as $key => $param ) { - $value = $this->array_search_key( $key, $flow_data ); - if ( false === $value ) { - return new \WP_Error( - 'wrong_param_provided', - "Wrong Parameter Provided : $key", - array( 'status' => 404 ) - ); - } - } - - $flow_data = array_replace_recursive( $flow_data, $params ); - - // update timestamp once data is updated - $flow_data['updatedAt'] = time(); - - // Update Blog Information from Basic Info - if ( ( ! empty( $flow_data['data']['blogName'] ) ) ) { - \update_option( Options::get_option_name( 'blog_name', false ), $flow_data['data']['blogName'] ); - } - - if ( ( ! empty( $flow_data['data']['blogDescription'] ) ) ) { - \update_option( Options::get_option_name( 'blog_description', false ), $flow_data['data']['blogDescription'] ); - } - - if ( ( ! empty( $flow_data['data']['siteLogo'] ) ) && ! empty( $flow_data['data']['siteLogo']['id'] ) ) { - \update_option( Options::get_option_name( 'site_icon', false ), $flow_data['data']['siteLogo']['id'] ); - \update_option( Options::get_option_name( 'site_logo', false ), $flow_data['data']['siteLogo']['id'] ); - } else { - \update_option( Options::get_option_name( 'site_icon', false ), 0 ); - \delete_option( Options::get_option_name( 'site_logo', false ) ); - } + $params = json_decode( $request->get_body(), true ); - // save data to database - if ( ! $this->update_wp_options_data_in_database( $flow_data ) ) { - return new \WP_Error( - 'database_update_failed', - 'There was an error saving the data', - array( 'status' => 404 ) - ); + $flow_data = FlowService::update_flow_data( $params ); + if ( \is_wp_error( $flow_data ) ) { + return $flow_data; } return new \WP_REST_Response( @@ -162,82 +120,7 @@ public function save_onboarding_flow_data( \WP_REST_Request $request ) { } /** - * Check the current flow type and update default data if flowtype is ecommerce. - * - * @param array $data default blueprint flow data. - * - * @return array - */ - private function update_default_data_for_ecommerce( $data ) { - // get current flow type - $flow_type = Data::current_flow(); - if ( 'ecommerce' === $flow_type ) { - // update default data with ecommerce data - $data['data']['topPriority']['priority1'] = 'selling'; - $data['data']['siteType'] = array( - 'label' => '', - 'referTo' => 'business', - ); - } - return $data; - } - - /** - * Read onboarding flow options from database - * - * @return array - */ - public function read_details_from_wp_options() { - return \get_option( Options::get_option_name( 'flow' ) ); - } - - /** - * Add onboarding flow options - * - * @param array $data default blueprint flow data. - * - * @return array - */ - private function save_details_to_wp_options( $data ) { - return \add_option( Options::get_option_name( 'flow' ), $data ); - } - - /** - * Update onboarding flow options - * - * @param array $data default blueprint flow data. - * - * @return array - */ - private function update_wp_options_data_in_database( $data ) { - return \update_option( Options::get_option_name( 'flow' ), $data ); - } - - /** - * Function to search for key in array recursively with case sensitive exact match - * - * @param array $needle_key specific key in flow data. - * @param array $array WP Options Data. - * - * @return boolean - */ - private function array_search_key( $needle_key, $array ) { - foreach ( $array as $key => $value ) { - if ( strcmp( $key, $needle_key ) === 0 ) { - return true; - } - if ( is_array( $value ) ) { - $result = $this->array_search_key( $needle_key, $value ); - if ( false !== $result ) { - return $result; - } - } - } - return false; - } - - /** - * Flow completion API for child theme generation, verify child theme and publish site pages + * Flow completion API for child theme generation, verify child theme and publish site pages. * * @return \WP_REST_Response */ @@ -264,4 +147,23 @@ public function complete() { 201 ); } + + /** + * Switch the Onboarding flow. + * + * @param \WP_REST_Request $request The incoming switch request. + * @return \WP_Error|\WP_REST_Response + */ + public function switch( \WP_REST_Request $request ) { + $flow = $request->get_param( 'flow' ); + $status = FlowService::switch_flow( $flow ); + if ( \is_wp_error( $status ) ) { + return $status; + } + + return new \WP_REST_Response( + array(), + 200 + ); + } } diff --git a/includes/Services/FlowService.php b/includes/Services/FlowService.php new file mode 100644 index 000000000..e5edc09c5 --- /dev/null +++ b/includes/Services/FlowService.php @@ -0,0 +1,202 @@ + 404 ) + ); + } + + $flow_data = self::get_flow_data(); + + foreach ( $params as $key => $param ) { + $value = self::array_search_key( $key, $flow_data ); + if ( false === $value ) { + return new \WP_Error( + 'wrong_param_provided', + "Wrong Parameter Provided : $key", + array( 'status' => 404 ) + ); + } + } + + $flow_data = array_replace_recursive( $flow_data, $params ); + + // Update timestamp everytime the Onboarding flow data is updated. + $flow_data['updatedAt'] = time(); + + // Update Blog Information from Basic Info + if ( ( ! empty( $flow_data['data']['blogName'] ) ) ) { + \update_option( Options::get_option_name( 'blog_name', false ), $flow_data['data']['blogName'] ); + } + + if ( ( ! empty( $flow_data['data']['blogDescription'] ) ) ) { + \update_option( Options::get_option_name( 'blog_description', false ), $flow_data['data']['blogDescription'] ); + } + + if ( ( ! empty( $flow_data['data']['siteLogo'] ) ) && ! empty( $flow_data['data']['siteLogo']['id'] ) ) { + \update_option( Options::get_option_name( 'site_icon', false ), $flow_data['data']['siteLogo']['id'] ); + \update_option( Options::get_option_name( 'site_logo', false ), $flow_data['data']['siteLogo']['id'] ); + } else { + \update_option( Options::get_option_name( 'site_icon', false ), 0 ); + \delete_option( Options::get_option_name( 'site_logo', false ) ); + } + + if ( ! self::update_data_in_wp_option( $flow_data ) ) { + return new \WP_Error( + 'database_update_failed', + 'There was an error saving the data', + array( 'status' => 404 ) + ); + } + + return $flow_data; + } + + /** + * Switch the Onboarding flow. + * + * @param string $flow A valid Onboarding flow for a brand. + * @return \WP_Error|boolean + */ + public static function switch_flow( $flow ) { + // Get all the enabled flows for a brand. + $enabled_flows = Flows::get_flows(); + // If the request flow does not exist or is not enabled then return an error. + if ( ! isset( $enabled_flows[ $flow ] ) || true !== $enabled_flows[ $flow ] ) { + return new \WP_Error( + 'nfd_onboarding_error', + 'Flow not enabled.', + array( 'status' => 400 ) + ); + } + + // Reset the Plugin Install Status and Queue. + PluginInstallTaskManager::reset_install_status(); + + // Get the pre requisites for a flow. + $pre_requisites = Preview::get_pre_requisites( $flow ); + if ( ! isset( $pre_requisites ) || ! isset( $pre_requisites['plugins'] ) ) { + return true; + } + + // Install and activate all the required plugins. + foreach ( $pre_requisites['plugins'] as $plugin => $active ) { + // Skip if the plugin installation if it is already active. + if ( 'activated' === $active ) { + continue; + } + + $plugin_install_task = new PluginInstallTask( $plugin, true ); + $status = $plugin_install_task->execute(); + + if ( \is_wp_error( $status ) ) { + return $status; + } + } + + return true; + } + + /** + * Read Onboarding flow data from the wp_option. + * + * @return array + */ + public static function read_data_from_wp_option() { + return \get_option( Options::get_option_name( 'flow' ), false ); + } + + /** + * Update flow data params if the current flow is ecommerce. + * + * @param array $data The flow data. + * + * @return array + */ + private static function update_data_for_ecommerce( $data ) { + // get current flow type + $flow_type = Data::current_flow(); + if ( 'ecommerce' === $flow_type ) { + // update default data with ecommerce data + $data['data']['topPriority']['priority1'] = 'selling'; + $data['data']['siteType'] = array( + 'label' => '', + 'referTo' => 'business', + ); + } + return $data; + } + + /** + * Update Onboarding flow data in the wp_option. + * + * @param array $data default blueprint flow data. + * + * @return array + */ + private static function update_data_in_wp_option( $data ) { + return \update_option( Options::get_option_name( 'flow' ), $data ); + } + + /** + * Search for $needle_key in $array recursively. + * + * @param string $needle_key The key to be searched for. + * @param array $array The array in which the search occurs. + * + * @return boolean + */ + private static function array_search_key( $needle_key, $array ) { + foreach ( $array as $key => $value ) { + if ( strcmp( $key, $needle_key ) === 0 ) { + return true; + } + if ( is_array( $value ) ) { + $result = self::array_search_key( $needle_key, $value ); + if ( false !== $result ) { + return $result; + } + } + } + return false; + } + +} diff --git a/includes/Services/PluginInstaller.php b/includes/Services/PluginInstaller.php index 5dc155e39..86423afd1 100644 --- a/includes/Services/PluginInstaller.php +++ b/includes/Services/PluginInstaller.php @@ -2,10 +2,20 @@ namespace NewfoldLabs\WP\Module\Onboarding\Services; use NewfoldLabs\WP\Module\Onboarding\Data\Plugins; -use NewfoldLabs\WP\Module\Onboarding\Data\Options; +/** + * Class PluginInstaller + */ class PluginInstaller { + /** + * Install a whitelisted plugin. + * + * @param string $plugin The plugin slug from Plugins.php. + * @param boolean $activate Whether to activate the plugin after install. + * + * @return \WP_Error|\WP_REST_Response + */ public static function install( $plugin, $activate ) { $plugins_list = Plugins::get(); @@ -36,23 +46,23 @@ public static function install( $plugin, $activate ) { // If it is not a zip URL then check if it is an approved slug. $plugin = \sanitize_text_field( $plugin ); if ( self::is_nfd_slug( $plugin ) ) { - // [TODO] Better handle mu-plugins and direct file downloads. - if ( $plugin === 'nfd_slug_endurance_page_cache' ) { + // [TODO] Better handle mu-plugins and direct file downloads. + if ( 'nfd_slug_endurance_page_cache' === $plugin ) { return self::install_endurance_page_cache(); } - $plugin_path = $plugins_list['nfd_slugs'][ $plugin ]['path']; + $plugin_path = $plugins_list['nfd_slugs'][ $plugin ]['path']; if ( ! self::is_plugin_installed( $plugin_path ) ) { - $status = self::install_from_zip( $plugins_list['nfd_slugs'][ $plugin ]['url'], $activate ); + $status = self::install_from_zip( $plugins_list['nfd_slugs'][ $plugin ]['url'], $activate ); if ( \is_wp_error( $status ) ) { return $status; } } if ( $activate && ! \is_plugin_active( $plugin_path ) ) { - $status = \activate_plugin( $plugin_path ); + $status = \activate_plugin( $plugin_path ); if ( \is_wp_error( $status ) ) { - $status->add_data( array( 'status' => 500 ) ); + $status->add_data( array( 'status' => 500 ) ); - return $status; + return $status; } } return new \WP_REST_Response( @@ -69,20 +79,26 @@ public static function install( $plugin, $activate ) { ); } - $plugin_path = $plugins_list['wp_slugs'][ $plugin ]['path']; + $plugin_path = $plugins_list['wp_slugs'][ $plugin ]['path']; + $plugin_post_install_callback = isset( $plugins_list['wp_slugs'][ $plugin ]['post_install_callback'] ) + ? $plugins_list['wp_slugs'][ $plugin ]['post_install_callback'] + : false; if ( ! self::is_plugin_installed( $plugin_path ) ) { - $status = self::install_from_wordpress( $plugin, $activate ); + $status = self::install_from_wordpress( $plugin, $activate ); if ( \is_wp_error( $status ) ) { - return $status; + return $status; } } if ( $activate && ! \is_plugin_active( $plugin_path ) ) { - $status = \activate_plugin( $plugin_path ); + $status = \activate_plugin( $plugin_path ); if ( \is_wp_error( $status ) ) { - $status->add_data( array( 'status' => 500 ) ); + $status->add_data( array( 'status' => 500 ) ); - return $status; + return $status; + } + if ( is_callable( $plugin_post_install_callback ) ) { + $plugin_post_install_callback(); } } @@ -93,12 +109,14 @@ public static function install( $plugin, $activate ) { } /** - * @param string $slug Representing the wordpress.org slug. + * Install a plugin from wordpress.org. * + * @param string $plugin The wp_slug to install. + * @param boolean $activate Whether to activate the plugin after install. * @return \WP_REST_Response|\WP_Error */ public static function install_from_wordpress( $plugin, $activate ) { - require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; + require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; $api = \plugins_api( 'plugin_information', @@ -121,9 +139,9 @@ public static function install_from_wordpress( $plugin, $activate ) { return $api; } - $status = self::install_from_zip( $api->download_link, $activate ); + $status = self::install_from_zip( $api->download_link, $activate ); if ( \is_wp_error( $status ) ) { - return $status; + return $status; } return new \WP_REST_Response( @@ -133,8 +151,10 @@ public static function install_from_wordpress( $plugin, $activate ) { } /** - * @param string $url URL to the zip for the plugin. + * Install the plugin from a custom ZIP. * + * @param string $url The ZIP URL to install from. + * @param boolean $activate Whether to activate the plugin after install. * @return \WP_REST_Response|\WP_Error */ public static function install_from_zip( $url, $activate ) { @@ -192,11 +212,11 @@ public static function install_from_zip( $url, $activate ) { } if ( $activate && ! \is_plugin_active( $plugin_file ) ) { - $status = \activate_plugin( $plugin_file ); + $status = \activate_plugin( $plugin_file ); if ( \is_wp_error( $status ) ) { - $status->add_data( array( 'status' => 500 ) ); + $status->add_data( array( 'status' => 500 ) ); - return $status; + return $status; } } @@ -207,25 +227,23 @@ public static function install_from_zip( $url, $activate ) { } /** - * @param string $plugin Slug of the plugin. - * * Checks if a given slug is a valid nfd_slug. Ref: includes/Data/Plugins.php for nfd_slug. * + * @param string $plugin Slug of the plugin. * @return boolean */ public static function is_nfd_slug( $plugin ) { - $plugins_list = Plugins::get(); + $plugins_list = Plugins::get(); if ( isset( $plugins_list['nfd_slugs'][ $plugin ]['approved'] ) ) { - return true; + return true; } - return false; + return false; } /** - * @param string $plugin_path Path to the plugin's header file. - * * Determines if a plugin has already been installed. * + * @param string $plugin_path Path to the plugin's header file. * @return boolean */ public static function is_plugin_installed( $plugin_path ) { @@ -241,50 +259,51 @@ public static function is_plugin_installed( $plugin_path ) { } /** - * @param string $plugin + * Get the type of plugin slug. Ref: includes/Data/Plugins.php for the different types. * - * @return string Type of plugin. Ref: includes/Data/Plugins.php for the different types. + * @param string $plugin The plugin slug to retrieve the type. + * @return string */ public static function get_plugin_type( $plugin ) { if ( \wp_http_validate_url( $plugin ) ) { - return 'urls'; + return 'urls'; } if ( self::is_nfd_slug( $plugin ) ) { - return 'nfd_slugs'; + return 'nfd_slugs'; } - return 'wp_slugs'; + return 'wp_slugs'; } /** - * @param string $plugin - * @param string $plugin_type + * Get the path to the Plugin's header file. * - * @return string Path to the Plugin's header file. + * @param string $plugin The slug of the plugin. + * @param string $plugin_type The type of plugin. + * @return string */ public static function get_plugin_path( $plugin, $plugin_type ) { - $plugin_list = Plugins::get(); - return $plugin_list[ $plugin_type ][ $plugin ]['path']; + $plugin_list = Plugins::get(); + return $plugin_list[ $plugin_type ][ $plugin ]['path']; } /** - * @param string $plugin - * @param string $activate - * * Checks if a plugin with the given slug and activation criteria already exists. * + * @param string $plugin The slug of the plugin to check for + * @param boolean $activate The activation criteria. * @return boolean */ public static function exists( $plugin, $activate ) { - $plugin_type = self::get_plugin_type( $plugin ); - $plugin_path = self::get_plugin_path( $plugin, $plugin_type ); + $plugin_type = self::get_plugin_type( $plugin ); + $plugin_path = self::get_plugin_path( $plugin, $plugin_type ); if ( ! self::is_plugin_installed( $plugin_path ) ) { - return false; + return false; } if ( $activate && ! \is_plugin_active( $plugin_path ) ) { - return false; + return false; } - return true; + return true; } /** @@ -303,11 +322,11 @@ public static function install_endurance_page_cache() { ); } - global $wp_filesystem; + global $wp_filesystem; - $plugin_list = Plugins::get(); - $plugin_url = $plugin_list['nfd_slugs']['nfd_slug_endurance_page_cache']['url']; - $plugin_path = $plugin_list['nfd_slugs']['nfd_slug_endurance_page_cache']['path']; + $plugin_list = Plugins::get(); + $plugin_url = $plugin_list['nfd_slugs']['nfd_slug_endurance_page_cache']['url']; + $plugin_path = $plugin_list['nfd_slugs']['nfd_slug_endurance_page_cache']['path']; if ( $wp_filesystem->exists( $plugin_path ) ) { return new \WP_REST_Response( @@ -317,15 +336,15 @@ public static function install_endurance_page_cache() { } if ( ! $wp_filesystem->is_dir( WP_CONTENT_DIR . '/mu-plugins' ) ) { - $wp_filesystem->mkdir( WP_CONTENT_DIR . '/mu-plugins' ); + $wp_filesystem->mkdir( WP_CONTENT_DIR . '/mu-plugins' ); } - $request = \wp_remote_get( $plugin_url ); + $request = \wp_remote_get( $plugin_url ); if ( \is_wp_error( $request ) ) { - return $request; + return $request; } - $wp_filesystem->put_contents( $plugin_path, $request['body'], FS_CHMOD_FILE ); + $wp_filesystem->put_contents( $plugin_path, $request['body'], FS_CHMOD_FILE ); return new \WP_REST_Response( array(), @@ -343,7 +362,7 @@ protected static function connect_to_filesystem() { // We want to ensure that the user has direct access to the filesystem. $access_type = \get_filesystem_method(); - if ( $access_type !== 'direct' ) { + if ( 'direct' !== $access_type ) { return false; } diff --git a/includes/TaskManagers/PluginInstallTaskManager.php b/includes/TaskManagers/PluginInstallTaskManager.php index c03014281..f5e1d7e4f 100644 --- a/includes/TaskManagers/PluginInstallTaskManager.php +++ b/includes/TaskManagers/PluginInstallTaskManager.php @@ -12,16 +12,24 @@ */ class PluginInstallTaskManager { - /** - * The number of times a PluginInstallTask can be retried. - * - * @var int - */ + /** + * The number of times a PluginInstallTask can be retried. + * + * @var int + */ private static $retry_limit = 1; + /** + * The name of the queue, might be prefixed. + * + * @var string + */ private static $queue_name = 'plugin_install_queue'; - function __construct() { + /** + * Schedules the crons. + */ + public function __construct() { // Ensure there is a thirty second option in the cron schedules add_filter( 'cron_schedules', array( $this, 'add_thirty_seconds_schedule' ) ); @@ -34,10 +42,21 @@ function __construct() { } } + /** + * Returns the queue name, might be prefixed. + * + * @return string + */ public static function get_queue_name() { - return self::$queue_name; + return self::$queue_name; } + /** + * Adds a 30 second cron schedule. + * + * @param array $schedules The existing cron schedule. + * @return array + */ public function add_thirty_seconds_schedule( $schedules ) { if ( ! array_key_exists( 'thirty_seconds', $schedules ) || 30 !== $schedules['thirty_seconds']['interval'] ) { $schedules['thirty_seconds'] = array( @@ -46,9 +65,14 @@ public function add_thirty_seconds_schedule( $schedules ) { ); } - return $schedules; + return $schedules; } + /** + * Queues the initial list of Plugin Installs for a flow. + * + * @return boolean + */ public static function queue_initial_installs() { // Checks if the init_list of plugins have already been queued. @@ -57,7 +81,7 @@ public static function queue_initial_installs() { } // Set option to installing to prevent re-queueing the init_list again on page load. - \update_option( Options::get_option_name( 'plugins_init_status' ), 'installing' ); + \update_option( Options::get_option_name( 'plugins_init_status' ), 'installing' ); // Get the initial list of plugins to be installed based on the plan. $init_plugins = Plugins::get_init(); @@ -86,17 +110,19 @@ public static function queue_initial_installs() { */ public function install() { /* - Get the plugins queued up to be installed, the PluginInstall task gets - converted to an associative array before storing it in the option. */ + Get the plugins queued up to be installed, the PluginInstall task gets + converted to an associative array before storing it in the option. + */ $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() ); /* - Conversion of the max heap to an array will always place the PluginInstallTask with the highest - priority at the beginning of the array */ + Conversion of the max heap to an array will always place the PluginInstallTask with the highest + priority at the beginning of the array + */ $plugin_to_install = array_shift( $plugins ); // Update the plugin install queue. - \update_option( Options::get_option_name( self::$queue_name ), $plugins ); + \update_option( Options::get_option_name( self::$queue_name ), $plugins ); // Recreate the PluginInstall task from the associative array. $plugin_install_task = new PluginInstallTask( @@ -113,15 +139,16 @@ public function install() { $status = $plugin_install_task->execute(); if ( \is_wp_error( $status ) ) { - // If there is an error, then increase the retry count for the task. - $plugin_install_task->increment_retries(); + // If there is an error, then increase the retry count for the task. + $plugin_install_task->increment_retries(); - // Get Latest Value of the install queue - $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() ); + // Get Latest Value of the install queue + $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() ); - /* - If the number of retries have not exceeded the limit - then re-queue the task at the end of the queue to be retried. */ + /* + If the number of retries have not exceeded the limit + then re-queue the task at the end of the queue to be retried. + */ if ( $plugin_install_task->get_retries() <= self::$retry_limit ) { array_push( $plugins, $plugin_install_task->to_array() ); @@ -139,30 +166,30 @@ public function install() { } /** - * @param PluginInstallTask $plugin_install_task - * * Adds a new PluginInstallTask to the Plugin Install queue. * The Task will be inserted at an appropriate position in the queue based on it's priority. * + * @param PluginInstallTask $plugin_install_task The task to be inserted. * @return array|false */ public static function add_to_queue( PluginInstallTask $plugin_install_task ) { /* - Get the plugins queued up to be installed, the PluginInstall task gets - converted to an associative array before storing it in the option. */ + Get the plugins queued up to be installed, the PluginInstall task gets + converted to an associative array before storing it in the option. + */ $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() ); $queue = new PriorityQueue(); foreach ( $plugins as $queued_plugin ) { - /* - Check if there is an already existing PluginInstallTask in the queue - for a given slug and activation criteria. */ + Check if there is an already existing PluginInstallTask in the queue + for a given slug and activation criteria. + */ if ( $queued_plugin['slug'] === $plugin_install_task->get_slug() - && $queued_plugin['activate'] === $plugin_install_task->get_activate() ) { - return false; + && $queued_plugin['activate'] === $plugin_install_task->get_activate() ) { + return false; } - $queue->insert( $queued_plugin, $queued_plugin['priority'] ); + $queue->insert( $queued_plugin, $queued_plugin['priority'] ); } // Insert a new PluginInstallTask at the appropriate position in the queue. @@ -171,29 +198,53 @@ public static function add_to_queue( PluginInstallTask $plugin_install_task ) { $plugin_install_task->get_priority() ); - return \update_option( Options::get_option_name( self::$queue_name ), $queue->to_array() ); + return \update_option( Options::get_option_name( self::$queue_name ), $queue->to_array() ); } + /** + * Removes a PluginInstallTask from the queue. + * + * @param string $plugin The slug of the task to remove. + * @return array + */ public static function remove_from_queue( $plugin ) { /* - Get the plugins queued up to be installed, the PluginInstall task gets - converted to an associative array before storing it in the option. */ + Get the plugins queued up to be installed, the PluginInstall task gets + converted to an associative array before storing it in the option. + */ $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() ); $queue = new PriorityQueue(); foreach ( $plugins as $queued_plugin ) { /* - If the Plugin slug does not match add it back to the queue. */ + If the Plugin slug does not match add it back to the queue. + */ if ( $queued_plugin['slug'] !== $plugin ) { - $queue->insert( $queued_plugin, $queued_plugin['priority'] ); + $queue->insert( $queued_plugin, $queued_plugin['priority'] ); } } - return \update_option( Options::get_option_name( self::$queue_name ), $queue->to_array() ); + return \update_option( Options::get_option_name( self::$queue_name ), $queue->to_array() ); } + /** + * Get the status of a given plugin slug from the queue. + * + * @param string $plugin The slug of the plugin. + * @return boolean + */ public static function status( $plugin ) { $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() ); - return array_search( $plugin, array_column( $plugins, 'slug' ) ); + return array_search( $plugin, array_column( $plugins, 'slug' ), true ); + } + + /** + * Reset the Plugin install status and the queue. + * + * @return void + */ + public static function reset_install_status() { + \delete_option( Options::get_option_name( 'plugins_init_status' ) ); + \delete_option( Options::get_option_name( 'plugin_install_queue' ) ); } } diff --git a/src/OnboardingSPA/components/Content/index.js b/src/OnboardingSPA/components/Content/index.js index f111868d9..46a050b79 100644 --- a/src/OnboardingSPA/components/Content/index.js +++ b/src/OnboardingSPA/components/Content/index.js @@ -3,6 +3,7 @@ import { Fragment, memo, Suspense, useCallback } from '@wordpress/element'; import { store as nfdOnboardingStore } from '../../store'; import { useSelect } from '@wordpress/data'; +import FlowStateHandler from '../StateHandlers/Flow'; /** * Primary content area within the . @@ -17,24 +18,23 @@ const Content = () => { }; } ); - const getMappedPages = useCallback( - ( routes ) => { - return routes?.map( ( route ) => ( - } - /> - ) ); - }, - [ routes ] - ); + const getMappedPages = useCallback( () => { + return routes?.map( ( route ) => ( + } + /> + ) ); + }, [ routes ] ); return (
}> - { getMappedPages( routes ) } + + { getMappedPages( routes ) } +
); diff --git a/src/OnboardingSPA/components/Loaders/Step/Ecommerce/contents.js b/src/OnboardingSPA/components/Loaders/Step/Ecommerce/contents.js new file mode 100644 index 000000000..a9feb7449 --- /dev/null +++ b/src/OnboardingSPA/components/Loaders/Step/Ecommerce/contents.js @@ -0,0 +1,22 @@ +import { __, sprintf } from '@wordpress/i18n'; +import { translations } from '../../../../utils/locales/translations'; + +const getContents = ( brandName ) => { + return { + title: sprintf( + /* translators: 1: Brand 2: Site */ + __( + 'Making the keys to your %1$s Online %2$s', + 'wp-module-onboarding' + ), + brandName, + translations( 'Site' ) + ), + subtitle: __( + 'We’re installing WooCommerce for you to fill with your amazing products & services!', + 'wp-module-onboarding' + ), + }; +}; + +export default getContents; diff --git a/src/OnboardingSPA/components/Loaders/Step/Ecommerce/index.js b/src/OnboardingSPA/components/Loaders/Step/Ecommerce/index.js new file mode 100644 index 000000000..71a7dd320 --- /dev/null +++ b/src/OnboardingSPA/components/Loaders/Step/Ecommerce/index.js @@ -0,0 +1,19 @@ +import StepLoader from '..'; +import getContents from './contents'; +import { useSelect } from '@wordpress/data'; + +import { store as nfdOnboardingStore } from '../../../../store'; + +const EcommerceStepLoader = () => { + const { brandName } = useSelect( ( select ) => { + return { + brandName: select( nfdOnboardingStore ).getNewfoldBrandName(), + }; + }, [] ); + const contents = getContents( brandName ); + return ( + + ); +}; + +export default EcommerceStepLoader; diff --git a/src/OnboardingSPA/components/Sidebar/components/LearnMore/Menu.js b/src/OnboardingSPA/components/Sidebar/components/LearnMore/Menu.js index f95b9b86f..355a41cc1 100644 --- a/src/OnboardingSPA/components/Sidebar/components/LearnMore/Menu.js +++ b/src/OnboardingSPA/components/Sidebar/components/LearnMore/Menu.js @@ -33,7 +33,7 @@ const LearnMoreMenu = () => { return ( <> - { currentStep?.sidebars?.LearnMore && ( + { sideBarView && currentStep?.sidebars?.LearnMore && ( diff --git a/src/OnboardingSPA/components/SkipButton/index.js b/src/OnboardingSPA/components/SkipButton/index.js index 96a475971..d47cb3636 100644 --- a/src/OnboardingSPA/components/SkipButton/index.js +++ b/src/OnboardingSPA/components/SkipButton/index.js @@ -9,12 +9,7 @@ import { store as nfdOnboardingStore } from '../../store'; import { getSettings, setSettings } from '../../utils/api/settings'; import { wpAdminPage, pluginDashboardPage } from '../../../constants'; -/** - * Interface Text Inputs with standard design. - * - * @return {WPComponent} SkipButton Component - */ -const SkipButton = () => { +const SkipButton = ( { callback = false } ) => { const navigate = useNavigate(); const location = useLocation(); const { nextStep, currentData, socialData } = useSelect( ( select ) => { @@ -75,7 +70,12 @@ const SkipButton = () => { return ( diff --git a/src/OnboardingSPA/components/StateHandlers/Ecommerce/contents.js b/src/OnboardingSPA/components/StateHandlers/Ecommerce/contents.js index 6090ca529..e9d1b5707 100644 --- a/src/OnboardingSPA/components/StateHandlers/Ecommerce/contents.js +++ b/src/OnboardingSPA/components/StateHandlers/Ecommerce/contents.js @@ -3,26 +3,11 @@ import { translations } from '../../../utils/locales/translations'; const getContents = ( brandName ) => { return { - loader: { - title: sprintf( - /* translators: 1: Brand 2: Site */ - __( - 'Making the keys to your %s Online %s', - 'wp-module-onboarding' - ), - brandName, - translations( 'Site' ) - ), - subtitle: __( - 'We’re installing WooCommerce for you to fill with your amazing products & services!', - 'wp-module-onboarding' - ), - }, errorState: { title: sprintf( /* translators: 1: Brand 2: Site */ __( - 'Making the keys to your %s Online %s', + 'Making the keys to your %1$s Online %2$s', 'wp-module-onboarding' ), brandName, diff --git a/src/OnboardingSPA/components/StateHandlers/Ecommerce/index.js b/src/OnboardingSPA/components/StateHandlers/Ecommerce/index.js index bf3d7af1a..af582f672 100644 --- a/src/OnboardingSPA/components/StateHandlers/Ecommerce/index.js +++ b/src/OnboardingSPA/components/StateHandlers/Ecommerce/index.js @@ -2,7 +2,6 @@ import { useViewportMatch } from '@wordpress/compose'; import { useSelect, useDispatch } from '@wordpress/data'; import { useEffect, useState } from '@wordpress/element'; -import { StepLoader } from '../../Loaders'; import { store as nfdOnboardingStore } from '../../../store'; import { getPluginStatus } from '../../../utils/api/plugins'; import { @@ -15,6 +14,7 @@ import { } from '../../../../constants'; import { StepErrorState } from '../../ErrorState'; import getContents from './contents'; +import EcommerceStepLoader from '../../Loaders/Step/Ecommerce'; const EcommerceStateHandler = ( { children, @@ -110,8 +110,7 @@ const EcommerceStateHandler = ( { window.location.reload(); break; default: - pluginsStatus[ ECOMMERCE_STEPS_PLUGIN ] = - pluginStatus; + pluginsStatus[ ECOMMERCE_STEPS_PLUGIN ] = pluginStatus; setWoocommerceStatus( pluginStatus ); updatePluginsStatus( pluginsStatus ); } @@ -139,12 +138,7 @@ const EcommerceStateHandler = ( { case PLUGIN_STATUS_ACTIVE: return children; default: - return ( - - ); + return ; } }; diff --git a/src/OnboardingSPA/components/StateHandlers/Flow/index.js b/src/OnboardingSPA/components/StateHandlers/Flow/index.js new file mode 100644 index 000000000..71c187119 --- /dev/null +++ b/src/OnboardingSPA/components/StateHandlers/Flow/index.js @@ -0,0 +1,90 @@ +import { useEffect, useState } from '@wordpress/element'; +import { useLocation } from 'react-router-dom'; +import { useSelect, useDispatch } from '@wordpress/data'; + +import { store as nfdOnboardingStore } from '../../../store'; +import { getFirstEcommerceStep } from '../../../data/routes/ecommerce-flow'; +import EcommerceStepLoader from '../../Loaders/Step/Ecommerce'; +import { switchFlow } from '../../../utils/api/flow'; +import { removeQueryParam } from '../../../utils'; +import { MAX_RETRIES_FLOW_SWITCH } from '../../../../constants'; +import { getFragment } from '@wordpress/url'; + +const FlowStateHandler = ( { children } ) => { + const location = useLocation(); + const [ newFlow, setNewFlow ] = useState( false ); + + const { brandConfig } = useSelect( ( select ) => { + return { + brandName: select( nfdOnboardingStore ).getNewfoldBrandName(), + brandConfig: select( nfdOnboardingStore ).getNewfoldBrandConfig(), + }; + }, [] ); + + const { + setIsDrawerOpened, + setIsDrawerSuppressed, + setIsHeaderNavigationEnabled, + setSidebarActiveView, + } = useDispatch( nfdOnboardingStore ); + + const disableNavigation = () => { + setIsDrawerOpened( false ); + setIsDrawerSuppressed( true ); + setIsHeaderNavigationEnabled( false ); + setSidebarActiveView( false ); + }; + + const handleCommerceFlow = async ( flow, retries = 0 ) => { + if ( retries >= MAX_RETRIES_FLOW_SWITCH ) { + return setNewFlow( false ); + } + const response = await switchFlow( flow ); + if ( response?.error ) { + retries = retries + 1; + return handleCommerceFlow( flow, retries ); + } + const firstEcommerceStep = getFirstEcommerceStep(); + const fragment = getFragment( window.location.href ); + const redirect = removeQueryParam( window.location.href, 'flow' ).replace( fragment, '' ); + window.location.replace( `${ redirect }#${ firstEcommerceStep.path }` ); + window.location.reload(); + }; + + const switchToNewFlow = async ( flow ) => { + const enabledFlows = brandConfig?.enabled_flows ?? {}; + if ( ! ( flow in enabledFlows ) || enabledFlows[ flow ] !== true ) { + return setNewFlow( false ); + } + + switch ( flow ) { + case 'ecommerce': + handleCommerceFlow( flow ); + break; + default: + setNewFlow( false ); + } + }; + + useEffect( () => { + if ( window.nfdOnboarding?.newFlow ) { + const flow = window.nfdOnboarding.newFlow; + disableNavigation(); + setNewFlow( flow ); + switchToNewFlow( flow ); + window.nfdOnboarding.newFlow = undefined; + } + }, [ location.pathname ] ); + + const handleRender = () => { + switch ( newFlow ) { + case 'ecommerce': + return ; + default: + return children; + } + }; + return <>{ handleRender() }; +}; + +export default FlowStateHandler; diff --git a/src/OnboardingSPA/data/routes/ecommerce-flow.js b/src/OnboardingSPA/data/routes/ecommerce-flow.js index 014c2cd85..1a23100a9 100644 --- a/src/OnboardingSPA/data/routes/ecommerce-flow.js +++ b/src/OnboardingSPA/data/routes/ecommerce-flow.js @@ -1,6 +1,7 @@ import { __ } from '@wordpress/i18n'; import { store, institution, shipping } from '@wordpress/icons'; import { lazy } from '@wordpress/element'; +// eslint-disable-next-line import/no-extraneous-dependencies import { orderBy, filter } from 'lodash'; import { @@ -37,11 +38,11 @@ export const ecommerceSteps = [ title: __( 'Street Address', 'wp-module-onboarding' ), heading: __( 'Street Address', 'wp-module-onboarding' ), subheading: __( - 'In this step you confirm the business address of your store. Simply confirm the one you provided during your initial Bluehost account setup or provide a new one.', + 'In this step you confirm the business address of your store. Simply confirm the one you provided during your initial Bluehost account setup or provide a new one.', 'wp-module-onboarding' ), description: __( - 'In this step you confirm the business address of your store. Simply confirm the one you provided during your initial Bluehost account setup or provide a new one.', + 'In this step you confirm the business address of your store. Simply confirm the one you provided during your initial Bluehost account setup or provide a new one.', 'wp-module-onboarding' ), Component: StepAddress, @@ -156,3 +157,7 @@ export const ecommerceGetStartedSteps = () => { ( step ) => ! step.path.includes( '/step/get-started/site-primary' ) ); }; + +export const getFirstEcommerceStep = () => { + return ecommerceSteps[ 0 ]; +}; diff --git a/src/OnboardingSPA/pages/Steps/TopPriority/index.js b/src/OnboardingSPA/pages/Steps/TopPriority/index.js index 29d59ec5f..f4f5155b0 100644 --- a/src/OnboardingSPA/pages/Steps/TopPriority/index.js +++ b/src/OnboardingSPA/pages/Steps/TopPriority/index.js @@ -1,5 +1,4 @@ import { __ } from '@wordpress/i18n'; -import { useNavigate } from 'react-router-dom'; import { useViewportMatch } from '@wordpress/compose'; import { useEffect, useState } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; @@ -11,7 +10,7 @@ import CommonLayout from '../../../components/Layouts/Common'; import HeadingWithSubHeading from '../../../components/HeadingWithSubHeading'; import SelectableCardList from '../../../components/SelectableCardList/selectable-card-list'; -const StepTopPriority = ( props ) => { +const StepTopPriority = () => { const priorityTypes = { 0: 'publishing', 1: 'selling', @@ -21,22 +20,30 @@ const StepTopPriority = ( props ) => { const priorities = [ { icon: '--nfd-publish-icon', - title: 'Publishing', - desc: 'From blogs, to newsletters, to podcasts and videos, we help the web find your content.', + title: __( 'Publishing', 'wp-module-onboarding' ), + desc: __( + 'From blogs, to newsletters, to podcasts and videos, we help the web find your content.', + 'wp-module-onboarding' + ), }, { icon: '--nfd-selling-icon', - title: 'Selling', - desc: "Startup or seasoned business, drop-shipping or downloads, we've got ecommerce covered.", + title: __( 'Selling', 'wp-module-onboarding' ), + desc: __( + "Startup or seasoned business, drop-shipping or downloads, we've got ecommerce covered.", + 'wp-module-onboarding' + ), }, { icon: '--nfd-design-icon', - title: 'Designing', - desc: 'With smart style presets and powerful options, we help your site look and feel polished.', + title: __( 'Designing', 'wp-module-onboarding' ), + desc: __( + 'With smart style presets and powerful options, we help your site look and feel polished.', + 'wp-module-onboarding' + ), }, ]; - const navigate = useNavigate(); const [ selected, setSelected ] = useState( 0 ); const [ isLoaded, setisLoaded ] = useState( false ); const isLargeViewport = useViewportMatch( 'medium' ); @@ -47,17 +54,18 @@ const StepTopPriority = ( props ) => { setSidebarActiveView, setCurrentOnboardingData, setIsDrawerSuppressed, - setIsHeaderNavigationEnabled + setIsHeaderNavigationEnabled, } = useDispatch( nfdOnboardingStore ); const { currentStep, currentData } = useSelect( ( select ) => { return { - currentStep: select(nfdOnboardingStore).getCurrentStep(), - currentData: select( nfdOnboardingStore ).getCurrentOnboardingData(), + currentStep: select( nfdOnboardingStore ).getCurrentStep(), + currentData: + select( nfdOnboardingStore ).getCurrentOnboardingData(), }; }, [] ); - const getKey = ( priorityTypes, value ) => { + const getKey = ( value ) => { return Object?.keys( priorityTypes ).find( ( key ) => priorityTypes[ key ] === value ); @@ -68,7 +76,7 @@ const StepTopPriority = ( props ) => { setIsDrawerOpened( true ); } setSidebarActiveView( SIDEBAR_LEARN_MORE ); - setIsDrawerSuppressed( false ); + setIsDrawerSuppressed( false ); setDrawerActiveView( VIEW_NAV_PRIMARY ); setIsHeaderNavigationEnabled( true ); }, [] ); @@ -77,9 +85,9 @@ const StepTopPriority = ( props ) => { async function setInitialData() { if ( currentData ) { const val = await currentData?.data.topPriority.priority1; - if ( val != '' ) - setSelected( parseInt( getKey( priorityTypes, val ) ) ); - else { + if ( val !== '' ) { + setSelected( parseInt( getKey( val ) ) ); + } else { currentData.data.topPriority.priority1 = priorityTypes[ selected ]; setCurrentOnboardingData( currentData ); @@ -87,20 +95,40 @@ const StepTopPriority = ( props ) => { } setisLoaded( true ); } - if ( ! isLoaded ) setInitialData(); + if ( ! isLoaded ) { + setInitialData(); + } }, [ isLoaded ] ); + const handleSelling = () => { + if ( 'ecommerce' !== window.nfdOnboarding.currentFlow ) { + window.nfdOnboarding.newFlow = 'ecommerce'; + } + }; + useEffect( () => { - if ( isLoaded ) { - currentData.data.topPriority.priority1 = priorityTypes[ selected ]; - setCurrentOnboardingData( currentData ); + const selectedPriorityType = priorityTypes[ selected ]; + currentData.data.topPriority.priority1 = selectedPriorityType; + setCurrentOnboardingData( currentData ); + if ( 'selling' === selectedPriorityType ) { + handleSelling(); + } else { + window.nfdOnboarding.newFlow = undefined; } }, [ selected ] ); + const handleSkip = () => { + window.nfdOnboarding.newFlow = undefined; + currentData.data.topPriority.priority1 = priorityTypes[0] ; + setCurrentOnboardingData( currentData ); + } + return ( + title={ currentStep?.heading } + subtitle={ currentStep?.subheading } + /> { 'wp-module-onboarding' ) }

- +
); diff --git a/src/OnboardingSPA/utils/api/flow.js b/src/OnboardingSPA/utils/api/flow.js index 3bb55b706..f33758e37 100644 --- a/src/OnboardingSPA/utils/api/flow.js +++ b/src/OnboardingSPA/utils/api/flow.js @@ -27,3 +27,15 @@ export async function completeFlow() { } ).then() ); } + +export async function switchFlow( flow ) { + return await resolve( + apiFetch( { + url: onboardingRestURL( 'flow/switch' ), + method: 'POST', + data: { + flow, + }, + } ).then() + ); +} diff --git a/src/OnboardingSPA/utils/index.js b/src/OnboardingSPA/utils/index.js index 6202713d3..5abb1f9f2 100644 --- a/src/OnboardingSPA/utils/index.js +++ b/src/OnboardingSPA/utils/index.js @@ -1,18 +1,13 @@ -import { findIndex } from 'lodash'; - -export const insertBeforeStep = (steps, path, newStep) => {}; - -export const insertAfterStep = (steps, path, newStep) => {}; - -export const insertStepAtIndex = (steps, index, newStep) => {}; - -export const findStepIndex = ( steps, path ) => { - const index = findIndex( steps, { path } ); - - return -1 !== index ? index : false; -}; +import { removeQueryArgs, hasQueryArg } from '@wordpress/url'; export const getQueryParam = ( paramName ) => { - const urlParams = new URLSearchParams( location.search ); + const urlParams = new URLSearchParams( window.location.search ); return urlParams.get( paramName ); }; + +export const removeQueryParam = ( url, paramName ) => { + if ( hasQueryArg( url, paramName ) ) { + return removeQueryArgs( url, paramName ); + } + return url; +}; diff --git a/src/constants.js b/src/constants.js index 75b5df22d..89d277e18 100644 --- a/src/constants.js +++ b/src/constants.js @@ -31,6 +31,7 @@ export const SIDEBAR_MENU_SLOTFILL_PREFIX = 'HeaderMenu'; export const SIDEBAR_LEARN_MORE = 'LearnMore'; export const MAX_RETRIES_SETTINGS_INIT = 2; +export const MAX_RETRIES_FLOW_SWITCH = 2; export const NFD_PLUGINS_QUERY_PARAM = 'nfd_plugins'; export const NFD_THEMES_QUERY_PARAM = 'nfd_themes'; From c04e2f24c352fb1ff1a292b4c9d5c7f8146e8325 Mon Sep 17 00:00:00 2001 From: arunshenoy99 Date: Mon, 17 Apr 2023 22:12:39 +0530 Subject: [PATCH 2/3] fix js lint --- src/OnboardingSPA/components/StateHandlers/Flow/index.js | 5 ++++- src/OnboardingSPA/pages/Steps/TopPriority/index.js | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/OnboardingSPA/components/StateHandlers/Flow/index.js b/src/OnboardingSPA/components/StateHandlers/Flow/index.js index 71c187119..d562e3845 100644 --- a/src/OnboardingSPA/components/StateHandlers/Flow/index.js +++ b/src/OnboardingSPA/components/StateHandlers/Flow/index.js @@ -46,7 +46,10 @@ const FlowStateHandler = ( { children } ) => { } const firstEcommerceStep = getFirstEcommerceStep(); const fragment = getFragment( window.location.href ); - const redirect = removeQueryParam( window.location.href, 'flow' ).replace( fragment, '' ); + const redirect = removeQueryParam( + window.location.href, + 'flow' + ).replace( fragment, '' ); window.location.replace( `${ redirect }#${ firstEcommerceStep.path }` ); window.location.reload(); }; diff --git a/src/OnboardingSPA/pages/Steps/TopPriority/index.js b/src/OnboardingSPA/pages/Steps/TopPriority/index.js index f4f5155b0..f19fc265b 100644 --- a/src/OnboardingSPA/pages/Steps/TopPriority/index.js +++ b/src/OnboardingSPA/pages/Steps/TopPriority/index.js @@ -119,9 +119,9 @@ const StepTopPriority = () => { const handleSkip = () => { window.nfdOnboarding.newFlow = undefined; - currentData.data.topPriority.priority1 = priorityTypes[0] ; + currentData.data.topPriority.priority1 = priorityTypes[ 0 ]; setCurrentOnboardingData( currentData ); - } + }; return ( @@ -146,7 +146,7 @@ const StepTopPriority = () => { 'wp-module-onboarding' ) }

- +
); From af7a7cfa08e62441e0d0fce4a78b2cc8f1e26b3d Mon Sep 17 00:00:00 2001 From: arunshenoy99 Date: Wed, 19 Apr 2023 18:18:09 +0530 Subject: [PATCH 3/3] run the post install callback earlier --- includes/Services/PluginInstaller.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/Services/PluginInstaller.php b/includes/Services/PluginInstaller.php index 86423afd1..89d2eb497 100644 --- a/includes/Services/PluginInstaller.php +++ b/includes/Services/PluginInstaller.php @@ -88,6 +88,9 @@ public static function install( $plugin, $activate ) { if ( \is_wp_error( $status ) ) { return $status; } + if ( is_callable( $plugin_post_install_callback ) ) { + $plugin_post_install_callback(); + } } if ( $activate && ! \is_plugin_active( $plugin_path ) ) { @@ -97,9 +100,6 @@ public static function install( $plugin, $activate ) { return $status; } - if ( is_callable( $plugin_post_install_callback ) ) { - $plugin_post_install_callback(); - } } return new \WP_REST_Response(