diff --git a/.eslintrc.js b/.eslintrc.js index f4bae5a87e9..a78fc8174f5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,7 +20,7 @@ module.exports = { rules: { '@wordpress/dependency-group': 'off', 'woocommerce/dependency-group': 'error', - 'woocommerce/feature-flag': 'error', + 'woocommerce/feature-flag': 'off', 'valid-jsdoc': 'off', radix: 'error', yoda: [ 'error', 'never' ], diff --git a/.travis.yml b/.travis.yml index dc489be11eb..20b7931e23f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,21 +47,21 @@ jobs: php: 7.1 env: - WP_VERSION=latest - - WOOCOMMERCE_BLOCKS_PHASE=experimental + - WOOCOMMERCE_BLOCKS_PHASE=3 script: - phpunit - name: PHP 5.6/unit-tests/Latest WP php: 5.6 env: - WP_VERSION=latest - - WOOCOMMERCE_BLOCKS_PHASE=experimental + - WOOCOMMERCE_BLOCKS_PHASE=3 script: - phpunit - name: PHP Linting Check php: 7.3 env: - WP_TRAVISCI=phpcs - - WOOCOMMERCE_BLOCKS_PHASE=experimental + - WOOCOMMERCE_BLOCKS_PHASE=3 script: - npm run lint:php - name: Javascript Tests @@ -69,13 +69,13 @@ jobs: - npm install - npm run test env: - - WOOCOMMERCE_BLOCKS_PHASE=experimental + - WOOCOMMERCE_BLOCKS_PHASE=3 - name: Javascript/CSS Lint check script: - npm install - npm run lint:ci env: - - WOOCOMMERCE_BLOCKS_PHASE=experimental + - WOOCOMMERCE_BLOCKS_PHASE=3 - name: E2E Tests script: - npm ci @@ -84,12 +84,12 @@ jobs: - npm run build:e2e-test - npm run test:e2e env: - - WOOCOMMERCE_BLOCKS_PHASE=experimental + - WOOCOMMERCE_BLOCKS_PHASE=3 - stage: deploy if: (NOT type IN (pull_request)) AND (branch = master) name: Deploy Storybook env: - - WOOCOMMERCE_BLOCKS_PHASE=experimental + - WOOCOMMERCE_BLOCKS_PHASE=3 install: - npm ci script: diff --git a/assets/js/blocks/cart-checkout/cart/index.js b/assets/js/blocks/cart-checkout/cart/index.js index b1e15917143..24067cc041f 100644 --- a/assets/js/blocks/cart-checkout/cart/index.js +++ b/assets/js/blocks/cart-checkout/cart/index.js @@ -3,10 +3,9 @@ */ import { __ } from '@wordpress/i18n'; import { InnerBlocks } from '@wordpress/block-editor'; -import { registerBlockType } from '@wordpress/blocks'; import { Icon, cart } from '@woocommerce/icons'; import classnames from 'classnames'; - +import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; /** * Internal dependencies */ @@ -51,4 +50,4 @@ const settings = { }, }; -registerBlockType( 'woocommerce/cart', settings ); +registerFeaturePluginBlockType( 'woocommerce/cart', settings ); diff --git a/assets/js/blocks/cart-checkout/checkout/index.js b/assets/js/blocks/cart-checkout/checkout/index.js index bca9a5c552d..376efcae063 100644 --- a/assets/js/blocks/cart-checkout/checkout/index.js +++ b/assets/js/blocks/cart-checkout/checkout/index.js @@ -2,9 +2,9 @@ * External dependencies */ import { __ } from '@wordpress/i18n'; -import { registerBlockType } from '@wordpress/blocks'; import { Icon, card } from '@woocommerce/icons'; import classnames from 'classnames'; +import { registerFeaturePluginBlockType } from '@woocommerce/block-settings'; /** * Internal dependencies @@ -49,4 +49,4 @@ const settings = { }, }; -registerBlockType( 'woocommerce/checkout', settings ); +registerFeaturePluginBlockType( 'woocommerce/checkout', settings ); diff --git a/assets/js/blocks/single-product/index.js b/assets/js/blocks/single-product/index.js index b94fa51f224..586bfc37b32 100644 --- a/assets/js/blocks/single-product/index.js +++ b/assets/js/blocks/single-product/index.js @@ -2,7 +2,7 @@ * External dependencies */ import { __ } from '@wordpress/i18n'; -import { registerBlockType } from '@wordpress/blocks'; +import { registerExperimentalBlockType } from '@woocommerce/block-settings'; /** * Internal dependencies @@ -40,4 +40,4 @@ const settings = { save, }; -registerBlockType( BLOCK_NAME, settings ); +registerExperimentalBlockType( BLOCK_NAME, settings ); diff --git a/assets/js/settings/blocks/constants.js b/assets/js/settings/blocks/constants.js index 5972d9b6c53..fe59bb24cea 100644 --- a/assets/js/settings/blocks/constants.js +++ b/assets/js/settings/blocks/constants.js @@ -49,6 +49,10 @@ export const IS_SHIPPING_COST_HIDDEN = getSetting( 'isShippingCostHidden', false ); +export const WOOCOMMERCE_BLOCKS_PHASE = getSetting( + 'woocommerceBlocksPhase', + 1 +); export const WC_BLOCKS_ASSET_URL = getSetting( 'wcBlocksAssetUrl', '' ); export const SHIPPING_COUNTRIES = getSetting( 'shippingCountries', {} ); export const ALLOWED_COUNTRIES = getSetting( 'allowedCountries', {} ); diff --git a/assets/js/settings/blocks/feature-flags.js b/assets/js/settings/blocks/feature-flags.js new file mode 100644 index 00000000000..f12746347d4 --- /dev/null +++ b/assets/js/settings/blocks/feature-flags.js @@ -0,0 +1,57 @@ +/** + * External dependencies + */ +import { registerBlockType } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { WOOCOMMERCE_BLOCKS_PHASE } from './constants'; + +/** + * Registers a new experimental block provided a unique name and an object defining its + * behavior. Once registered, the block is made available as an option to any + * editor interface where blocks are implemented. + * + * @param {string} name Block name. + * @param {Object} settings Block settings. + * + * @return {?Object} The block, if it has been successfully registered; + * otherwise `undefined`. + */ +export const registerExperimentalBlockType = ( name, settings ) => { + if ( WOOCOMMERCE_BLOCKS_PHASE > 2 ) { + return registerBlockType( name, settings ); + } +}; + +/** + * Registers a new feature plugin block provided a unique name and an object + * defining its behavior. Once registered, the block is made available as an + * option to any editor interface where blocks are implemented. + * + * @param {string} name Block name. + * @param {Object} settings Block settings. + * + * @return {?Object} The block, if it has been successfully registered; + * otherwise `undefined`. + */ +export const registerFeaturePluginBlockType = ( name, settings ) => { + if ( WOOCOMMERCE_BLOCKS_PHASE > 1 ) { + return registerBlockType( name, settings ); + } +}; + +/** + * Checks if we're executing the code in an experimental build mode. + * + * @return {boolean} True if this is an experimental build, false otherwise. + */ +export const isExperimentalBuild = () => WOOCOMMERCE_BLOCKS_PHASE > 2; + +/** + * Checks if we're executing the code in an feature plugin or experimental build mode. + * + * @return {boolean} True if this is an experimental or feature plugin build, false otherwise. + */ +export const isFeaturePluginBuild = () => WOOCOMMERCE_BLOCKS_PHASE > 1; diff --git a/assets/js/settings/blocks/index.js b/assets/js/settings/blocks/index.js index e91d7ced15f..d7a79ffce99 100644 --- a/assets/js/settings/blocks/index.js +++ b/assets/js/settings/blocks/index.js @@ -2,3 +2,4 @@ * Internal dependencies */ export * from './constants'; +export * from './feature-flags'; diff --git a/bin/eslint-plugin-woocommerce/rules/feature-flag.js b/bin/eslint-plugin-woocommerce/rules/feature-flag.js index 86cea81a471..d539e773149 100644 --- a/bin/eslint-plugin-woocommerce/rules/feature-flag.js +++ b/bin/eslint-plugin-woocommerce/rules/feature-flag.js @@ -27,14 +27,15 @@ function findParent( sourceNode, predicate ) { * @example * ```js * // good - * if ( process.env.WOOCOMMERCE_BLOCKS_PHASE === 'experimental' ) { + * if ( process.env.WOOCOMMERCE_BLOCKS_PHASE > 1 ) { * * // bad - * if ( WOOCOMMERCE_BLOCKS_PHASE === 'experimental' ) { + * if ( WOOCOMMERCE_BLOCKS_PHASE > 1 ) { * ``` * * @param {Object} node The WOOCOMMERCE_BLOCKS_PHASE identifier node. * @param {Object} context The eslint context object. + * @todo: update this rule to match the new flags. */ function testIsAccessedViaProcessEnv( node, context ) { let parent = node.parent; diff --git a/bin/webpack-helpers.js b/bin/webpack-helpers.js index 7d313e37003..5504c65d874 100644 --- a/bin/webpack-helpers.js +++ b/bin/webpack-helpers.js @@ -9,7 +9,6 @@ const DependencyExtractionWebpackPlugin = require( '@wordpress/dependency-extrac const WebpackRTLPlugin = require( 'webpack-rtl-plugin' ); const chalk = require( 'chalk' ); const { omit } = require( 'lodash' ); -const { DefinePlugin } = require( 'webpack' ); const NODE_ENV = process.env.NODE_ENV || 'development'; function findModuleMatch( module, match ) { @@ -149,16 +148,17 @@ const stableMainEntry = { 'active-filters': './assets/js/blocks/active-filters/index.js', 'block-error-boundary': './assets/js/base/components/block-error-boundary/style.scss', - 'single-product': './assets/js/blocks/single-product/index.js', + cart: './assets/js/blocks/cart-checkout/cart/index.js', + checkout: './assets/js/blocks/cart-checkout/checkout/index.js', }; const experimentalMainEntry = { - cart: './assets/js/blocks/cart-checkout/cart/index.js', - checkout: './assets/js/blocks/cart-checkout/checkout/index.js', + 'single-product': './assets/js/blocks/single-product/index.js', }; const mainEntry = - process.env.WOOCOMMERCE_BLOCKS_PHASE === 'stable' + // env variables are strings, so we compare against a string, so we need to parse it. + parseInt( process.env.WOOCOMMERCE_BLOCKS_PHASE, 10 ) < 3 ? stableMainEntry : { ...stableMainEntry, ...experimentalMainEntry }; @@ -168,16 +168,17 @@ const stableFrontEndEntry = { 'price-filter': './assets/js/blocks/price-filter/frontend.js', 'attribute-filter': './assets/js/blocks/attribute-filter/frontend.js', 'active-filters': './assets/js/blocks/active-filters/frontend.js', - 'single-product': './assets/js/blocks/single-product/frontend.js', + cart: './assets/js/blocks/cart-checkout/cart/frontend.js', + checkout: './assets/js/blocks/cart-checkout/checkout/frontend.js', }; const experimentalFrontEndEntry = { - cart: './assets/js/blocks/cart-checkout/cart/frontend.js', - checkout: './assets/js/blocks/cart-checkout/checkout/frontend.js', + 'single-product': './assets/js/blocks/single-product/frontend.js', }; const frontEndEntry = - process.env.WOOCOMMERCE_BLOCKS_PHASE === 'stable' + // env variables are strings, so we compare against a string, so we need to parse it. + parseInt( process.env.WOOCOMMERCE_BLOCKS_PHASE, 10 ) < 3 ? stableFrontEndEntry : { ...stableFrontEndEntry, ...experimentalFrontEndEntry }; @@ -358,13 +359,6 @@ const getMainConfig = ( options = {} ) => { requestToExternal, requestToHandle, } ), - new DefinePlugin( { - // Inject the `WOOCOMMERCE_BLOCKS_PHASE` global, used for feature flagging. - 'process.env.WOOCOMMERCE_BLOCKS_PHASE': JSON.stringify( - // eslint-disable-next-line woocommerce/feature-flag - process.env.WOOCOMMERCE_BLOCKS_PHASE || 'experimental' - ), - } ), ], resolve, }; @@ -460,13 +454,6 @@ const getFrontConfig = ( options = {} ) => { requestToExternal, requestToHandle, } ), - new DefinePlugin( { - // Inject the `WOOCOMMERCE_BLOCKS_PHASE` global, used for feature flagging. - 'process.env.WOOCOMMERCE_BLOCKS_PHASE': JSON.stringify( - // eslint-disable-next-line woocommerce/feature-flag - process.env.WOOCOMMERCE_BLOCKS_PHASE || 'experimental' - ), - } ), ], resolve, }; @@ -599,13 +586,6 @@ const getPaymentMethodsExtensionConfig = ( options = {} ) => { requestToExternal, requestToHandle, } ), - new DefinePlugin( { - // Inject the `WOOCOMMERCE_BLOCKS_PHASE` global, used for feature flagging. - 'process.env.WOOCOMMERCE_BLOCKS_PHASE': JSON.stringify( - // eslint-disable-next-line woocommerce/feature-flag - process.env.WOOCOMMERCE_BLOCKS_PHASE || 'experimental' - ), - } ), ], resolve, }; diff --git a/package-lock.json b/package-lock.json index 88248195ea9..5b99a548554 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38389,4 +38389,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index f034c6f5962..cf561fcbfab 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "build:map": "cross-env BABEL_ENV=default NODE_ENV=production FORCE_MAP=true webpack", "changelog": "node ./bin/changelog", "changelog:zenhub": "node ./bin/changelog --changelogSrcType='ZENHUB_RELEASE'", - "deploy": "cross-env WOOCOMMERCE_BLOCKS_PHASE=stable composer install --no-dev && npm run build --loglevel error && sh ./bin/github-deploy.sh", + "deploy": "cross-env WOOCOMMERCE_BLOCKS_PHASE=2 composer install --no-dev && npm run build --loglevel error && sh ./bin/github-deploy.sh", "dev": "cross-env BABEL_ENV=default webpack", "explore": "source-map-explorer", "lint": "npm run lint:php && npm run lint:css && npm run lint:js", @@ -208,4 +208,4 @@ "license.txt", "woocommerce-gutenberg-products-block.php" ] -} +} \ No newline at end of file diff --git a/src/Assets.php b/src/Assets.php index 3495d2639b4..50c1854dca6 100644 --- a/src/Assets.php +++ b/src/Assets.php @@ -81,12 +81,15 @@ public static function register_assets() { self::register_script( 'wc-price-filter', plugins_url( self::get_block_asset_build_path( 'price-filter' ), __DIR__ ), $block_dependencies ); self::register_script( 'wc-attribute-filter', plugins_url( self::get_block_asset_build_path( 'attribute-filter' ), __DIR__ ), $block_dependencies ); self::register_script( 'wc-active-filters', plugins_url( self::get_block_asset_build_path( 'active-filters' ), __DIR__ ), $block_dependencies ); - self::register_script( 'wc-checkout-block', plugins_url( self::get_block_asset_build_path( 'checkout' ), __DIR__ ), $block_dependencies ); - self::register_script( 'wc-cart-block', plugins_url( self::get_block_asset_build_path( 'cart' ), __DIR__ ), $block_dependencies ); - if ( 'experimental' === WOOCOMMERCE_BLOCKS_PHASE ) { + if ( Package::is_experimental_build() ) { self::register_script( 'wc-single-product-block', plugins_url( self::get_block_asset_build_path( 'single-product' ), __DIR__ ), $block_dependencies ); } + + if ( Package::is_feature_plugin_build() ) { + self::register_script( 'wc-checkout-block', plugins_url( self::get_block_asset_build_path( 'checkout' ), __DIR__ ), $block_dependencies ); + self::register_script( 'wc-cart-block', plugins_url( self::get_block_asset_build_path( 'cart' ), __DIR__ ), $block_dependencies ); + } } /** @@ -178,6 +181,7 @@ public static function get_wc_block_data( $settings ) { 'checkoutAllowsGuest' => 'yes' === get_option( 'woocommerce_enable_guest_checkout' ), 'checkoutAllowsSignup' => 'yes' === get_option( 'woocommerce_enable_signup_and_login_from_checkout' ), 'baseLocation' => wc_get_base_location(), + 'woocommerceBlocksPhase' => WOOCOMMERCE_BLOCKS_PHASE, /* * translators: If your word count is based on single characters (e.g. East Asian characters), diff --git a/src/Domain/Bootstrap.php b/src/Domain/Bootstrap.php index fad87fda39c..583a3b2a164 100644 --- a/src/Domain/Bootstrap.php +++ b/src/Domain/Bootstrap.php @@ -64,6 +64,7 @@ protected function init() { if ( ! $this->has_core_dependencies() ) { return; } + $this->define_feature_flag(); $this->register_dependencies(); $this->register_payment_methods(); @@ -72,7 +73,6 @@ protected function init() { // Load assets in admin and on the frontend. if ( ! $is_rest ) { $this->add_build_notice(); - $this->define_feature_flag(); $this->container->get( AssetDataRegistry::class ); $this->container->get( Installer::class ); BlockAssets::init(); @@ -130,17 +130,17 @@ function() { * Define the global feature flag. */ protected function define_feature_flag() { - $allowed_flags = [ 'experimental', 'stable' ]; - $flag = getenv( 'WOOCOMMERCE_BLOCKS_PHASE' ); - if ( ! in_array( $flag, $allowed_flags, true ) ) { - if ( file_exists( __DIR__ . '/../../blocks.ini' ) ) { - $woo_options = parse_ini_file( __DIR__ . '/../../blocks.ini' ); - $flag = is_array( $woo_options ) && 'experimental' === $woo_options['woocommerce_blocks_phase'] ? 'experimental' : 'stable'; - } else { - $flag = 'stable'; - } + $default_flag = defined( 'WC_BLOCKS_IS_FEATURE_PLUGIN' ) ? '2' : '1'; + $allowed_flags = [ '1', '2', '3' ]; + + if ( file_exists( __DIR__ . '/../../blocks.ini' ) ) { + $woo_options = parse_ini_file( __DIR__ . '/../../blocks.ini' ); + $flag = is_array( $woo_options ) && in_array( $woo_options['woocommerce_blocks_phase'], $allowed_flags, true ) ? $woo_options['woocommerce_blocks_phase'] : $default_flag; + } else { + $flag = $default_flag; } - define( 'WOOCOMMERCE_BLOCKS_PHASE', $flag ); + + define( 'WOOCOMMERCE_BLOCKS_PHASE', intval( $flag ) ); } /** diff --git a/src/Domain/Package.php b/src/Domain/Package.php index 28c496558be..92298448353 100644 --- a/src/Domain/Package.php +++ b/src/Domain/Package.php @@ -72,4 +72,22 @@ public function get_url( $relative_url = '' ) { // Append index.php so WP does not return the parent directory. return plugin_dir_url( $this->path . '/index.php' ) . $relative_url; } + + /** + * Checks if we're executing the code in an experimental build mode. + * + * @return boolean + */ + public static function is_experimental_build() { + return WOOCOMMERCE_BLOCKS_PHASE > 2; + } + + /** + * Checks if we're executing the code in an feature plugin or experimental build mode. + * + * @return boolean + */ + public static function is_feature_plugin_build() { + return WOOCOMMERCE_BLOCKS_PHASE > 1; + } } diff --git a/src/Library.php b/src/Library.php index 3af9d292b23..eaeecc9bc95 100644 --- a/src/Library.php +++ b/src/Library.php @@ -9,6 +9,8 @@ defined( 'ABSPATH' ) || exit; +use Automattic\WooCommerce\Blocks\Package; + /** * Library class. */ @@ -72,10 +74,13 @@ public static function register_blocks() { $blocks[] = 'PriceFilter'; $blocks[] = 'AttributeFilter'; $blocks[] = 'ActiveFilters'; - $blocks[] = 'Checkout'; - $blocks[] = 'Cart'; + + if ( Package::is_feature_plugin_build() ) { + $blocks[] = 'Checkout'; + $blocks[] = 'Cart'; + } } - if ( 'experimental' === WOOCOMMERCE_BLOCKS_PHASE ) { + if ( Package::is_experimental_build() ) { $blocks[] = 'SingleProduct'; } foreach ( $blocks as $class ) { diff --git a/src/Package.php b/src/Package.php index 4a672d10d91..79fa558aed2 100644 --- a/src/Package.php +++ b/src/Package.php @@ -65,6 +65,23 @@ public static function get_path() { return self::get_package()->get_path(); } + /** + * Checks if we're executing the code in an experimental build mode. + * + * @return boolean + */ + public static function is_experimental_build() { + return self::get_package()->is_experimental_build(); + } + + /** + * Checks if we're executing the code in an feature plugin or experimental build mode. + * + * @return boolean + */ + public static function is_feature_plugin_build() { + return self::get_package()->is_feature_plugin_build(); + } /** * Loads the dependency injection container for woocommerce blocks. * diff --git a/webpack.config.js b/webpack.config.js index caf41b286fa..3aacc859863 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,7 +3,6 @@ */ const path = require( 'path' ); const { kebabCase } = require( 'lodash' ); -const { DefinePlugin } = require( 'webpack' ); const { CleanWebpackPlugin } = require( 'clean-webpack-plugin' ); const CreateFileWebpack = require( 'create-file-webpack' ); const ProgressBarPlugin = require( 'progress-bar-webpack-plugin' ); @@ -89,22 +88,13 @@ const CoreConfig = { ' :msg (:elapsed seconds)', } ), new DependencyExtractionWebpackPlugin( { injectPolyfill: true } ), - new DefinePlugin( { - // Inject the `WOOCOMMERCE_BLOCKS_PHASE` global, used for feature flagging. - 'process.env.WOOCOMMERCE_BLOCKS_PHASE': JSON.stringify( - // eslint-disable-next-line woocommerce/feature-flag - process.env.WOOCOMMERCE_BLOCKS_PHASE || 'experimental' - ), - } ), new CreateFileWebpack( { path: './', // file name fileName: 'blocks.ini', // content of the file - content: `woocommerce_blocks_phase = ${ - // eslint-disable-next-line woocommerce/feature-flag - process.env.WOOCOMMERCE_BLOCKS_PHASE || 'experimental' - }`, + content: `woocommerce_blocks_phase = ${ process.env + .WOOCOMMERCE_BLOCKS_PHASE || 3 }`, } ), ], }; diff --git a/woocommerce-gutenberg-products-block.php b/woocommerce-gutenberg-products-block.php index f4694179070..f388c6597fe 100644 --- a/woocommerce-gutenberg-products-block.php +++ b/woocommerce-gutenberg-products-block.php @@ -20,6 +20,9 @@ $minimum_wp_version = '5.2'; +if ( ! defined( 'WC_BLOCKS_IS_FEATURE_PLUGIN' ) ) { + define( 'WC_BLOCKS_IS_FEATURE_PLUGIN', true ); +} /** * Whether notices must be displayed in the current page (plugins and WooCommerce pages). *