Add advanced setting option (#36380)

* Modify feature flag

* Add tooltip to WC > Settings > Advanced > Features

* Add Settings option

* Add `optional_features` and `beta_features` option

* Add changelog

* Fix lint

* Fix lint

* Add `new_product_management` to legacy features

* Fix escaped tooltip

* Fix `Analytics pages` e2e tests

* Fix `Payment setup task` e2e tests

Co-authored-by: Fernando Marichal <contacto@fernandomarichal.com>
This commit is contained in:
Fernando Marichal 2023-01-13 17:04:02 -03:00 committed by GitHub
parent 8ad92c4c82
commit c5a27cbd55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 109 additions and 71 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Add advanced setting option

View File

@ -14,7 +14,7 @@
"minified-js": false, "minified-js": false,
"mobile-app-banner": true, "mobile-app-banner": true,
"navigation": true, "navigation": true,
"new-product-management-experience": false, "new-product-management-experience": true,
"onboarding": true, "onboarding": true,
"onboarding-tasks": true, "onboarding-tasks": true,
"product-variation-management": false, "product-variation-management": false,

View File

@ -14,7 +14,7 @@
"minified-js": true, "minified-js": true,
"mobile-app-banner": true, "mobile-app-banner": true,
"navigation": true, "navigation": true,
"new-product-management-experience": false, "new-product-management-experience": true,
"onboarding": true, "onboarding": true,
"onboarding-tasks": true, "onboarding-tasks": true,
"payment-gateway-suggestions": true, "payment-gateway-suggestions": true,

View File

@ -4375,6 +4375,11 @@ img.help_tip {
top: 20px; top: 20px;
} }
td.help-tooltip {
white-space: nowrap;
width: 8px;
}
.select2-container { .select2-container {
vertical-align: top; vertical-align: top;
margin-bottom: 3px; margin-bottom: 3px;

View File

@ -492,6 +492,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
?> ?>
<tr valign="top" class="<?php echo esc_attr( implode( ' ', $visibility_class ) ); ?>"> <tr valign="top" class="<?php echo esc_attr( implode( ' ', $visibility_class ) ); ?>">
<th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ); ?></th> <th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ); ?></th>
<td class="help-tooltip"><?php echo isset( $value['tooltip'] ) && '' !== $value['tooltip'] ? wc_help_tip( esc_html( $value['tooltip'] ) ) : ''; ?></td>
<td class="forminp forminp-checkbox"> <td class="forminp forminp-checkbox">
<fieldset> <fieldset>
<?php <?php

View File

@ -26,11 +26,12 @@ class Features {
* @var array * @var array
*/ */
protected static $optional_features = array( protected static $optional_features = array(
'multichannel-marketing' => array( 'default' => 'no' ), 'multichannel-marketing' => array( 'default' => 'no' ),
'navigation' => array( 'default' => 'no' ), 'navigation' => array( 'default' => 'no' ),
'settings' => array( 'default' => 'no' ), 'settings' => array( 'default' => 'no' ),
'analytics' => array( 'default' => 'yes' ), 'new-product-management-experience' => array( 'default' => 'no' ),
'remote-inbox-notifications' => array( 'default' => 'yes' ), 'analytics' => array( 'default' => 'yes' ),
'remote-inbox-notifications' => array( 'default' => 'yes' ),
); );
/** /**
@ -41,6 +42,7 @@ class Features {
protected static $beta_features = array( protected static $beta_features = array(
'multichannel-marketing', 'multichannel-marketing',
'navigation', 'navigation',
'new-product-management-experience',
'settings', 'settings',
); );

View File

@ -13,6 +13,11 @@ use \Automattic\WooCommerce\Internal\Admin\Loader;
*/ */
class NewProductManagementExperience { class NewProductManagementExperience {
/**
* Option name used to toggle this feature.
*/
const TOGGLE_OPTION_NAME = 'woocommerce_new_product_management_enabled';
/** /**
* Constructor * Constructor
*/ */

View File

@ -8,6 +8,7 @@ namespace Automattic\WooCommerce\Internal\Features;
use Automattic\Jetpack\Constants; use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Analytics; use Automattic\WooCommerce\Internal\Admin\Analytics;
use Automattic\WooCommerce\Admin\Features\Navigation\Init; use Automattic\WooCommerce\Admin\Features\Navigation\Init;
use Automattic\WooCommerce\Admin\Features\NewProductManagementExperience;
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods; use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
use Automattic\WooCommerce\Proxies\LegacyProxy; use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\ArrayUtil; use Automattic\WooCommerce\Utilities\ArrayUtil;
@ -89,25 +90,31 @@ class FeaturesController {
*/ */
public function __construct() { public function __construct() {
$features = array( $features = array(
'analytics' => array( 'analytics' => array(
'name' => __( 'Analytics', 'woocommerce' ), 'name' => __( 'Analytics', 'woocommerce' ),
'description' => __( 'Enables WooCommerce Analytics', 'woocommerce' ), 'description' => __( 'Enables WooCommerce Analytics', 'woocommerce' ),
'is_experimental' => false, 'is_experimental' => false,
'enabled_by_default' => true, 'enabled_by_default' => true,
), ),
'new_navigation' => array( 'new_navigation' => array(
'name' => __( 'Navigation', 'woocommerce' ), 'name' => __( 'Navigation', 'woocommerce' ),
'description' => __( 'Adds the new WooCommerce navigation experience to the dashboard', 'woocommerce' ), 'description' => __( 'Adds the new WooCommerce navigation experience to the dashboard', 'woocommerce' ),
'is_experimental' => false, 'is_experimental' => false,
), ),
'custom_order_tables' => array( 'new_product_management' => array(
'name' => __( 'New product editor', 'woocommerce' ),
'description' => __( 'Try the new product editor (Beta)', 'woocommerce' ),
'tooltip' => __( 'Enable to try the new, simplified product editor (currently in development and only available for simple products). No extension support yet.', 'woocommerce' ),
'is_experimental' => false,
),
'custom_order_tables' => array(
'name' => __( 'High-Performance order storage (COT)', 'woocommerce' ), 'name' => __( 'High-Performance order storage (COT)', 'woocommerce' ),
'description' => __( 'Enable the high performance order storage feature.', 'woocommerce' ), 'description' => __( 'Enable the high performance order storage feature.', 'woocommerce' ),
'is_experimental' => true, 'is_experimental' => true,
), ),
); );
$this->legacy_feature_ids = array( 'analytics', 'new_navigation' ); $this->legacy_feature_ids = array( 'analytics', 'new_navigation', 'new_product_management' );
$this->init_features( $features ); $this->init_features( $features );
@ -393,6 +400,8 @@ class FeaturesController {
return Analytics::TOGGLE_OPTION_NAME; return Analytics::TOGGLE_OPTION_NAME;
} elseif ( 'new_navigation' === $feature_id ) { } elseif ( 'new_navigation' === $feature_id ) {
return Init::TOGGLE_OPTION_NAME; return Init::TOGGLE_OPTION_NAME;
} elseif ( 'new_product_management' === $feature_id ) {
return NewProductManagementExperience::TOGGLE_OPTION_NAME;
} }
return "woocommerce_feature_${feature_id}_enabled"; return "woocommerce_feature_${feature_id}_enabled";
@ -450,7 +459,7 @@ class FeaturesController {
$matches = array(); $matches = array();
$success = preg_match( '/^woocommerce_feature_([a-zA-Z0-9_]+)_enabled$/', $option, $matches ); $success = preg_match( '/^woocommerce_feature_([a-zA-Z0-9_]+)_enabled$/', $option, $matches );
if ( ! $success && Analytics::TOGGLE_OPTION_NAME !== $option && Init::TOGGLE_OPTION_NAME !== $option ) { if ( ! $success && Analytics::TOGGLE_OPTION_NAME !== $option && Init::TOGGLE_OPTION_NAME !== $option && NewProductManagementExperience::TOGGLE_OPTION_NAME !== $option ) {
return; return;
} }
@ -462,6 +471,8 @@ class FeaturesController {
$feature_id = 'analytics'; $feature_id = 'analytics';
} elseif ( Init::TOGGLE_OPTION_NAME === $option ) { } elseif ( Init::TOGGLE_OPTION_NAME === $option ) {
$feature_id = 'new_navigation'; $feature_id = 'new_navigation';
} elseif ( NewProductManagementExperience::TOGGLE_OPTION_NAME === $option ) {
$feature_id = 'new_product_management';
} else { } else {
$feature_id = $matches[1]; $feature_id = $matches[1];
} }
@ -590,6 +601,7 @@ class FeaturesController {
$description = $feature['description']; $description = $feature['description'];
$disabled = false; $disabled = false;
$desc_tip = ''; $desc_tip = '';
$tooltip = isset( $feature['tooltip'] ) ? $feature['tooltip'] : '';
if ( ( 'analytics' === $feature_id || 'new_navigation' === $feature_id ) && $admin_features_disabled ) { if ( ( 'analytics' === $feature_id || 'new_navigation' === $feature_id ) && $admin_features_disabled ) {
$disabled = true; $disabled = true;
@ -675,6 +687,7 @@ class FeaturesController {
'id' => $this->feature_enable_option_name( $feature_id ), 'id' => $this->feature_enable_option_name( $feature_id ),
'disabled' => $disabled && ! $this->force_allow_enabling_features, 'disabled' => $disabled && ! $this->force_allow_enabling_features,
'desc_tip' => $desc_tip, 'desc_tip' => $desc_tip,
'tooltip' => $tooltip,
'default' => $this->feature_is_enabled_by_default( $feature_id ) ? 'yes' : 'no', 'default' => $this->feature_is_enabled_by_default( $feature_id ) ? 'yes' : 'no',
); );
} }

View File

@ -23,7 +23,9 @@ test.describe( 'Analytics pages', () => {
await page.goto( await page.goto(
`/wp-admin/admin.php?page=wc-admin&path=%2Fanalytics%2F${ urlTitle }` `/wp-admin/admin.php?page=wc-admin&path=%2Fanalytics%2F${ urlTitle }`
); );
const pageTitle = page.locator( 'h1' ); const pageTitle = page.locator(
'.woocommerce-layout__header-wrapper > h1'
);
await expect( pageTitle ).toContainText( aPages ); await expect( pageTitle ).toContainText( aPages );
await expect( await expect(
page.locator( '#woocommerce-layout__primary' ) page.locator( '#woocommerce-layout__primary' )

View File

@ -1,85 +1,91 @@
const { test, expect } = require('@playwright/test'); const { test, expect } = require( '@playwright/test' );
const wcApi = require('@woocommerce/woocommerce-rest-api').default; const wcApi = require( '@woocommerce/woocommerce-rest-api' ).default;
test.describe('Payment setup task', () => { test.describe( 'Payment setup task', () => {
test.use({ storageState: process.env.ADMINSTATE }); test.use( { storageState: process.env.ADMINSTATE } );
test.beforeEach(async ({ page }) => { test.beforeEach( async ( { page } ) => {
await page.goto('wp-admin/admin.php?page=wc-admin&path=/setup-wizard'); await page.goto(
await page.click('text=Skip setup store details'); 'wp-admin/admin.php?page=wc-admin&path=/setup-wizard'
await page.click('text=No thanks'); );
await page.waitForLoadState('networkidle'); await page.click( 'text=Skip setup store details' );
}); await page.click( 'text=No thanks' );
await page.waitForLoadState( 'networkidle' );
} );
test.afterAll(async ({ baseURL }) => { test.afterAll( async ( { baseURL } ) => {
const api = new wcApi({ const api = new wcApi( {
url: baseURL, url: baseURL,
consumerKey: process.env.CONSUMER_KEY, consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET, consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3', version: 'wc/v3',
}); } );
await api.put('payment_gateways/bacs', { await api.put( 'payment_gateways/bacs', {
enabled: false, enabled: false,
}); } );
await api.put('payment_gateways/cod', { await api.put( 'payment_gateways/cod', {
enabled: false, enabled: false,
}); } );
}); } );
test('Can visit the payment setup task from the homescreen if the setup wizard has been skipped', async ({ test( 'Can visit the payment setup task from the homescreen if the setup wizard has been skipped', async ( {
page, page,
}) => { } ) => {
await page.goto('wp-admin/admin.php?page=wc-admin'); await page.goto( 'wp-admin/admin.php?page=wc-admin' );
await page.click('text=Set up payments'); await page.click( 'text=Set up payments' );
await expect(page.locator('h1')).toHaveText('Set up payments'); await expect(
}); page.locator( '.woocommerce-layout__header-wrapper > h1' )
).toHaveText( 'Set up payments' );
} );
test('Saving valid bank account transfer details enables the payment method', async ({ test( 'Saving valid bank account transfer details enables the payment method', async ( {
page, page,
}) => { } ) => {
// load the bank transfer page // load the bank transfer page
await page.goto( await page.goto(
'wp-admin/admin.php?page=wc-admin&task=payments&id=bacs' 'wp-admin/admin.php?page=wc-admin&task=payments&id=bacs'
); );
// purposely no await -- close the help dialog if/when it appears // purposely no await -- close the help dialog if/when it appears
page.locator('.components-button.is-small.has-icon') page.locator( '.components-button.is-small.has-icon' )
.click() .click()
.catch(() => {}); .catch( () => {} );
// fill in bank transfer form // fill in bank transfer form
await page.fill('//input[@placeholder="Account name"]', 'Savings'); await page.fill( '//input[@placeholder="Account name"]', 'Savings' );
await page.fill('//input[@placeholder="Account number"]', '1234'); await page.fill( '//input[@placeholder="Account number"]', '1234' );
await page.fill('//input[@placeholder="Bank name"]', 'Test Bank'); await page.fill( '//input[@placeholder="Bank name"]', 'Test Bank' );
await page.fill('//input[@placeholder="Sort code"]', '12'); await page.fill( '//input[@placeholder="Sort code"]', '12' );
await page.fill('//input[@placeholder="IBAN"]', '12 3456 7890'); await page.fill( '//input[@placeholder="IBAN"]', '12 3456 7890' );
await page.fill('//input[@placeholder="BIC / Swift"]', 'ABBA'); await page.fill( '//input[@placeholder="BIC / Swift"]', 'ABBA' );
await page.click('text=Save'); await page.click( 'text=Save' );
// check that bank transfers were set up // check that bank transfers were set up
await expect( await expect(
page.locator('div.components-snackbar__content') page.locator( 'div.components-snackbar__content' )
).toContainText('Direct bank transfer details added successfully'); ).toContainText( 'Direct bank transfer details added successfully' );
await page.goto('wp-admin/admin.php?page=wc-settings&tab=checkout'); await page.goto( 'wp-admin/admin.php?page=wc-settings&tab=checkout' );
await expect( await expect(
page.locator('//tr[@data-gateway_id="bacs"]/td[@class="status"]/a') page.locator(
).toHaveClass('wc-payment-gateway-method-toggle-enabled'); '//tr[@data-gateway_id="bacs"]/td[@class="status"]/a'
}); )
).toHaveClass( 'wc-payment-gateway-method-toggle-enabled' );
} );
test('Enabling cash on delivery enables the payment method', async ({ test( 'Enabling cash on delivery enables the payment method', async ( {
page, page,
baseURL, baseURL,
}) => { } ) => {
// Payments page differs if located outside of a WCPay-supported country, so make sure we aren't. // Payments page differs if located outside of a WCPay-supported country, so make sure we aren't.
const api = new wcApi({ const api = new wcApi( {
url: baseURL, url: baseURL,
consumerKey: process.env.CONSUMER_KEY, consumerKey: process.env.CONSUMER_KEY,
consumerSecret: process.env.CONSUMER_SECRET, consumerSecret: process.env.CONSUMER_SECRET,
version: 'wc/v3', version: 'wc/v3',
}); } );
// ensure store address is US // ensure store address is US
await api.post('settings/general/batch', { await api.post( 'settings/general/batch', {
update: [ update: [
{ {
id: 'woocommerce_store_address', id: 'woocommerce_store_address',
@ -98,28 +104,28 @@ test.describe('Payment setup task', () => {
value: '94107', value: '94107',
}, },
], ],
}); } );
await page.goto('wp-admin/admin.php?page=wc-admin&task=payments'); await page.goto( 'wp-admin/admin.php?page=wc-admin&task=payments' );
// purposely no await -- close the help dialog if/when it appears // purposely no await -- close the help dialog if/when it appears
page.locator('.components-button.is-small.has-icon') page.locator( '.components-button.is-small.has-icon' )
.click() .click()
.catch(() => {}); .catch( () => {} );
await page.waitForLoadState('networkidle'); await page.waitForLoadState( 'networkidle' );
// purposely no await again // purposely no await again
page.click('button.toggle-button'); page.click( 'button.toggle-button' );
// enable COD payment option // enable COD payment option
await page.click( await page.click(
'div.woocommerce-task-payment-cod > div.woocommerce-task-payment__footer > button' 'div.woocommerce-task-payment-cod > div.woocommerce-task-payment__footer > button'
); );
await page.waitForLoadState('networkidle'); await page.waitForLoadState( 'networkidle' );
await page.goto('wp-admin/admin.php?page=wc-settings&tab=checkout'); await page.goto( 'wp-admin/admin.php?page=wc-settings&tab=checkout' );
await expect( await expect(
page.locator('//tr[@data-gateway_id="cod"]/td[@class="status"]/a') page.locator( '//tr[@data-gateway_id="cod"]/td[@class="status"]/a' )
).toHaveClass('wc-payment-gateway-method-toggle-enabled'); ).toHaveClass( 'wc-payment-gateway-method-toggle-enabled' );
}); } );
}); } );