diff --git a/plugins/woocommerce-admin/src/Features/Features.php b/plugins/woocommerce-admin/src/Features/Features.php new file mode 100644 index 00000000000..1f32889c875 --- /dev/null +++ b/plugins/woocommerce-admin/src/Features/Features.php @@ -0,0 +1,304 @@ + __( 'Features', 'woocommerce-admin' ), + 'type' => 'title', + 'desc' => __( 'Start using new features that are being progressively rolled out to improve the store management experience.', 'woocommerce-admin' ), + 'id' => 'features_options', + ), + ), + $features, + array( + array( + 'type' => 'sectionend', + 'id' => 'features_options', + ), + ) + ); + } + + /** + * Conditionally loads the beta features tracking modal. + * + * @param array $settings Settings. + * @return array + */ + public static function maybe_load_beta_features_modal( $settings ) { + $tracking_enabled = get_option( 'woocommerce_allow_tracking', 'no' ); + + if ( 'yes' === $tracking_enabled ) { + return $settings; + } + + $rtl = is_rtl() ? '.rtl' : ''; + + wp_enqueue_style( + 'wc-admin-beta-features-tracking-modal', + Loader::get_url( "beta-features-tracking-modal/style{$rtl}", 'css' ), + array( 'wp-components' ), + Loader::get_file_version( 'css' ) + ); + + wp_enqueue_script( + 'wc-admin-beta-features-tracking-modal', + Loader::get_url( 'wp-admin-scripts/beta-features-tracking-modal', 'js' ), + array( 'wp-i18n', 'wp-element', WC_ADMIN_APP ), + Loader::get_file_version( 'js' ), + true + ); + + return $settings; + } + + /** + * Loads the required scripts on the correct pages. + */ + public static function load_scripts() { + if ( ! Loader::is_admin_or_embed_page() ) { + return; + } + + if ( ! Loader::user_can_analytics() ) { + return; + } + + $features = self::get_features(); + $enabled_features = array(); + foreach ( $features as $key ) { + $enabled_features[ $key ] = self::is_enabled( $key ); + } + wp_add_inline_script( WC_ADMIN_APP, 'window.wcAdminFeatures = ' . wp_json_encode( $enabled_features ), 'before' ); + } + + + /** + * Adds body classes to the main wp-admin wrapper, allowing us to better target elements in specific scenarios. + * + * @param string $admin_body_class Body class to add. + */ + public static function add_admin_body_classes( $admin_body_class = '' ) { + if ( ! Loader::is_admin_or_embed_page() ) { + return $admin_body_class; + } + + $classes = explode( ' ', trim( $admin_body_class ) ); + + $features = self::get_features(); + foreach ( $features as $feature_key ) { + $classes[] = sanitize_html_class( 'woocommerce-feature-enabled-' . $feature_key ); + } + + $admin_body_class = implode( ' ', array_unique( $classes ) ); + return " $admin_body_class "; + } +} diff --git a/plugins/woocommerce-admin/src/Features/Navigation/Init.php b/plugins/woocommerce-admin/src/Features/Navigation/Init.php index f1358e70706..743f8276618 100644 --- a/plugins/woocommerce-admin/src/Features/Navigation/Init.php +++ b/plugins/woocommerce-admin/src/Features/Navigation/Init.php @@ -17,6 +17,11 @@ use Automattic\WooCommerce\Admin\Features\Navigation\CoreMenu; * Contains logic for the Navigation */ class Init { + /** + * Option name used to toggle this feature. + */ + const TOGGLE_OPTION_NAME = 'woocommerce_navigation_enabled'; + /** * Hook into WooCommerce. */ @@ -24,7 +29,7 @@ class Init { add_filter( 'woocommerce_settings_features', array( $this, 'add_feature_toggle' ) ); add_filter( 'woocommerce_admin_preload_options', array( $this, 'preload_options' ) ); add_filter( 'woocommerce_admin_features', array( $this, 'maybe_remove_nav_feature' ), 0 ); - add_action( 'update_option_woocommerce_navigation_enabled', array( $this, 'reload_page_on_toggle' ), 10, 2 ); + add_action( 'update_option_' . self::TOGGLE_OPTION_NAME, array( $this, 'reload_page_on_toggle' ), 10, 2 ); add_action( 'admin_enqueue_scripts', array( $this, 'maybe_enqueue_opt_out_scripts' ) ); if ( Loader::is_feature_enabled( 'navigation' ) ) { @@ -63,7 +68,7 @@ class Init { $features[] = array( 'title' => __( 'Navigation', 'woocommerce-admin' ), 'desc' => $description . $update_text, - 'id' => 'woocommerce_navigation_enabled', + 'id' => self::TOGGLE_OPTION_NAME, 'type' => 'checkbox', 'class' => $needs_update ? 'disabled' : '', ); @@ -106,7 +111,7 @@ class Init { */ public function maybe_remove_nav_feature( $features ) { $has_feature_enabled = in_array( 'navigation', $features, true ); - $has_option_disabled = 'yes' !== get_option( 'woocommerce_navigation_enabled', 'no' ); + $has_option_disabled = 'yes' !== get_option( self::TOGGLE_OPTION_NAME, 'no' ); $is_not_compatible = ! self::is_nav_compatible(); if ( ( $has_feature_enabled && $has_option_disabled ) || $is_not_compatible ) { @@ -122,7 +127,7 @@ class Init { * @return array */ public function preload_options( $options ) { - $options[] = 'woocommerce_navigation_enabled'; + $options[] = self::TOGGLE_OPTION_NAME; return $options; } diff --git a/plugins/woocommerce-admin/src/Loader.php b/plugins/woocommerce-admin/src/Loader.php index 13ab3812f6a..360d6242941 100644 --- a/plugins/woocommerce-admin/src/Loader.php +++ b/plugins/woocommerce-admin/src/Loader.php @@ -7,9 +7,9 @@ namespace Automattic\WooCommerce\Admin; use \_WP_Dependency; -use Automattic\WooCommerce\Admin\Features\Onboarding; use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore; use Automattic\WooCommerce\Admin\API\Plugins; +use Automattic\WooCommerce\Admin\Features\Features; use Automattic\WooCommerce\Admin\Features\Navigation\Screen; use WC_Marketplace_Suggestions; @@ -58,12 +58,8 @@ class Loader { * Hooks added here should be removed in `wc_admin_initialize` via the feature plugin. */ public function __construct() { + Features::get_instance(); add_action( 'init', array( __CLASS__, 'define_tables' ) ); - // Load feature before WooCommerce update hooks. - add_action( 'init', array( __CLASS__, 'load_features' ), 4 ); - add_filter( 'woocommerce_get_sections_advanced', array( __CLASS__, 'add_features_section' ) ); - add_filter( 'woocommerce_get_settings_advanced', array( __CLASS__, 'add_features_settings' ), 10, 2 ); - add_filter( 'woocommerce_get_settings_advanced', array( __CLASS__, 'maybe_load_beta_features_modal' ), 10, 2 ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'register_scripts' ) ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'inject_wc_settings_dependencies' ), 14 ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'load_scripts' ), 15 ); @@ -140,9 +136,11 @@ class Loader { * Gets a build configured array of enabled WooCommerce Admin features/sections. * * @return array Enabled Woocommerce Admin features/sections. + * + * @deprecated since 1.9.0, use Features::get_features() */ public static function get_features() { - return apply_filters( 'woocommerce_admin_features', array() ); + return Features::get_features(); } /** @@ -176,10 +174,11 @@ class Loader { * * @param string $feature Feature slug. * @return bool Returns true if the feature is enabled. + * + * @deprecated since 1.9.0, use Features::exists( $feature ) */ public static function is_feature_enabled( $feature ) { - $features = self::get_features(); - return in_array( $feature, $features, true ); + return Features::exists( $feature ); } /** @@ -190,7 +189,7 @@ class Loader { */ public static function should_use_minified_js_file( $script_debug ) { // minified files are only shipped in non-core versions of wc-admin, return false if minified files are not available. - if ( ! self::is_feature_enabled( 'minified-js' ) ) { + if ( ! Features::exists( 'minified-js' ) ) { return false; } @@ -240,119 +239,6 @@ class Loader { return ( 'css' === $ext ) ? WC_ADMIN_DIST_CSS_FOLDER : WC_ADMIN_DIST_JS_FOLDER; } - /** - * Class loader for enabled WooCommerce Admin features/sections. - */ - public static function load_features() { - $features = self::get_features(); - foreach ( $features as $feature ) { - $feature = str_replace( '-', '', ucwords( strtolower( $feature ), '-' ) ); - $feature_class = 'Automattic\\WooCommerce\\Admin\\Features\\' . $feature; - - // Handle features contained in subdirectory. - if ( ! class_exists( $feature_class ) && class_exists( $feature_class . '\\Init' ) ) { - $feature_class = $feature_class . '\\Init'; - } - - if ( class_exists( $feature_class ) ) { - new $feature_class(); - } - } - } - - /** - * Adds the Features section to the advanced tab of WooCommerce Settings - * - * @param array $sections Sections. - * @return array - */ - public static function add_features_section( $sections ) { - $features = apply_filters( - 'woocommerce_settings_features', - array() - ); - - if ( empty( $features ) ) { - return $sections; - } - - $sections['features'] = __( 'Features', 'woocommerce-admin' ); - return $sections; - } - - /** - * Conditionally loads the beta features tracking modal. - * - * @param array $settings Settings. - * @return array - */ - public static function maybe_load_beta_features_modal( $settings ) { - $tracking_enabled = get_option( 'woocommerce_allow_tracking', 'no' ); - - if ( 'yes' === $tracking_enabled ) { - return $settings; - } - - $rtl = is_rtl() ? '.rtl' : ''; - - wp_enqueue_style( - 'wc-admin-beta-features-tracking-modal', - self::get_url( "beta-features-tracking-modal/style{$rtl}", 'css' ), - array( 'wp-components' ), - self::get_file_version( 'css' ) - ); - - wp_enqueue_script( - 'wc-admin-beta-features-tracking-modal', - self::get_url( 'wp-admin-scripts/beta-features-tracking-modal', 'js' ), - array( 'wp-i18n', 'wp-element', WC_ADMIN_APP ), - self::get_file_version( 'js' ), - true - ); - - return $settings; - } - - /** - * Adds the Features settings. - * - * @param array $settings Settings. - * @param string $current_section Current section slug. - * @return array - */ - public static function add_features_settings( $settings, $current_section ) { - if ( 'features' !== $current_section ) { - return $settings; - } - - $features = apply_filters( - 'woocommerce_settings_features', - array() - ); - - if ( empty( $features ) ) { - return $settings; - } - - return array_merge( - array( - array( - 'title' => __( 'Features', 'woocommerce-admin' ), - 'type' => 'title', - 'desc' => __( 'Test new features to improve the store management experience. These features might be included in future versions of WooCommerce. Requires usage tracking.', 'woocommerce-admin' ), - 'id' => 'features_options', - ), - ), - $features, - array( - array( - 'type' => 'sectionend', - 'id' => 'features_options', - ), - ) - ); - } - /** * Connects existing WooCommerce pages. * @@ -826,13 +712,6 @@ class Loader { // Grab translation strings from Webpack-generated chunks. add_filter( 'load_script_translation_file', array( __CLASS__, 'load_script_translation_file' ), 10, 3 ); - $features = self::get_features(); - $enabled_features = array(); - foreach ( $features as $key ) { - $enabled_features[ $key ] = self::is_feature_enabled( $key ); - } - wp_add_inline_script( WC_ADMIN_APP, 'window.wcAdminFeatures = ' . wp_json_encode( $enabled_features ), 'before' ); - wp_enqueue_script( WC_ADMIN_APP ); wp_enqueue_style( WC_ADMIN_APP ); wp_enqueue_style( 'wc-material-icons' ); @@ -957,7 +836,7 @@ class Loader { * TODO: See usage in `admin.php`. This needs refactored and implemented properly in core. */ public static function is_embed_page() { - return wc_admin_is_connected_page() || ( ! self::is_admin_page() && Screen::is_woocommerce_page() ); + return wc_admin_is_connected_page() || ( ! self::is_admin_page() && class_exists( 'Automattic\WooCommerce\Admin\Features\Navigation\Screen' ) && Screen::is_woocommerce_page() ); } /** @@ -1042,11 +921,6 @@ class Loader { $classes[] = 'woocommerce-admin-is-loading'; } - $features = self::get_features(); - foreach ( $features as $feature_key ) { - $classes[] = sanitize_html_class( 'woocommerce-feature-enabled-' . $feature_key ); - } - $admin_body_class = implode( ' ', array_unique( $classes ) ); return " $admin_body_class "; }