diff --git a/plugins/woocommerce-admin/TESTING-INSTRUCTIONS.md b/plugins/woocommerce-admin/TESTING-INSTRUCTIONS.md
index 6efd687a7a8..54f8ce7afa8 100644
--- a/plugins/woocommerce-admin/TESTING-INSTRUCTIONS.md
+++ b/plugins/woocommerce-admin/TESTING-INSTRUCTIONS.md
@@ -1,27 +1,26 @@
# Testing instructions
-## Unreleased
-
## 2.8.0
### Store Profiler and Product task - include Subscriptions #7734
-##### Feature: turned off
+##### Non US stores
1. Deactivate and delete `WooCommerce Payments` if you have it installed.
-2. Go to the 3rd step of the store profiler (`Product Types`).
-3. Verify `Subscriptions` is shown as a paid extension (with a price chip).
-4. Check `Subscriptions` and continue with the OBW.
-5. Go back to the `Home` screen. Check that the task item `Add Subscriptions to my store` is visible in the setup task list.
-6. Press `Add my products` in the setup task list.
-7. Select `Start with a template`. Verify that the option `Subscription product` is not visible in the popup.
+2. Go to step one of the store profiler and select `France` (or any country other than the US) as the store `Country / Region`.
+3. Go to step three of the store profiler (`Product Types`).
+4. Verify `Subscriptions` is shown as a paid extension (with a price chip).
+5. Check `Subscriptions` and continue with the OBW.
+6. Go back to the `Home` screen by pressing `Skip setup store details` in step one of the store profiler. Check that the task item `Add Subscriptions to my store` is visible in the setup task list.
+7. Press `Add my products` in the setup task list.
+8. Select `Start with a template`. Verify that the option `Subscription product` is not visible in the popup.
-##### Feature: turned on
+##### US stores
-1. Install and activate this plugin to turn on the subscriptions inclusion -> https://gist.github.com/octaedro/455eb4c85887608c253249bad533ccb3
-2. Deactivate and delete `WooCommerce Payments` if you have it installed.
-3. Go to the 3rd step of the store profiler (`Product Types`).
-4. Verify `Subscriptions` is shown as free (without a price chip). Also, verify that the text
+9. Deactivate and delete `WooCommerce Payments`.
+10. Go to step one of the store profiler and select `US` as the store `Country / Region`.
+11. Go to step three of the store profiler (`Product Types`).
+12. Verify `Subscriptions` is shown as free (without a price chip). Also, verify that the text
```
The following extensions will be added to your site for free: WooCommerce Payments. An account is required to use this feature
@@ -31,20 +30,23 @@ is visible at the bottom when `WooCommerce Payments` is not installed.
![screenshot-one wordpress test-2021 09 30-14_12_58](https://user-images.githubusercontent.com/1314156/135506696-b7812f7e-437f-4d89-956a-b73248f70f6b.png)
-5. Press `Continue` and verify that the `WooCommerce Payments` plugin is installed and activated and it's not shown in the `Free features` list
+
+13. Check `Subscriptions` and press `Continue` and verify that the `WooCommerce Payments` plugin is installed and activated and it's not shown in the `Free features` list
![screenshot-one wordpress test-2021 09 30-14_32_20](https://user-images.githubusercontent.com/1314156/135506727-d8888f2b-3424-4cf5-a4bf-b67a14a198b6.png)
-6. Go back to the `Home` screen. Check that the task item `Add Subscriptions to my store` is not visible in the setup task list.
+14. Verify that the `WooCommerce Payments` plugin is being shown in the `Free features` list when the store country is other than the `US`.
+
+15. Go back to the `Home` screen by pressing `Skip setup store details` in step one of the store profiler. Check that the task item `Add Subscriptions to my store` is not visible in the setup task list. It should be visible if the store is from any country other than the `US`.
![screenshot-one wordpress test-2021 09 30-14_39_28](https://user-images.githubusercontent.com/1314156/135506770-91571f8f-2e2e-43a7-b092-b9e5fdf56df8.png)
-7. Press `Add my products` in the setup task list.
-8. Select `Start with a template`. Verify that the option `Subscription product` is visible in the popup
+16. Press `Add my products` in the setup task list.
+17. Select `Start with a template`. Verify that the option `Subscription product` is visible in the popup
![screenshot-one wordpress test-2021 09 30-14_35_22](https://user-images.githubusercontent.com/1314156/135506748-0b7bdce5-b006-47f9-9289-03ed26e4950c.png)
-9. Select `Subscription product` and press `Ok`. You should have been redirected to `post-new.php?post_type=product&subscription_pointers=true`
+18. Select `Subscription product` and press `Ok`. You should have been redirected to `post-new.php?post_type=product&subscription_pointers=true`.
## 2.7.1
diff --git a/plugins/woocommerce-admin/client/dashboard/components/cart-modal.js b/plugins/woocommerce-admin/client/dashboard/components/cart-modal.js
index 847b8fe6a65..d0c52f0bf26 100644
--- a/plugins/woocommerce-admin/client/dashboard/components/cart-modal.js
+++ b/plugins/woocommerce-admin/client/dashboard/components/cart-modal.js
@@ -80,11 +80,8 @@ class CartModal extends Component {
}
renderProducts() {
- const { productIds } = this.props;
- const { productTypes = {}, themes = [] } = getSetting(
- 'onboarding',
- {}
- );
+ const { productIds, productTypes } = this.props;
+ const { themes = [] } = getSetting( 'onboarding', {} );
const listItems = [];
productIds.forEach( ( productId ) => {
@@ -169,15 +166,19 @@ class CartModal extends Component {
export default compose(
withSelect( ( select ) => {
const { getInstalledPlugins } = select( PLUGINS_STORE_NAME );
- const { getProfileItems } = select( ONBOARDING_STORE_NAME );
+ const { getProductTypes, getProfileItems } = select(
+ ONBOARDING_STORE_NAME
+ );
const profileItems = getProfileItems();
const installedPlugins = getInstalledPlugins();
+ const productTypes = getProductTypes();
const productIds = getProductIdsForCart(
+ productTypes,
profileItems,
false,
installedPlugins
);
- return { profileItems, productIds };
+ return { profileItems, productIds, productTypes };
} )
)( CartModal );
diff --git a/plugins/woocommerce-admin/client/dashboard/utils.js b/plugins/woocommerce-admin/client/dashboard/utils.js
index 784696f0560..b4c5da56901 100644
--- a/plugins/woocommerce-admin/client/dashboard/utils.js
+++ b/plugins/woocommerce-admin/client/dashboard/utils.js
@@ -36,12 +36,14 @@ export function getCurrencyRegion( countryState ) {
/**
* Gets the product IDs for items based on the product types and theme selected in the onboarding profiler.
*
+ * @param {Object} productTypes Product Types.
* @param {Object} profileItems Onboarding profile.
* @param {boolean} includeInstalledItems Include installed items in returned product IDs.
* @param {Array} installedPlugins Installed plugins.
* @return {Array} Product Ids.
*/
export function getProductIdsForCart(
+ productTypes,
profileItems,
includeInstalledItems = false,
installedPlugins
@@ -49,7 +51,8 @@ export function getProductIdsForCart(
const productList = getProductList(
profileItems,
includeInstalledItems,
- installedPlugins
+ installedPlugins,
+ productTypes
);
const productIds = productList.map(
( product ) => product.id || product.product
@@ -60,11 +63,13 @@ export function getProductIdsForCart(
/**
* Gets the labeled/categorized product names and types for items based on the product types and theme selected in the onboarding profiler.
*
+ * @param {Object} productTypes Product Types.
* @param {Object} profileItems Onboarding profile.
* @param {Array} installedPlugins Installed plugins.
* @return {Array} Objects with labeled/categorized product names and types.
*/
export function getCategorizedOnboardingProducts(
+ productTypes,
profileItems,
installedPlugins
) {
@@ -72,12 +77,14 @@ export function getCategorizedOnboardingProducts(
productList.products = getProductList(
profileItems,
true,
- installedPlugins
+ installedPlugins,
+ productTypes
);
productList.remainingProducts = getProductList(
profileItems,
false,
- installedPlugins
+ installedPlugins,
+ productTypes
);
const uniqueItemsList = [
@@ -106,37 +113,37 @@ export function getCategorizedOnboardingProducts(
* @param {Object} profileItems Onboarding profile.
* @param {boolean} includeInstalledItems Include installed items in returned product list.
* @param {Array} installedPlugins Installed plugins.
+ * @param {Object} productTypes Product Types.
* @return {Array} Products.
*/
export function getProductList(
profileItems,
includeInstalledItems = false,
- installedPlugins
+ installedPlugins,
+ productTypes
) {
- const onboarding = getSetting( 'onboarding', {} );
const productList = [];
- // The population of onboarding.productTypes only happens if the task list should be shown
- // so bail early if it isn't present.
- if ( ! onboarding.productTypes ) {
+ if ( ! productTypes ) {
return productList;
}
- const productTypes = profileItems.product_types || [];
+ const profileItemsProductTypes = profileItems.product_types || [];
- productTypes.forEach( ( productType ) => {
+ profileItemsProductTypes.forEach( ( productType ) => {
if (
- onboarding.productTypes[ productType ] &&
- onboarding.productTypes[ productType ].product &&
+ productTypes[ productType ] &&
+ productTypes[ productType ].product &&
( includeInstalledItems ||
! installedPlugins.includes(
- onboarding.productTypes[ productType ].slug
+ productTypes[ productType ].slug
) )
) {
- productList.push( onboarding.productTypes[ productType ] );
+ productList.push( productTypes[ productType ] );
}
} );
+ const onboarding = getSetting( 'onboarding', {} );
const theme = onboarding.themes.find(
( themeData ) => themeData.slug === profileItems.theme
);
diff --git a/plugins/woocommerce-admin/client/profile-wizard/steps/business-details/flows/selective-bundle/selective-extensions-bundle/index.js b/plugins/woocommerce-admin/client/profile-wizard/steps/business-details/flows/selective-bundle/selective-extensions-bundle/index.js
index dd4060b09dd..8c9cbf2940d 100644
--- a/plugins/woocommerce-admin/client/profile-wizard/steps/business-details/flows/selective-bundle/selective-extensions-bundle/index.js
+++ b/plugins/woocommerce-admin/client/profile-wizard/steps/business-details/flows/selective-bundle/selective-extensions-bundle/index.js
@@ -8,7 +8,11 @@ import { Link } from '@woocommerce/components';
import { __, _n, sprintf } from '@wordpress/i18n';
import { Icon, chevronDown, chevronUp } from '@wordpress/icons';
import interpolateComponents from 'interpolate-components';
-import { pluginNames, ONBOARDING_STORE_NAME } from '@woocommerce/data';
+import {
+ pluginNames,
+ ONBOARDING_STORE_NAME,
+ SETTINGS_STORE_NAME,
+} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useSelect } from '@wordpress/data';
@@ -19,6 +23,7 @@ import { AppIllustration } from '../app-illustration';
import './style.scss';
import sanitizeHTML from '~/lib/sanitize-html';
import { setAllPropsToValue } from '~/lib/collections';
+import { getCountryCode } from '../../../../../../dashboard/utils';
const ALLOWED_PLUGIN_LISTS = [ 'basics' ];
@@ -178,28 +183,35 @@ export const SelectiveExtensionsBundle = ( {
const [ showExtensions, setShowExtensions ] = useState( false );
const [ values, setValues ] = useState( baseValues );
- const { freeExtensions, isResolving, profileItems } = useSelect(
- ( select ) => {
- const {
- getFreeExtensions,
- getProfileItems,
- hasFinishedResolution,
- } = select( ONBOARDING_STORE_NAME );
+ const {
+ countryCode,
+ freeExtensions,
+ isResolving,
+ profileItems,
+ } = useSelect( ( select ) => {
+ const {
+ getFreeExtensions,
+ getProfileItems,
+ hasFinishedResolution,
+ } = select( ONBOARDING_STORE_NAME );
+ const { getSettings } = select( SETTINGS_STORE_NAME );
+ const { general: settings = {} } = getSettings( 'general' );
- return {
- freeExtensions: getFreeExtensions(),
- isResolving: ! hasFinishedResolution( 'getFreeExtensions' ),
- profileItems: getProfileItems(),
- };
- }
- );
+ return {
+ countryCode: getCountryCode( settings.woocommerce_default_country ),
+ freeExtensions: getFreeExtensions(),
+ isResolving: ! hasFinishedResolution( 'getFreeExtensions' ),
+ profileItems: getProfileItems(),
+ };
+ } );
const installableExtensions = useMemo( () => {
const { product_types: productTypes } = profileItems;
return freeExtensions.filter( ( list ) => {
if (
window.wcAdminFeatures &&
- window.wcAdminFeatures.subscriptions
+ window.wcAdminFeatures.subscriptions &&
+ countryCode === 'US'
) {
if ( productTypes.includes( 'subscriptions' ) ) {
list.plugins = list.plugins.filter(
diff --git a/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/index.js b/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/index.js
index ff2fb5a0c49..bf49ec58fdd 100644
--- a/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/index.js
+++ b/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/index.js
@@ -11,35 +11,34 @@ import {
CardFooter,
CheckboxControl,
FormToggle,
+ Spinner,
} from '@wordpress/components';
-import { includes, filter, get } from 'lodash';
-import { getSetting } from '@woocommerce/wc-admin-settings';
+import { includes, filter } from 'lodash';
import { recordEvent } from '@woocommerce/tracks';
import { withDispatch, withSelect } from '@wordpress/data';
-import { ONBOARDING_STORE_NAME, PLUGINS_STORE_NAME } from '@woocommerce/data';
+import {
+ ONBOARDING_STORE_NAME,
+ PLUGINS_STORE_NAME,
+ SETTINGS_STORE_NAME,
+} from '@woocommerce/data';
import { Text } from '@woocommerce/experimental';
/**
* Internal dependencies
*/
import { createNoticesFromResponse } from '~/lib/notices';
+import { getCountryCode } from '../../../dashboard/utils';
import ProductTypeLabel from './label';
import './style.scss';
export class ProductTypes extends Component {
- constructor( props ) {
+ constructor() {
super();
- const profileItems = get( props, 'profileItems', {} );
-
- const { productTypes = {} } = getSetting( 'onboarding', {} );
- const defaultProductTypes = Object.keys( productTypes ).filter(
- ( key ) => !! productTypes[ key ].default
- );
this.state = {
error: null,
isMonthlyPricing: true,
- selected: profileItems.product_types || defaultProductTypes,
+ selected: [],
isWCPayInstalled: null,
};
@@ -48,9 +47,11 @@ export class ProductTypes extends Component {
}
componentDidMount() {
- const { installedPlugins } = this.props;
+ const { installedPlugins, invalidateResolution } = this.props;
const { isWCPayInstalled } = this.state;
+ invalidateResolution( 'getProductTypes', [] );
+
if ( isWCPayInstalled === null && installedPlugins ) {
this.setState( {
isWCPayInstalled: installedPlugins.includes(
@@ -60,6 +61,19 @@ export class ProductTypes extends Component {
}
}
+ componentDidUpdate( prevProps ) {
+ const { profileItems, productTypes } = this.props;
+
+ if ( prevProps.productTypes !== productTypes ) {
+ const defaultProductTypes = Object.keys( productTypes ).filter(
+ ( key ) => !! productTypes[ key ].default
+ );
+ this.setState( {
+ selected: profileItems.product_types || defaultProductTypes,
+ } );
+ }
+ }
+
validateField() {
const error = this.state.selected.length
? null
@@ -80,6 +94,7 @@ export class ProductTypes extends Component {
}
const {
+ countryCode,
createNotice,
goToNextStep,
installAndActivatePlugins,
@@ -95,6 +110,7 @@ export class ProductTypes extends Component {
if (
window.wcAdminFeatures &&
window.wcAdminFeatures.subscriptions &&
+ countryCode === 'US' &&
! installedPlugins.includes( 'woocommerce-payments' ) &&
selected.includes( 'subscriptions' )
) {
@@ -145,14 +161,27 @@ export class ProductTypes extends Component {
}
render() {
- const { productTypes = {} } = getSetting( 'onboarding', {} );
+ const { productTypes = [] } = this.props;
const {
error,
isMonthlyPricing,
isWCPayInstalled,
selected,
} = this.state;
- const { isInstallingActivating, isProfileItemsRequesting } = this.props;
+ const {
+ countryCode,
+ isInstallingActivating,
+ isProductTypesRequesting,
+ isProfileItemsRequesting,
+ } = this.props;
+
+ if ( isProductTypesRequesting ) {
+ return (
+
+
+
+ );
+ }
return (
@@ -256,6 +285,7 @@ export class ProductTypes extends Component {
{ window.wcAdminFeatures &&
window.wcAdminFeatures.subscriptions &&
+ countryCode === 'US' &&
! isWCPayInstalled &&
selected.includes( 'subscriptions' ) && (
{
const {
getProfileItems,
+ getProductTypes,
getOnboardingError,
+ hasFinishedResolution,
isOnboardingRequesting,
} = select( ONBOARDING_STORE_NAME );
+ const { getSettings } = select( SETTINGS_STORE_NAME );
const { getInstalledPlugins, isPluginsRequesting } = select(
PLUGINS_STORE_NAME
);
+ const { general: settings = {} } = getSettings( 'general' );
return {
isError: Boolean( getOnboardingError( 'updateProfileItems' ) ),
@@ -297,16 +331,23 @@ export default compose(
isInstallingActivating:
isPluginsRequesting( 'installPlugins' ) ||
isPluginsRequesting( 'activatePlugins' ),
+ countryCode: getCountryCode( settings.woocommerce_default_country ),
+ productTypes: getProductTypes(),
+ isProductTypesRequesting: ! hasFinishedResolution(
+ 'getProductTypes'
+ ),
};
} ),
withDispatch( ( dispatch ) => {
const { updateProfileItems } = dispatch( ONBOARDING_STORE_NAME );
const { createNotice } = dispatch( 'core/notices' );
const { installAndActivatePlugins } = dispatch( PLUGINS_STORE_NAME );
+ const { invalidateResolution } = dispatch( ONBOARDING_STORE_NAME );
return {
createNotice,
installAndActivatePlugins,
+ invalidateResolution,
updateProfileItems,
};
} )
diff --git a/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/style.scss b/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/style.scss
index 0ed73b729ab..0a482909b3e 100644
--- a/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/style.scss
+++ b/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/style.scss
@@ -60,10 +60,13 @@
margin-left: $gap;
}
}
+ &__spinner {
+ text-align: center;
+ }
}
}
-@media screen and (max-width: 438px) {
+@media screen and ( max-width: 438px ) {
.woocommerce-profile-wizard__body {
.woocommerce-profile-wizard__product-types {
.woocommerce-product-wizard__product-types-label {
@@ -73,7 +76,7 @@
}
}
-@media screen and (max-width: 375px) {
+@media screen and ( max-width: 375px ) {
.woocommerce-profile-wizard__body {
.woocommerce-profile-wizard__product-types {
.woocommerce-pill {
diff --git a/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/test/index.js b/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/test/index.js
index 7bee3a2e6c0..628fd24051b 100644
--- a/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/test/index.js
+++ b/plugins/woocommerce-admin/client/profile-wizard/steps/product-types/test/index.js
@@ -2,46 +2,44 @@
* External dependencies
*/
import { render, screen, waitFor } from '@testing-library/react';
-import { setSetting } from '@woocommerce/wc-admin-settings';
import userEvent from '@testing-library/user-event';
-import { createElement } from '@wordpress/element';
/**
* Internal dependencies
*/
import { ProductTypes } from '../';
-describe( 'ProductTypes', () => {
- beforeEach( () => {
- setSetting( 'onboarding', {
- productTypes: {
- paidProduct: {
- description: 'Paid product type',
- label: 'Paid product',
- more_url: 'https://woocommerce.com/paid-product',
- product: 100,
- slug: 'paid-product',
- yearly_price: 120,
- },
- freeProduct: {
- label: 'Free product',
- },
- },
- } );
- } );
+const testProps = {
+ countryCode: 'US',
+ invalidateResolution: jest.fn(),
+ isProductTypesRequesting: false,
+ productTypes: {
+ paidProduct: {
+ description: 'Paid product type',
+ label: 'Paid product',
+ more_url: 'https://woocommerce.com/paid-product',
+ product: 100,
+ slug: 'paid-product',
+ yearly_price: 120,
+ },
+ freeProduct: {
+ label: 'Free product',
+ },
+ },
+};
+describe( 'ProductTypes', () => {
afterEach( () => {
- setSetting( 'onboarding', {} );
window.wcAdminFeatures.subscriptions = false;
} );
test( 'should render product types', () => {
- const { container } = render( );
+ const { container } = render( );
expect( container ).toMatchSnapshot();
} );
test( 'should show annual prices on toggle', () => {
- const { container } = render( );
+ const { container } = render( );
const toggle = screen.getByLabelText( 'Display monthly prices', {
selector: 'input',
@@ -62,6 +60,7 @@ describe( 'ProductTypes', () => {
createNotice={ mockCreateNotice }
goToNextStep={ mockGoToNextStep }
updateProfileItems={ mockUpdateProfileItems }
+ { ...testProps }
/>
);
@@ -88,16 +87,16 @@ describe( 'ProductTypes', () => {
} );
} );
test( 'should show a warning message at the bottom of the step', () => {
- setSetting( 'onboarding', {
- productTypes: {
- subscriptions: {
- label: 'Subscriptions',
- },
+ const productTypes = {
+ subscriptions: {
+ label: 'Subscriptions',
},
- } );
+ };
window.wcAdminFeatures.subscriptions = true;
- render( );
+ render(
+
+ );
const subscription = screen.getByText( 'Subscriptions', {
selector: 'label',
@@ -110,4 +109,32 @@ describe( 'ProductTypes', () => {
)
).toBeInTheDocument();
} );
+ test( 'should show the warning message only for US stores', () => {
+ const productTypes = {
+ subscriptions: {
+ label: 'Subscriptions',
+ },
+ };
+ const countryCode = 'FR';
+ window.wcAdminFeatures.subscriptions = true;
+
+ render(
+
+ );
+
+ const subscription = screen.getByText( 'Subscriptions', {
+ selector: 'label',
+ } );
+ userEvent.click( subscription );
+
+ expect(
+ screen.queryByText(
+ 'The following extensions will be added to your site for free: WooCommerce Payments. An account is required to use this feature.'
+ )
+ ).not.toBeInTheDocument();
+ } );
} );
diff --git a/plugins/woocommerce-admin/client/profile-wizard/steps/store-details/index.js b/plugins/woocommerce-admin/client/profile-wizard/steps/store-details/index.js
index 224bae6d058..f259ef2939f 100644
--- a/plugins/woocommerce-admin/client/profile-wizard/steps/store-details/index.js
+++ b/plugins/woocommerce-admin/client/profile-wizard/steps/store-details/index.js
@@ -230,7 +230,13 @@ class StoreDetails extends Component {
isStoreDetailsPopoverVisible,
isSkipSetupPopoverVisible,
} = this.state;
- const { skipProfiler, isLoading, isBusy, initialValues } = this.props;
+ const {
+ skipProfiler,
+ isLoading,
+ isBusy,
+ initialValues,
+ invalidateResolutionForStoreSelector,
+ } = this.props;
/* eslint-disable @wordpress/i18n-no-collapsible-whitespace */
const skipSetupText = __(
@@ -390,6 +396,9 @@ class StoreDetails extends Component {
isLink
className="woocommerce-profile-wizard__footer-link"
onClick={ () => {
+ invalidateResolutionForStoreSelector(
+ 'getTaskLists'
+ );
this.setState( {
showUsageModal: true,
skipping: true,
@@ -498,13 +507,17 @@ export default compose(
} ),
withDispatch( ( dispatch ) => {
const { createNotice } = dispatch( 'core/notices' );
- const { updateProfileItems } = dispatch( ONBOARDING_STORE_NAME );
+ const {
+ invalidateResolutionForStoreSelector,
+ updateProfileItems,
+ } = dispatch( ONBOARDING_STORE_NAME );
const { updateAndPersistSettingsForGroup } = dispatch(
SETTINGS_STORE_NAME
);
return {
createNotice,
+ invalidateResolutionForStoreSelector,
updateProfileItems,
updateAndPersistSettingsForGroup,
};
diff --git a/plugins/woocommerce-admin/client/tasks/fills/products/product-template-modal.js b/plugins/woocommerce-admin/client/tasks/fills/products/product-template-modal.js
index cd47ae9dc29..29b08e08ef4 100644
--- a/plugins/woocommerce-admin/client/tasks/fills/products/product-template-modal.js
+++ b/plugins/woocommerce-admin/client/tasks/fills/products/product-template-modal.js
@@ -5,11 +5,12 @@ import { __ } from '@wordpress/i18n';
import { Button, Modal, RadioControl } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
-import { addFilter, applyFilters } from '@wordpress/hooks';
+import { applyFilters } from '@wordpress/hooks';
import {
ITEMS_STORE_NAME,
ONBOARDING_STORE_NAME,
PLUGINS_STORE_NAME,
+ SETTINGS_STORE_NAME,
} from '@woocommerce/data';
import { getAdminLink } from '@woocommerce/wc-admin-settings';
import { recordEvent } from '@woocommerce/tracks';
@@ -19,11 +20,12 @@ import { recordEvent } from '@woocommerce/tracks';
*/
import './product-template-modal.scss';
import { createNoticesFromResponse } from '../../../lib/notices';
+import { getCountryCode } from '../../../dashboard/utils';
export const ONBOARDING_PRODUCT_TEMPLATES_FILTER =
'woocommerce_admin_onboarding_product_templates';
-const PRODUCT_TEMPLATES = [
+const getProductTemplates = () => [
{
key: 'physical',
title: __( 'Physical product', 'woocommerce-admin' ),
@@ -62,10 +64,13 @@ export default function ProductTemplateModal( { onClose } ) {
const [ selectedTemplate, setSelectedTemplate ] = useState( null );
const [ isRedirecting, setIsRedirecting ] = useState( false );
const { createProductFromTemplate } = useDispatch( ITEMS_STORE_NAME );
- const { profileItems } = useSelect( ( select ) => {
+ const { countryCode, profileItems } = useSelect( ( select ) => {
const { getProfileItems } = select( ONBOARDING_STORE_NAME );
+ const { getSettings } = select( SETTINGS_STORE_NAME );
+ const { general: settings = {} } = getSettings( 'general' );
return {
+ countryCode: getCountryCode( settings.woocommerce_default_country ),
profileItems: getProfileItems(),
};
} );
@@ -116,25 +121,21 @@ export default function ProductTemplateModal( { onClose } ) {
}
};
- if (
+ const removeSubscriptions =
( window.wcAdminFeatures && ! window.wcAdminFeatures.subscriptions ) ||
+ countryCode !== 'US' ||
! profileItems.product_types.includes( 'subscriptions' ) ||
- ! installedPlugins.includes( 'woocommerce-payments' )
- ) {
- addFilter(
- ONBOARDING_PRODUCT_TEMPLATES_FILTER,
- 'woocommerce-admin',
- ( productTemplates ) => {
- return productTemplates.filter(
- ( template ) => template.key !== 'subscription'
- );
- }
- );
- }
+ ! installedPlugins.includes( 'woocommerce-payments' );
+
+ const productTemplates = removeSubscriptions
+ ? getProductTemplates().filter(
+ ( template ) => template.key !== 'subscription'
+ )
+ : getProductTemplates();
const templates = applyFilters(
ONBOARDING_PRODUCT_TEMPLATES_FILTER,
- PRODUCT_TEMPLATES
+ productTemplates
);
return (
diff --git a/plugins/woocommerce-admin/client/tasks/fills/products/products.js b/plugins/woocommerce-admin/client/tasks/fills/products/products.js
index 926bed475bd..157471ada19 100644
--- a/plugins/woocommerce-admin/client/tasks/fills/products/products.js
+++ b/plugins/woocommerce-admin/client/tasks/fills/products/products.js
@@ -12,7 +12,11 @@ import {
archive,
download,
} from '@wordpress/icons';
-import { ONBOARDING_STORE_NAME, PLUGINS_STORE_NAME } from '@woocommerce/data';
+import {
+ ONBOARDING_STORE_NAME,
+ PLUGINS_STORE_NAME,
+ SETTINGS_STORE_NAME,
+} from '@woocommerce/data';
import { useSelect } from '@wordpress/data';
import { List, Pill } from '@woocommerce/components';
import { getAdminLink } from '@woocommerce/wc-admin-settings';
@@ -24,8 +28,9 @@ import { WooOnboardingTask } from '@woocommerce/onboarding';
* Internal dependencies
*/
import ProductTemplateModal from './product-template-modal';
+import { getCountryCode } from '../../../dashboard/utils';
-const subTasks = [
+const getSubTasks = () => [
{
key: 'addProductTemplate',
title: (
@@ -94,10 +99,13 @@ const subTasks = [
const Products = () => {
const [ selectTemplate, setSelectTemplate ] = useState( null );
- const { profileItems } = useSelect( ( select ) => {
+ const { countryCode, profileItems } = useSelect( ( select ) => {
const { getProfileItems } = select( ONBOARDING_STORE_NAME );
+ const { getSettings } = select( SETTINGS_STORE_NAME );
+ const { general: settings = {} } = getSettings( 'general' );
return {
+ countryCode: getCountryCode( settings.woocommerce_default_country ),
profileItems: getProfileItems(),
};
} );
@@ -109,9 +117,12 @@ const Products = () => {
};
} );
+ const subTasks = getSubTasks();
+
if (
window.wcAdminFeatures &&
window.wcAdminFeatures.subscriptions &&
+ countryCode === 'US' &&
profileItems.product_types.includes( 'subscriptions' ) &&
installedPlugins.includes( 'woocommerce-payments' )
) {
diff --git a/plugins/woocommerce-admin/client/tasks/fills/purchase.js b/plugins/woocommerce-admin/client/tasks/fills/purchase.js
index 5f1e436273f..31a894c9158 100644
--- a/plugins/woocommerce-admin/client/tasks/fills/purchase.js
+++ b/plugins/woocommerce-admin/client/tasks/fills/purchase.js
@@ -18,15 +18,20 @@ import { getCategorizedOnboardingProducts } from '../../dashboard/utils';
const PurchaseTaskItem = () => {
const [ cartModalOpen, setCartModalOpen ] = useState( false );
- const { installedPlugins, profileItems } = useSelect( ( select ) => {
- const { getProfileItems } = select( ONBOARDING_STORE_NAME );
- const { getInstalledPlugins } = select( PLUGINS_STORE_NAME );
+ const { installedPlugins, productTypes, profileItems } = useSelect(
+ ( select ) => {
+ const { getProductTypes, getProfileItems } = select(
+ ONBOARDING_STORE_NAME
+ );
+ const { getInstalledPlugins } = select( PLUGINS_STORE_NAME );
- return {
- installedPlugins: getInstalledPlugins(),
- profileItems: getProfileItems(),
- };
- } );
+ return {
+ installedPlugins: getInstalledPlugins(),
+ productTypes: getProductTypes(),
+ profileItems: getProfileItems(),
+ };
+ }
+ );
const toggleCartModal = useCallback( () => {
if ( ! cartModalOpen ) {
@@ -37,6 +42,7 @@ const PurchaseTaskItem = () => {
}, [ cartModalOpen ] );
const groupedProducts = getCategorizedOnboardingProducts(
+ productTypes,
profileItems,
installedPlugins
);
diff --git a/plugins/woocommerce-admin/packages/data/src/onboarding/action-types.js b/plugins/woocommerce-admin/packages/data/src/onboarding/action-types.js
index 36f621ab65d..7eae1465621 100644
--- a/plugins/woocommerce-admin/packages/data/src/onboarding/action-types.js
+++ b/plugins/woocommerce-admin/packages/data/src/onboarding/action-types.js
@@ -5,6 +5,8 @@ const TYPES = {
SET_EMAIL_PREFILL: 'SET_EMAIL_PREFILL',
SET_TASKS_STATUS: 'SET_TASKS_STATUS',
GET_PAYMENT_METHODS_SUCCESS: 'GET_PAYMENT_METHODS_SUCCESS',
+ GET_PRODUCT_TYPES_SUCCESS: 'GET_PRODUCT_TYPES_SUCCESS',
+ GET_PRODUCT_TYPES_ERROR: 'GET_PRODUCT_TYPES_ERROR',
GET_FREE_EXTENSIONS_ERROR: 'GET_FREE_EXTENSIONS_ERROR',
GET_FREE_EXTENSIONS_SUCCESS: 'GET_FREE_EXTENSIONS_SUCCESS',
GET_TASK_LISTS_ERROR: 'GET_TASK_LISTS_ERROR',
diff --git a/plugins/woocommerce-admin/packages/data/src/onboarding/actions.js b/plugins/woocommerce-admin/packages/data/src/onboarding/actions.js
index 2efabe3ce45..e8b87d211aa 100644
--- a/plugins/woocommerce-admin/packages/data/src/onboarding/actions.js
+++ b/plugins/woocommerce-admin/packages/data/src/onboarding/actions.js
@@ -222,6 +222,20 @@ export function actionTaskSuccess( task ) {
};
}
+export function getProductTypesSuccess( productTypes ) {
+ return {
+ type: TYPES.GET_PRODUCT_TYPES_SUCCESS,
+ productTypes,
+ };
+}
+
+export function getProductTypesError( error ) {
+ return {
+ type: TYPES.GET_PRODUCT_TYPES_ERROR,
+ error,
+ };
+}
+
export function* updateProfileItems( items ) {
yield setIsRequesting( 'updateProfileItems', true );
yield setError( 'updateProfileItems', null );
diff --git a/plugins/woocommerce-admin/packages/data/src/onboarding/reducer.js b/plugins/woocommerce-admin/packages/data/src/onboarding/reducer.js
index bfc07017651..4c2c28063ad 100644
--- a/plugins/woocommerce-admin/packages/data/src/onboarding/reducer.js
+++ b/plugins/woocommerce-admin/packages/data/src/onboarding/reducer.js
@@ -25,6 +25,7 @@ export const defaultState = {
},
emailPrefill: '',
paymentMethods: [],
+ productTypes: [],
requesting: {},
taskLists: [],
tasksStatus: {},
@@ -55,6 +56,7 @@ const onboarding = (
profileItems,
emailPrefill,
paymentMethods,
+ productTypes,
replace,
error,
isRequesting,
@@ -106,6 +108,19 @@ const onboarding = (
...state,
paymentMethods,
};
+ case TYPES.GET_PRODUCT_TYPES_SUCCESS:
+ return {
+ ...state,
+ productTypes,
+ };
+ case TYPES.GET_PRODUCT_TYPES_ERROR:
+ return {
+ ...state,
+ errors: {
+ ...state.errors,
+ productTypes: error,
+ },
+ };
case TYPES.GET_FREE_EXTENSIONS_ERROR:
return {
...state,
diff --git a/plugins/woocommerce-admin/packages/data/src/onboarding/resolvers.js b/plugins/woocommerce-admin/packages/data/src/onboarding/resolvers.js
index 2f5b806827f..71ac758ad88 100644
--- a/plugins/woocommerce-admin/packages/data/src/onboarding/resolvers.js
+++ b/plugins/woocommerce-admin/packages/data/src/onboarding/resolvers.js
@@ -17,6 +17,8 @@ import {
setTasksStatus,
setPaymentMethods,
setEmailPrefill,
+ getProductTypesSuccess,
+ getProductTypesError,
} from './actions';
import { DeprecatedTasks } from './deprecated-tasks';
@@ -103,3 +105,16 @@ export function* getFreeExtensions() {
yield getFreeExtensionsError( error );
}
}
+
+export function* getProductTypes() {
+ try {
+ const results = yield apiFetch( {
+ path: WC_ADMIN_NAMESPACE + '/onboarding/product-types',
+ method: 'GET',
+ } );
+
+ yield getProductTypesSuccess( results );
+ } catch ( error ) {
+ yield getProductTypesError( error );
+ }
+}
diff --git a/plugins/woocommerce-admin/packages/data/src/onboarding/selectors.ts b/plugins/woocommerce-admin/packages/data/src/onboarding/selectors.ts
index a1497442cae..eb384d9b87c 100644
--- a/plugins/woocommerce-admin/packages/data/src/onboarding/selectors.ts
+++ b/plugins/woocommerce-admin/packages/data/src/onboarding/selectors.ts
@@ -24,6 +24,7 @@ export const getTasksStatus = (
const initialTaskLists: TaskListType[] = [];
+const EMPTY_ARRAY: Product[] = [];
export const getTaskLists = ( state: OnboardingState ): TaskListType[] => {
return state.taskLists || initialTaskLists;
};
@@ -52,6 +53,10 @@ export const getEmailPrefill = ( state: OnboardingState ): string => {
return state.emailPrefill || '';
};
+export const getProductTypes = ( state: OnboardingState ): Product[] => {
+ return state.productTypes || EMPTY_ARRAY;
+};
+
// Types
export type OnboardingSelectors = {
getProfileItems: () => ReturnType< typeof getProfileItems >;
@@ -69,6 +74,7 @@ export type OnboardingState = {
taskLists: TaskListType[];
tasksStatus: TasksStatusState;
paymentMethods: PaymentMethodsState[];
+ productTypes: Product[];
emailPrefill: string;
// TODO clarify what the error record's type is
errors: Record< string, unknown >;
@@ -151,6 +157,12 @@ export type MethodFields = {
value?: string;
};
+export type Product = {
+ default?: boolean;
+ label: string;
+ product?: number;
+};
+
export type PaymentMethodsState = {
locale: string;
title: string;
diff --git a/plugins/woocommerce-admin/src/API/Init.php b/plugins/woocommerce-admin/src/API/Init.php
index 15111257df0..8028dec0ea3 100644
--- a/plugins/woocommerce-admin/src/API/Init.php
+++ b/plugins/woocommerce-admin/src/API/Init.php
@@ -76,6 +76,7 @@ class Init {
'Automattic\WooCommerce\Admin\API\Plugins',
'Automattic\WooCommerce\Admin\API\OnboardingFreeExtensions',
'Automattic\WooCommerce\Admin\API\OnboardingPayments',
+ 'Automattic\WooCommerce\Admin\API\OnboardingProductTypes',
'Automattic\WooCommerce\Admin\API\OnboardingProfile',
'Automattic\WooCommerce\Admin\API\OnboardingTasks',
'Automattic\WooCommerce\Admin\API\OnboardingThemes',
diff --git a/plugins/woocommerce-admin/src/API/OnboardingProductTypes.php b/plugins/woocommerce-admin/src/API/OnboardingProductTypes.php
new file mode 100644
index 00000000000..46d128546a5
--- /dev/null
+++ b/plugins/woocommerce-admin/src/API/OnboardingProductTypes.php
@@ -0,0 +1,78 @@
+namespace,
+ '/' . $this->rest_base,
+ array(
+ array(
+ 'methods' => \WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_product_types' ),
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ )
+ );
+ }
+
+ /**
+ * Check whether a given request has permission to read onboarding profile data.
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_Error|boolean
+ */
+ public function get_items_permissions_check( $request ) {
+ if ( ! wc_rest_check_manager_permissions( 'settings', 'read' ) ) {
+ return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce-admin' ), array( 'status' => rest_authorization_required_code() ) );
+ }
+
+ return true;
+ }
+
+ /**
+ * Return available product types.
+ *
+ * @param \WP_REST_Request $request Request data.
+ *
+ * @return \WP_Error|\WP_REST_Response
+ */
+ public function get_product_types( $request ) {
+ return Onboarding::get_allowed_product_types();
+ }
+
+}
diff --git a/plugins/woocommerce-admin/src/Features/Onboarding.php b/plugins/woocommerce-admin/src/Features/Onboarding.php
index 176f617b9f3..dc6c4c9ea98 100644
--- a/plugins/woocommerce-admin/src/Features/Onboarding.php
+++ b/plugins/woocommerce-admin/src/Features/Onboarding.php
@@ -433,7 +433,7 @@ class Onboarding {
* @return array
*/
public static function get_allowed_product_types() {
- $products = array(
+ $products = array(
'physical' => array(
'label' => __( 'Physical products', 'woocommerce-admin' ),
'default' => true,
@@ -461,7 +461,8 @@ class Onboarding {
'product' => 18618,
),
);
- if ( ! Features::is_enabled( 'subscriptions' ) ) {
+ $base_location = wc_get_base_location();
+ if ( ! Features::is_enabled( 'subscriptions' ) || 'US' !== $base_location['country'] ) {
$products['subscriptions']['product'] = 27147;
}
$product_types = self::append_product_data( $products );
@@ -690,7 +691,6 @@ class Onboarding {
$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();