s[ $key ]['slug'] = strtolower( preg_replace( '~[^\pL\d]+~u', '-', $products[ $product_type['product'] ]->slug ) ); } elseif ( isset( $product_type['product'] ) ) { /* translators: site currency symbol (used to show that the product costs money) */ $product_types[ $key ]['label'] .= sprintf( __( ' — %s', 'woocommerce' ), html_entity_decode( get_woocommerce_currency_symbol() ) ); } } return $product_types; } /** * Delete the stored themes transient. */ public static function delete_themes_transient() { delete_transient( self::THEMES_TRANSIENT ); } /** * Determine if the current page is home or setup wizard. * * @return bool */ protected function is_home_or_setup_wizard_page() { $allowed_paths = array( 'wc-admin', 'wc-admin&path=/setup-wizard' ); $current_page = PageController::get_instance()->get_current_page(); if ( ! $current_page || ! isset( $current_page['path'] ) ) { return false; } return in_array( $current_page['path'], $allowed_paths ); } /** * Add profiler items to component settings. * * @param array $settings Component settings. * * @return array */ public function component_settings( $settings ) { $profile = (array) get_option( self::PROFILE_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 ( ( ! self::should_show_profiler() && ! self::should_show_tasks() || ! $this->is_home_or_setup_wizard_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']['activeTheme'] = get_option( 'stylesheet' ); $settings['onboarding']['currencySymbols'] = get_woocommerce_currency_symbols(); $settings['onboarding']['euCountries'] = WC()->countries->get_european_union_countries(); $settings['onboarding']['industries'] = self::get_allowed_industries(); $settings['onboarding']['localeInfo'] = include WC()->plugin_path() . '/i18n/locale-info.php'; $settings['onboarding']['productTypes'] = self::get_allowed_product_types(); $settings['onboarding']['profile'] = $profile; $settings['onboarding']['themes'] = self::get_themes(); return $settings; } /** * Preload options to prime state of the application. * * @param array $options Array of options to preload. * @return array */ public function preload_options( $options ) { $options[] = 'woocommerce_task_list_complete'; $options[] = 'woocommerce_task_list_do_this_later'; $options[] = 'woocommerce_task_list_hidden'; $options[] = 'woocommerce_extended_task_list_complete'; $options[] = 'woocommerce_extended_task_list_hidden'; if ( ! self::should_show_tasks() && ! self::should_show_profiler() ) { return $options; } $options[] = 'wc_connect_options'; $options[] = 'woocommerce_task_list_welcome_modal_dismissed'; $options[] = 'woocommerce_welcome_from_calypso_modal_dismissed'; $options[] = 'woocommerce_task_list_prompt_shown'; $options[] = 'woocommerce_task_list_tracked_completed_tasks'; $options[] = 'woocommerce_task_list_dismissed_tasks'; $options[] = 'woocommerce_allow_tracking'; $options[] = 'woocommerce_stripe_settings'; $options[] = 'woocommerce-ppcp-settings'; $options[] = 'woocommerce_ppcp-gateway_settings'; $options[] = 'wc_square_refresh_tokens'; $options[] = 'woocommerce_square_credit_card_settings'; $options[] = 'woocommerce_payfast_settings'; $options[] = 'woocommerce_kco_settings'; $options[] = 'woocommerce_klarna_payments_settings'; $options[] = 'woocommerce_cod_settings'; $options[] = 'woocommerce_bacs_settings'; $options[] = 'woocommerce_bacs_accounts'; $options[] = 'woocommerce_woocommerce_payments_settings'; $options[] = 'woocommerce_eway_settings'; $options[] = 'woocommerce_razorpay_settings'; $options[] = 'woocommerce_payubiz_settings'; $options[] = 'woocommerce_mollie_payments_settings'; return $options; } /** * 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; } /** * Gets an array of plugins that can be installed & activated via the onboarding wizard. * * @param array $plugins Array of plugin slugs to be allowed. * * @return array * @todo Handle edgecase of where installed plugins may have versioned folder names (i.e. `jetpack-main/jetpack.php`). */ public static function get_onboarding_allowed_plugins( $plugins ) { $onboarding_plugins = apply_filters( 'woocommerce_admin_onboarding_plugins_whitelist', array( 'facebook-for-woocommerce' => 'facebook-for-woocommerce/facebook-for-woocommerce.php', 'mailchimp-for-woocommerce' => 'mailchimp-for-woocommerce/mailchimp-woocommerce.php', 'creative-mail-by-constant-contact' => 'creative-mail-by-constant-contact/creative-mail-plugin.php', 'kliken-marketing-for-google' => 'kliken-marketing-for-google/kliken-marketing-for-google.php', 'jetpack' => 'jetpack/jetpack.php', 'woocommerce-services' => 'woocommerce-services/woocommerce-services.php', 'woocommerce-gateway-stripe' => 'woocommerce-gateway-stripe/woocommerce-gateway-stripe.php', 'woocommerce-paypal-payments' => 'woocommerce-paypal-payments/woocommerce-paypal-payments.php', 'klarna-checkout-for-woocommerce' => 'klarna-checkout-for-woocommerce/klarna-checkout-for-woocommerce.php', 'klarna-payments-for-woocommerce' => 'klarna-payments-for-woocommerce/klarna-payments-for-woocommerce.php', 'woocommerce-square' => 'woocommerce-square/woocommerce-square.php', 'woocommerce-shipstation-integration' => 'woocommerce-shipstation-integration/woocommerce-shipstation.php', 'woocommerce-payfast-gateway' => 'woocommerce-payfast-gateway/gateway-payfast.php', 'woocommerce-payments' => 'woocommerce-payments/woocommerce-payments.php', 'woocommerce-gateway-eway' => 'woocommerce-gateway-eway/woocommerce-gateway-eway.php', 'woo-razorpay' => 'woo-razorpay/woo-razorpay.php', 'mollie-payments-for-woocommerce' => 'mollie-payments-for-woocommerce/mollie-payments-for-woocommerce.php', 'payu-india' => 'payu-india/index.php', ) ); return array_merge( $plugins, $onboarding_plugins ); } /** * Gets an array of themes that can be installed & activated via the onboarding wizard. * * @return array */ public static function get_allowed_themes() { $allowed_themes = array(); $themes = self::get_themes(); foreach ( $themes as $theme ) { $price = preg_replace( '/&#?[a-z0-9]+;/i', '', $theme['price'] ); if ( $theme['is_installed'] || '0.00' === $price ) { $allowed_themes[] = $theme['slug']; } } return apply_filters( 'woocommerce_admin_onboarding_themes_whitelist', $allowed_themes ); } /** * Let the app know that we will be showing the onboarding route, so wp-admin elements should be hidden while loading. * * @param bool $is_loading Indicates if the `woocommerce-admin-is-loading` should be appended or not. * @return bool */ public function is_loading( $is_loading ) { $show_profiler = self::should_show_profiler(); if ( $show_profiler ) { return true; } return $is_loading; } /** * Instead of redirecting back to the payment settings page, we will redirect back to the payments task list with our status. * * @param string $location URL of redirect. * @param int $status HTTP response status code. * @return string URL of redirect. */ public function overwrite_paypal_redirect( $location, $status ) { $settings_page = 'tab=checkout§ion=ppec_paypal'; if ( substr( $location, -strlen( $settings_page ) ) === $settings_page ) { $settings_array = (array) get_option( 'woocommerce_ppec_paypal_settings', array() ); $connected = isset( $settings_array['api_username'] ) && isset( $settings_array['api_password'] ) ? true : false; return wc_admin_url( '&task=payments&method=paypal&paypal-connect=' . $connected ); } return $location; } /** * Finishes the PayPal connection process by saving the correct settings. */ public function finish_paypal_connect() { if ( ! Loader::is_admin_page() || ! isset( $_GET['paypal-connect-finish'] ) // phpcs:ignore CSRF ok. ) { return; } if ( ! function_exists( 'wc_gateway_ppec' ) ) { return false; } // @todo This is a bit hacky but works. Ideally, woocommerce-gateway-paypal-express-checkout would contain a filter for us. add_filter( 'wp_redirect', array( $this, 'overwrite_paypal_redirect' ), 10, 2 ); wc_gateway_ppec()->ips->maybe_received_credentials(); remove_filter( 'wp_redirect', array( $this, 'overwrite_paypal_redirect' ) ); } /** * Instead of redirecting back to the payment settings page, we will redirect back to the payments task list with our status. * * @param string $location URL of redirect. * @param int $status HTTP response status code. * @return string URL of redirect. */ public function overwrite_square_redirect( $location, $status ) { $settings_page = 'page=wc-settings&tab=square'; if ( substr( $location, -strlen( $settings_page ) ) === $settings_page ) { return wc_admin_url( '&task=payments&method=square&square-connect=1' ); } return $location; } /** * Finishes the Square connection process by saving the correct settings. */ public function finish_square_connect() { if ( ! Loader::is_admin_page() || ! isset( $_GET['square-connect-finish'] ) // phpcs:ignore CSRF ok. ) { return; } if ( ! class_exists( '\WooCommerce\Square\Plugin' ) ) { return false; } $square = \WooCommerce\Square\Plugin::instance(); // @todo This is a bit hacky but works. Ideally, woocommerce-square would contain a filter for us. add_filter( 'wp_redirect', array( $this, 'overwrite_square_redirect' ), 10, 2 ); $square->get_connection_handler()->handle_connected(); remove_filter( 'wp_redirect', array( $this, 'overwrite_square_redirect' ) ); } /** * Track changes to the onboarding option. * * @param mixed $mixed Option name or previous value if option previously existed. * @param string $value Value of the updated option. */ public static function track_onboarding_toggle( $mixed, $value ) { if ( defined( 'WC_ADMIN_MIGRATING_OPTIONS' ) && WC_ADMIN_MIGRATING_OPTIONS ) { return; }; wc_admin_record_tracks_event( 'onboarding_toggled', array( 'previous_value' => ! $value, 'new_value' => $value, ) ); } /** * Update the help tab setup link to reset the onboarding profiler. */ public static function add_help_tab() { if ( ! function_exists( 'wc_get_screen_ids' ) ) { return; } $screen = get_current_screen(); if ( ! $screen || ! in_array( $screen->id, wc_get_screen_ids(), true ) ) { return; } // Remove the old help tab if it exists. $help_tabs = $screen->get_help_tabs(); foreach ( $help_tabs as $help_tab ) { if ( 'woocommerce_onboard_tab' !== $help_tab['id'] ) { continue; } $screen->remove_help_tab( 'woocommerce_onboard_tab' ); } // Add the new help tab. $help_tab = array( 'title' => __( 'Setup wizard', 'woocommerce' ), 'id' => 'woocommerce_onboard_tab', ); $task_list_hidden = ( 'yes' === get_option( 'woocommerce_task_list_hidden', 'no' ) ); $extended_task_list_hidden = ( 'yes' === get_option( 'woocommerce_extended_task_list_hidden', 'no' ) ); $help_tab['content'] = '

' . __( 'WooCommerce Onboarding', 'woocommerce' ) . '

'; $help_tab['content'] .= '

' . __( 'Profile Setup Wizard', 'woocommerce' ) . '

'; $help_tab['content'] .= '

' . __( 'If you need to access the setup wizard again, please click on the button below.', 'woocommerce' ) . '

' . '

' . __( 'Setup wizard', 'woocommerce' ) . '

'; $help_tab['content'] .= '

' . __( 'Task List', 'woocommerce' ) . '

'; $help_tab['content'] .= '

' . __( 'If you need to enable or disable the task lists, please click on the button below.', 'woocommerce' ) . '

' . ( $task_list_hidden ? '

' . __( 'Enable', 'woocommerce' ) . '

' : '

' . __( 'Disable', 'woocommerce' ) . '

' ); $help_tab['content'] .= '

' . __( 'Extended task List', 'woocommerce' ) . '

'; $help_tab['content'] .= '

' . __( 'If you need to enable or disable the extended task lists, please click on the button below.', 'woocommerce' ) . '

' . ( $extended_task_list_hidden ? '

' . __( 'Enable', 'woocommerce' ) . '

' : '

' . __( 'Disable', 'woocommerce' ) . '

' ); $screen->add_help_tab( $help_tab ); } /** * Reset the onboarding profiler and redirect to the profiler. */ public static function reset_profiler() { if ( ! Loader::is_admin_page() || ! isset( $_GET['reset_profiler'] ) // phpcs:ignore CSRF ok. ) { return; } $previous = 1 === absint( $_GET['reset_profiler'] ); // phpcs:ignore CSRF ok. $new_value = ! $previous; wc_admin_record_tracks_event( 'storeprofiler_toggled', array( 'previous' => $previous, 'new_value' => $new_value, ) ); $request = new \WP_REST_Request( 'POST', '/wc-admin/onboarding/profile' ); $request->set_headers( array( 'content-type' => 'application/json' ) ); $request->set_body( wp_json_encode( array( 'completed' => $new_value, 'skipped' => $new_value, ) ) ); $response = rest_do_request( $request ); wp_safe_redirect( wc_admin_url() ); exit; } /** * Reset the onboarding task list and redirect to the dashboard. */ public static function reset_task_list() { if ( ! Loader::is_admin_page() || ! isset( $_GET['reset_task_list'] ) // phpcs:ignore CSRF ok. ) { return; } $task_list_hidden = 1 === absint( $_GET['reset_task_list'] ) ? 'no' : 'yes'; // phpcs:ignore CSRF ok. update_option( 'woocommerce_task_list_hidden', $task_list_hidden ); wc_admin_record_tracks_event( 'tasklist_toggled', array( 'status' => 'yes' === $task_list_hidden ? 'disabled' : 'enabled', ) ); wp_safe_redirect( wc_admin_url() ); exit; } /** * Reset the extended task list and redirect to the dashboard. */ public static function reset_extended_task_list() { if ( ! Loader::is_admin_page() || ! isset( $_GET['reset_extended_task_list'] ) // phpcs:ignore CSRF ok. ) { return; } $extended_task_list_hidden = 1 === absint( $_GET['reset_extended_task_list'] ) ? 'no' : 'yes'; // phpcs:ignore CSRF ok. update_option( 'woocommerce_extended_task_list_hidden', $extended_task_list_hidden ); wc_admin_record_tracks_event( 'extended_tasklist_toggled', array( 'status' => 'yes' === $extended_task_list_hidden ? 'disabled' : 'enabled', ) ); wp_safe_redirect( wc_admin_url() ); exit; } /** * 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 static function remove_install_notice( $show, $notice ) { if ( 'install' === $notice ) { return false; } return $show; } /** * Redirects the user to the task list if the task list is enabled and finishing a wccom checkout. * * @todo Once URL params are added to the redirect, we can check those instead of the referer. */ public static function redirect_wccom_install() { if ( ! self::should_show_tasks() || ! isset( $_SERVER['HTTP_REFERER'] ) || 0 !== strpos( $_SERVER['HTTP_REFERER'], 'https://woocommerce.com/checkout' ) // phpcs:ignore sanitization ok. ) { return; } wp_safe_redirect( wc_admin_url() ); } /** * When updating WooCommerce, mark the profiler and task list complete. * * @todo The `maybe_enable_setup_wizard()` method should be revamped on onboarding enable in core. * See https://github.com/woocommerce/woocommerce/blob/1ca791f8f2325fe2ee0947b9c47e6a4627366374/includes/class-wc-install.php#L341 */ public static function maybe_mark_complete() { // The install notice still exists so don't complete the profiler. if ( ! class_exists( 'WC_Admin_Notices' ) || \WC_Admin_Notices::has_notice( 'install' ) ) { return; } $onboarding_data = get_option( self::PROFILE_DATA_OPTION, array() ); // Don't make updates if the profiler is completed, but task list is potentially incomplete. if ( isset( $onboarding_data['completed'] ) && $onboarding_data['completed'] ) { return; } $onboarding_data['completed'] = true; update_option( self::PROFILE_DATA_OPTION, $onboarding_data ); update_option( 'woocommerce_task_list_hidden', 'yes' ); } }