관리-도구
편집 파일: Onboarding.php
<?php /** * Kkart Onboarding * NOTE: DO NOT edit this file in Kkart core, this is generated from kkart-admin. */ namespace Automattic\Kkart\Admin\Features; use \Automattic\Kkart\Admin\Loader; use \Automattic\Kkart\Admin\PluginsHelper; use \Automattic\Kkart\Admin\Features\OnboardingSetUpShipping; use \Automattic\Kkart\Admin\Features\OnboardingAutomateTaxes; /** * Contains backend logic for the onboarding profile and checklist feature. */ class Onboarding { /** * Class instance. * * @var Onboarding instance */ protected static $instance = null; /** * Name of themes transient. * * @var string */ const THEMES_TRANSIENT = 'kkart_onboarding_themes'; /** * Name of product data transient. * * @var string */ const PRODUCT_DATA_TRANSIENT = 'kkart_onboarding_product_data'; /** * Profile data option name. */ const PROFILE_DATA_OPTION = 'kkart_onboarding_profile'; /** * Get class instance. */ public static function get_instance() { if ( ! self::$instance ) { self::$instance = new self(); } return self::$instance; } /** * Hook into Kkart. */ public function __construct() { $this->add_toggle_actions(); // Include KKART Admin Onboarding classes. if ( self::should_show_tasks() ) { OnboardingTasks::get_instance(); } // Add actions and filters. $this->add_actions(); $this->add_filters(); // Hook up dependent classes. new OnboardingSetUpShipping(); new OnboardingAutomateTaxes(); } /** * Adds the ability to toggle the new onboarding experience on or off. */ private function add_toggle_actions() { add_action( 'kkart_updated', array( $this, 'maybe_mark_complete' ) ); add_action( 'update_option_' . self::PROFILE_DATA_OPTION, array( $this, 'send_profile_data_on_update' ), 10, 2 ); add_action( 'kkart_helper_connected', array( $this, 'send_profile_data_on_connect' ) ); } /** * Add onboarding actions. */ private function add_actions() { // Rest API hooks need to run before is_admin() checks. add_action( 'kkart_theme_installed', array( $this, 'delete_themes_transient' ) ); add_action( 'after_switch_theme', array( $this, 'delete_themes_transient' ) ); add_action( 'update_option_' . self::PROFILE_DATA_OPTION, array( $this, 'trigger_profile_completed_action', ), 10, 2 ); // Always hook into Jetpack connection even if outside of admin. add_action( 'jetpack_site_registered', array( $this, 'set_kkart_setup_jetpack_opted_in' ) ); if ( ! is_admin() ) { return; } add_action( 'admin_init', array( $this, 'admin_redirects' ) ); add_action( 'current_screen', array( $this, 'finish_paypal_connect' ) ); add_action( 'current_screen', array( $this, 'finish_square_connect' ) ); add_action( 'current_screen', array( $this, 'add_help_tab' ), 60 ); add_action( 'current_screen', array( $this, 'reset_profiler' ) ); add_action( 'current_screen', array( $this, 'reset_task_list' ) ); add_action( 'current_screen', array( $this, 'calypso_tests' ) ); add_action( 'current_screen', array( $this, 'redirect_wccom_install' ) ); add_action( 'current_screen', array( $this, 'redirect_old_onboarding' ) ); } /** * Test whether the context of execution comes from async action scheduler. * Note: this is a polyfill for kkart_is_running_from_async_action_scheduler() * which was introduced in KKART 4.0. * * @return bool */ public static function is_running_from_async_action_scheduler() { if ( function_exists( '\kkart_is_running_from_async_action_scheduler' ) ) { return \kkart_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 admin_redirects() { // Don't run this fn from Action Scheduler requests, as it would clear _kkart_activation_redirect transient. // That means OBW would never be shown. if ( self::is_running_from_async_action_scheduler() ) { return; } // Setup wizard redirect. if ( get_transient( '_kkart_activation_redirect' ) && apply_filters( 'kkart_enable_setup_wizard', true ) ) { $do_redirect = true; $current_page = isset( $_GET['page'] ) ? kkart_clean( wp_unslash( $_GET['page'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification $is_onboarding_path = ! isset( $_GET['path'] ) || '/setup-wizard' === kkart_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_kkart' ) ) { $do_redirect = false; } // On these pages, or during these events, disable the redirect. if ( ( 'kkart-admin' === $current_page && $is_onboarding_path ) || apply_filters( 'kkart_prevent_automatic_wizard_redirect', false ) || isset( $_GET['activate-multi'] ) // phpcs:ignore WordPress.Security.NonceVerification ) { delete_transient( '_kkart_activation_redirect' ); $do_redirect = false; } if ( $do_redirect ) { delete_transient( '_kkart_activation_redirect' ); wp_safe_redirect( kkart_admin_url() ); exit; } } } /** * Sets the kkart_setup_jetpack_opted_in to true when Jetpack connects to WPCOM. */ public function set_kkart_setup_jetpack_opted_in() { update_option( 'kkart_setup_jetpack_opted_in', true ); } /** * Trigger the kkart_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( 'kkart_onboarding_profile_completed' ); } /** * Add onboarding filters. */ private function add_filters() { // Rest API hooks need to run before is_admin() checks. add_filter( 'kkart_rest_prepare_themes', array( $this, 'add_uploaded_theme_data' ) ); add_filter( 'kkart_admin_plugins_whitelist', array( $this, 'get_onboarding_allowed_plugins' ), 10, 2 ); if ( ! is_admin() ) { return; } // Old settings injection. // Run after Automattic\Kkart\Admin\Loader. add_filter( 'kkart_components_settings', array( $this, 'component_settings' ), 20 ); // New settings injection. add_filter( 'kkart_shared_settings', array( $this, 'component_settings' ), 20 ); add_filter( 'kkart_admin_preload_options', array( $this, 'preload_options' ) ); add_filter( 'kkart_admin_preload_settings', array( $this, 'preload_settings' ) ); add_filter( 'kkart_admin_is_loading', array( $this, 'is_loading' ) ); add_filter( 'kkart_show_admin_notice', array( $this, 'remove_install_notice' ), 10, 2 ); } /** * Send profile data to Kkart.com. */ public static function send_profile_data() { if ( 'yes' !== get_option( 'kkart_allow_tracking', 'no' ) ) { return; } if ( ! class_exists( '\KKART_Helper_API' ) || ! method_exists( '\KKART_Helper_API', 'put' ) ) { return; } if ( ! class_exists( '\KKART_Helper_Options' ) ) { return; } $auth = \KKART_Helper_Options::get( 'auth' ); if ( empty( $auth['access_token'] ) || empty( $auth['access_token_secret'] ) ) { return false; } $profile = get_option( self::PROFILE_DATA_OPTION, array() ); $base_location = kkart_get_base_location(); $defaults = array( 'plugins' => 'skipped', 'industry' => array(), 'product_types' => array(), 'product_count' => '0', 'selling_venues' => 'no', 'revenue' => 'none', 'other_platform' => 'none', 'business_extensions' => array(), 'theme' => get_stylesheet(), 'setup_client' => false, 'store_location' => $base_location['country'], 'default_currency' => get_kkart_currency(), ); // Prepare industries as an array of slugs if they are in array format. if ( isset( $profile['industry'] ) && is_array( $profile['industry'] ) ) { $industry_slugs = array(); foreach ( $profile['industry'] as $industry ) { $industry_slugs[] = is_array( $industry ) ? $industry['slug'] : $industry; } $profile['industry'] = $industry_slugs; } $body = wp_parse_args( $profile, $defaults ); \KKART_Helper_API::put( 'profile', array( 'authenticated' => true, 'body' => wp_json_encode( $body ), 'headers' => array( 'Content-Type' => 'application/json', ), ) ); } /** * Send profiler data on profiler change to completion. * * @param array $old_value Previous value. * @param array $value Current value. */ public static function send_profile_data_on_update( $old_value, $value ) { if ( ! isset( $value['completed'] ) || ! $value['completed'] ) { return; } self::send_profile_data(); } /** * Send profiler data after a site is connected. */ public static function send_profile_data_on_connect() { $profile = get_option( self::PROFILE_DATA_OPTION, array() ); if ( ! isset( $profile['completed'] ) || ! $profile['completed'] ) { return; } self::send_profile_data(); } /** * Redirect the old onboarding wizard to the profiler. */ public static function redirect_old_onboarding() { $current_page = isset( $_GET['page'] ) ? kkart_clean( wp_unslash( $_GET['page'] ) ) : false; // phpcs:ignore csrf okay. if ( 'kkart-setup' === $current_page ) { delete_transient( '_kkart_activation_redirect' ); wp_safe_redirect( kkart_admin_url( '&reset_profiler=1' ) ); } } /** * Returns true if the profiler should be displayed (not completed and not skipped). * * @return bool */ public static function should_show_profiler() { /* phpcs:disable WordPress.Security.NonceVerification */ $is_current_page = isset( $_GET['page'] ) && 'kkart-admin' === $_GET['page'] && isset( $_GET['path'] ) && '/setup-wizard' === $_GET['path']; /* phpcs: enable */ if ( $is_current_page ) { return true; } $onboarding_data = get_option( self::PROFILE_DATA_OPTION, array() ); $is_completed = isset( $onboarding_data['completed'] ) && true === $onboarding_data['completed']; $is_skipped = isset( $onboarding_data['skipped'] ) && true === $onboarding_data['skipped']; // @todo When merging to Kkart Core, we should set the `completed` flag to true during the upgrade progress. // https://github.com/kkart/kkart-admin/pull/2300#discussion_r287237498. return ! $is_completed && ! $is_skipped; } /** * Returns true if the task list should be displayed (not completed or hidden off the dashboard). * * @return bool */ public static function should_show_tasks() { return 'no' === get_option( 'kkart_task_list_hidden', 'no' ); } /** * Get a list of allowed industries for the onboarding wizard. * * @return array */ public static function get_allowed_industries() { /* With "use_description" we turn the description input on. With "description_label" we set the input label */ return apply_filters( 'kkart_admin_onboarding_industries', array( 'fashion-apparel-accessories' => array( 'label' => __( 'Fashion, apparel, and accessories', 'kkart' ), 'use_description' => false, 'description_label' => '', ), 'health-beauty' => array( 'label' => __( 'Health and beauty', 'kkart' ), 'use_description' => false, 'description_label' => '', ), 'electronics-computers' => array( 'label' => __( 'Electronics and computers', 'kkart' ), 'use_description' => false, 'description_label' => '', ), 'food-drink' => array( 'label' => __( 'Food and drink', 'kkart' ), 'use_description' => false, 'description_label' => '', ), 'home-furniture-garden' => array( 'label' => __( 'Home, furniture, and garden', 'kkart' ), 'use_description' => false, 'description_label' => '', ), 'cbd-other-hemp-derived-products' => array( 'label' => __( 'CBD and other hemp-derived products', 'kkart' ), 'use_description' => false, 'description_label' => '', ), 'education-and-learning' => array( 'label' => __( 'Education and learning', 'kkart' ), 'use_description' => false, 'description_label' => '', ), 'other' => array( 'label' => __( 'Other', 'kkart' ), 'use_description' => true, 'description_label' => 'Description', ), ) ); } /** * Get a list of allowed product types for the onboarding wizard. * * @return array */ public static function get_allowed_product_types() { $product_types = self::append_product_data( array( 'physical' => array( 'label' => __( 'Physical products', 'kkart' ), 'default' => true, ), 'downloads' => array( 'label' => __( 'Downloads', 'kkart' ), ), 'subscriptions' => array( 'label' => __( 'Subscriptions', 'kkart' ), 'product' => 27147, ), 'memberships' => array( 'label' => __( 'Memberships', 'kkart' ), 'product' => 958589, ), 'bookings' => array( 'label' => __( 'Bookings', 'kkart' ), 'product' => 390890, ), 'product-bundles' => array( 'label' => __( 'Bundles', 'kkart' ), 'product' => 18716, ), 'product-add-ons' => array( 'label' => __( 'Customizable products', 'kkart' ), 'product' => 18618, ), ) ); return apply_filters( 'kkart_admin_onboarding_product_types', $product_types ); } /** * Sort themes returned from Kkart.com * * @param array $themes Array of themes from Kkart.com. * @return array */ public static function sort_kkart_themes( $themes ) { usort( $themes, function ( $product_1, $product_2 ) { if ( ! property_exists( $product_1, 'id' ) || ! property_exists( $product_1, 'slug' ) ) { return 1; } if ( ! property_exists( $product_2, 'id' ) || ! property_exists( $product_2, 'slug' ) ) { return 1; } if ( in_array( 'Storefront', array( $product_1->slug, $product_2->slug ), true ) ) { return 'Storefront' === $product_1->slug ? -1 : 1; } return $product_1->id < $product_2->id ? 1 : -1; } ); return $themes; } /** * Get a list of themes for the onboarding wizard. * * @return array */ public static function get_themes() { $themes = get_transient( self::THEMES_TRANSIENT ); if ( false === $themes ) { $theme_data = wp_remote_get( 'https://kkart.com/sp-json/wccom-extensions/1.0/search?category=themes' ); $themes = array(); if ( ! is_wp_error( $theme_data ) ) { $theme_data = json_decode( $theme_data['body'] ); $woo_themes = property_exists( $theme_data, 'products' ) ? $theme_data->products : array(); $sorted_themes = self::sort_kkart_themes( $woo_themes ); foreach ( $sorted_themes as $theme ) { $slug = sanitize_title_with_dashes( $theme->slug ); $themes[ $slug ] = (array) $theme; $themes[ $slug ]['is_installed'] = false; $themes[ $slug ]['has_kkart_support'] = true; $themes[ $slug ]['slug'] = $slug; } } $installed_themes = wp_get_themes(); $active_theme = get_option( 'stylesheet' ); foreach ( $installed_themes as $slug => $theme ) { $theme_data = self::get_theme_data( $theme ); $installed_themes = wp_get_themes(); $themes[ $slug ] = $theme_data; } // Add the Kkart support tag for default themes that don't explicitly declare support. if ( function_exists( 'kkart_is_wp_default_theme_active' ) && kkart_is_wp_default_theme_active() ) { $themes[ $active_theme ]['has_kkart_support'] = true; } $themes = array( $active_theme => $themes[ $active_theme ] ) + $themes; set_transient( self::THEMES_TRANSIENT, $themes, DAY_IN_SECONDS ); } $themes = apply_filters( 'kkart_admin_onboarding_themes', $themes ); return array_values( $themes ); } /** * Get theme data used in onboarding theme browser. * * @param WP_Theme $theme Theme to gather data from. * @return array */ public static function get_theme_data( $theme ) { return array( 'slug' => sanitize_text_field( $theme->stylesheet ), 'title' => $theme->get( 'Name' ), 'price' => '0.00', 'is_installed' => true, 'image' => $theme->get_screenshot(), 'has_kkart_support' => self::has_kkart_support( $theme ), ); } /** * Add theme data to response from themes controller. * * @param WP_REST_Response $response Rest response. * @return WP_REST_Response */ public static function add_uploaded_theme_data( $response ) { if ( ! isset( $response->data['theme'] ) ) { return $response; } $theme = wp_get_theme( $response->data['theme'] ); $response->data['theme_data'] = self::get_theme_data( $theme ); return $response; } /** * Check if theme has declared support for Kkart. * * @param WP_Theme $theme Theme to check. * @return bool */ public static function has_kkart_support( $theme ) { $themes = array( $theme ); if ( $theme->get( 'Template' ) ) { $parent_theme = wp_get_theme( $theme->get( 'Template' ) ); $themes[] = $parent_theme; } foreach ( $themes as $theme ) { $directory = new \RecursiveDirectoryIterator( $theme->theme_root . '/' . $theme->stylesheet ); $iterator = new \RecursiveIteratorIterator( $directory ); $files = new \RegexIterator( $iterator, '/^.+\.php$/i', \RecursiveRegexIterator::GET_MATCH ); foreach ( $files as $file ) { $content = file_get_contents( $file[0] ); if ( preg_match( '/add_theme_support\(([^(]*)(\'|\")kkart(\'|\")([^(]*)/si', $content, $matches ) ) { return true; } } } return false; } /** * Append dynamic product data from API. * * @param array $product_types Array of product types. * @return array */ public static function append_product_data( $product_types ) { $kkart_products = get_transient( self::PRODUCT_DATA_TRANSIENT ); if ( false === $kkart_products ) { $kkart_products = wp_remote_get( 'https://kkart.com/sp-json/wccom-extensions/1.0/search' ); if ( is_wp_error( $kkart_products ) ) { return $product_types; } set_transient( self::PRODUCT_DATA_TRANSIENT, $kkart_products, DAY_IN_SECONDS ); } $product_data = json_decode( $kkart_products['body'] ); $products = array(); // Map product data by ID. if ( isset( $product_data ) && isset( $product_data->products ) ) { foreach ( $product_data->products as $product_datum ) { if ( isset( $product_datum->id ) ) { $products[ $product_datum->id ] = $product_datum; } } } // Loop over product types and append data. foreach ( $product_types as $key => $product_type ) { if ( isset( $product_type['product'] ) && isset( $products[ $product_type['product'] ] ) ) { $price = html_entity_decode( $products[ $product_type['product'] ]->price ); $yearly_price = (float) str_replace( '$', '', $price ); $product_types[ $key ]['yearly_price'] = $yearly_price; $product_types[ $key ]['description'] = $products[ $product_type['product'] ]->excerpt; $product_types[ $key ]['more_url'] = $products[ $product_type['product'] ]->link; $product_types[ $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', 'kkart' ), html_entity_decode( get_kkart_currency_symbol() ) ); } } return $product_types; } /** * Delete the stored themes transient. */ public static function delete_themes_transient() { delete_transient( self::THEMES_TRANSIENT ); } /** * Add profiler items to component settings. * * @param array $settings Component settings. */ 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. if ( ! self::should_show_profiler() && ! self::should_show_tasks() ) { return $settings; } include_once KKART_ABSPATH . 'includes/admin/helper/class-kkart-helper-options.php'; $wccom_auth = \KKART_Helper_Options::get( 'auth' ); $profile['wccom_connected'] = empty( $wccom_auth['access_token'] ) ? false : true; $settings['onboarding']['activeTheme'] = get_option( 'stylesheet' ); $settings['onboarding']['euCountries'] = KKART()->countries->get_european_union_countries(); $settings['onboarding']['industries'] = self::get_allowed_industries(); $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[] = 'kkart_task_list_complete'; $options[] = 'kkart_task_list_do_this_later'; $options[] = 'kkart_task_list_hidden'; if ( ! self::should_show_tasks() && ! self::should_show_profiler() ) { return $options; } $options[] = 'kkart_connect_options'; $options[] = 'kkart_task_list_welcome_modal_dismissed'; $options[] = 'kkart_task_list_prompt_shown'; $options[] = 'kkart_task_list_tracked_completed_tasks'; $options[] = 'kkart_task_list_dismissed_tasks'; $options[] = 'kkart_allow_tracking'; $options[] = 'kkart_stripe_settings'; $options[] = 'kkart_ppec_paypal_settings'; $options[] = 'kkart_square_refresh_tokens'; $options[] = 'kkart_square_credit_card_settings'; $options[] = 'kkart_payfast_settings'; $options[] = 'kkart_kco_settings'; $options[] = 'kkart_klarna_payments_settings'; $options[] = 'kkart_cod_settings'; $options[] = 'kkart_bacs_settings'; $options[] = 'kkart_bacs_accounts'; $options[] = 'kkart_kkart_payments_settings'; $options[] = 'kkart_eway_settings'; return $options; } /** * Preload KKART 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( 'kkart_admin_onboarding_plugins_whitelist', array( 'facebook-for-kkart' => 'facebook-for-kkart/facebook-for-kkart.php', 'mailchimp-for-kkart' => 'mailchimp-for-kkart/mailchimp-kkart.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', 'kkart-services' => 'kkart-services/kkart-services.php', 'kkart-gateway-stripe' => 'kkart-gateway-stripe/kkart-gateway-stripe.php', 'kkart-gateway-paypal-express-checkout' => 'kkart-gateway-paypal-express-checkout/kkart-gateway-paypal-express-checkout.php', 'klarna-checkout-for-kkart' => 'klarna-checkout-for-kkart/klarna-checkout-for-kkart.php', 'klarna-payments-for-kkart' => 'klarna-payments-for-kkart/klarna-payments-for-kkart.php', 'kkart-square' => 'kkart-square/kkart-square.php', 'kkart-shipstation-integration' => 'kkart-shipstation-integration/kkart-shipstation.php', 'kkart-payfast-gateway' => 'kkart-payfast-gateway/gateway-payfast.php', 'kkart-payments' => 'kkart-payments/kkart-payments.php', 'kkart-gateway-eway' => 'kkart-gateway-eway/kkart-gateway-eway.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( 'kkart_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 `kkart-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( 'kkart_ppec_paypal_settings', array() ); $connected = isset( $settings_array['api_username'] ) && isset( $settings_array['api_password'] ) ? true : false; return kkart_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( 'kkart_gateway_ppec' ) ) { return false; } // @todo This is a bit hacky but works. Ideally, kkart-gateway-paypal-express-checkout would contain a filter for us. add_filter( 'wp_redirect', array( $this, 'overwrite_paypal_redirect' ), 10, 2 ); kkart_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=kkart-settings&tab=square'; if ( substr( $location, -strlen( $settings_page ) ) === $settings_page ) { return kkart_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( '\Kkart\Square\Plugin' ) ) { return false; } $square = \Kkart\Square\Plugin::instance(); // @todo This is a bit hacky but works. Ideally, kkart-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( 'KKART_ADMIN_MIGRATING_OPTIONS' ) && KKART_ADMIN_MIGRATING_OPTIONS ) { return; }; kkart_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( 'kkart_get_screen_ids' ) ) { return; } $screen = get_current_screen(); if ( ! $screen || ! in_array( $screen->id, kkart_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 ( 'kkart_onboard_tab' !== $help_tab['id'] ) { continue; } $screen->remove_help_tab( 'kkart_onboard_tab' ); } // Add the new help tab. $help_tab = array( 'title' => __( 'Setup wizard', 'kkart' ), 'id' => 'kkart_onboard_tab', ); $task_list_hidden = get_option( 'kkart_task_list_hidden', 'no' ); $help_tab['content'] = '<h2>' . __( 'Kkart Onboarding', 'kkart' ) . '</h2>'; $help_tab['content'] .= '<h3>' . __( 'Profile Setup Wizard', 'kkart' ) . '</h3>'; $help_tab['content'] .= '<p>' . __( 'If you need to access the setup wizard again, please click on the button below.', 'kkart' ) . '</p>' . '<p><a href="' . kkart_admin_url( '&path=/setup-wizard' ) . '" class="button button-primary">' . __( 'Setup wizard', 'kkart' ) . '</a></p>'; $help_tab['content'] .= '<h3>' . __( 'Task List', 'kkart' ) . '</h3>'; $help_tab['content'] .= '<p>' . __( 'If you need to enable or disable the task list, please click on the button below.', 'kkart' ) . '</p>' . ( 'yes' === $task_list_hidden ? '<p><a href="' . kkart_admin_url( '&reset_task_list=1' ) . '" class="button button-primary">' . __( 'Enable', 'kkart' ) . '</a></p>' : '<p><a href="' . kkart_admin_url( '&reset_task_list=0' ) . '" class="button button-primary">' . __( 'Disable', 'kkart' ) . '</a></p>' ); if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { $help_tab['content'] .= '<h3>' . __( 'Calypso / WordPress.com', 'kkart' ) . '</h3>'; if ( class_exists( 'Jetpack' ) ) { $help_tab['content'] .= '<p>' . __( 'Quickly access the Jetpack connection flow in Calypso.', 'kkart' ) . '</p>'; $help_tab['content'] .= '<p><a href="' . kkart_admin_url( '&test_kkart_jetpack_connect=1' ) . '" class="button button-primary">' . __( 'Connect', 'kkart' ) . '</a></p>'; } $help_tab['content'] .= '<p>' . __( 'Quickly access the Kkart.com connection flow in Calypso.', 'kkart' ) . '</p>'; $help_tab['content'] .= '<p><a href="' . kkart_admin_url( '&test_kkart_helper_connect=1' ) . '" class="button button-primary">' . __( 'Connect', 'kkart' ) . '</a></p>'; } $screen->add_help_tab( $help_tab ); } /** * Allows quick access to testing the calypso parts of onboarding. */ public static function calypso_tests() { $calypso_env = defined( 'KKART_CALYPSO_ENVIRONMENT' ) && in_array( KKART_CALYPSO_ENVIRONMENT, array( 'development', 'wpcalypso', 'horizon', 'stage' ), true ) ? KKART_CALYPSO_ENVIRONMENT : 'production'; if ( Loader::is_admin_page() && class_exists( 'Jetpack' ) && isset( $_GET['test_kkart_jetpack_connect'] ) && 1 === absint( $_GET['test_kkart_jetpack_connect'] ) ) { // phpcs:ignore CSRF ok. $redirect_url = esc_url_raw( add_query_arg( array( 'page' => 'kkart-admin', ), admin_url( 'admin.php' ) ) ); $connect_url = \Jetpack::init()->build_connect_url( true, $redirect_url, 'kkart-onboarding' ); $connect_url = add_query_arg( array( 'calypso_env' => $calypso_env ), $connect_url ); wp_redirect( $connect_url ); exit; } if ( Loader::is_admin_page() && isset( $_GET['test_kkart_helper_connect'] ) && 1 === absint( $_GET['test_kkart_helper_connect'] ) ) { // phpcs:ignore CSRF ok. include_once KKART_ABSPATH . 'includes/admin/helper/class-kkart-helper-api.php'; $redirect_uri = kkart_admin_url( '&task=connect&wccom-connected=1' ); $request = \KKART_Helper_API::post( 'oauth/request_token', array( 'body' => array( 'home_url' => home_url(), 'redirect_uri' => $redirect_uri, ), ) ); $code = wp_remote_retrieve_response_code( $request ); if ( 200 !== $code ) { wp_die( esc_html__( 'Kkart Helper was not able to connect to Kkart.com.', 'kkart' ) ); exit; } $secret = json_decode( wp_remote_retrieve_body( $request ) ); if ( empty( $secret ) ) { wp_die( esc_html__( 'Kkart Helper was not able to connect to Kkart.com.', 'kkart' ) ); exit; } $connect_url = add_query_arg( array( 'home_url' => rawurlencode( home_url() ), 'redirect_uri' => rawurlencode( $redirect_uri ), 'secret' => rawurlencode( $secret ), 'wccom-from' => 'onboarding', ), \KKART_Helper_API::url( 'oauth/authorize' ) ); $connect_url = add_query_arg( array( 'calypso_env' => $calypso_env ), $connect_url ); wp_redirect( $connect_url ); exit; } } /** * 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; kkart_admin_record_tracks_event( 'storeprofiler_toggled', array( 'previous' => $previous, 'new_value' => $new_value, ) ); $request = new \WP_REST_Request( 'POST', '/kkart-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( kkart_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( 'kkart_task_list_hidden', $task_list_hidden ); kkart_admin_record_tracks_event( 'tasklist_toggled', array( 'status' => 'yes' === $task_list_hidden ? 'disabled' : 'enabled', ) ); wp_safe_redirect( kkart_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://kkart.com/checkout' ) // phpcs:ignore sanitization ok. ) { return; } wp_safe_redirect( kkart_admin_url() ); } /** * When updating Kkart, 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/kkart/kkart/blob/1ca791f8f2325fe2ee0947b9c47e6a4627366374/includes/class-kkart-install.php#L341 */ public static function maybe_mark_complete() { // The install notice still exists so don't complete the profiler. if ( ! class_exists( 'KKART_Admin_Notices' ) || \KKART_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( 'kkart_task_list_hidden', 'yes' ); } }