Commit f37fd84f70d for woocommerce
commit f37fd84f70d761513dddddc5900018abf837d203
Author: Albert Juhé Lluveras <contact@albertjuhe.com>
Date: Mon Oct 26 08:17:35 2026 +0100
Fix circular dependencies (#70173)
* Fix circular dependency in template selector
* Fix circular dependency in type guards
* Fix circular dependency in Product Collection
* Fix circular dependency in cart-checkout package
* Fix circular dependency in payment stores
* Fix circular dependency in block-data
* Fix circular dependency in email editor events
* Add changelog
* Revert "Fix circular dependency in email editor events"
This reverts commit f91d1562b365b399d31198b5fd58eba8e99086d0.
* Revert "Fix circular dependency in block-data"
This reverts commit e59c21511afaf3b4c6068f5e89a45d5584e19b94.
* Revert "Fix circular dependency in payment stores"
This reverts commit baddac69a1d80a38d267d13a1404d56811bcae1a.
* Revert "Fix circular dependency in cart-checkout package"
This reverts commit d99a280a34a2e6bb8b9cc694451b8f671be6e943.
diff --git a/plugins/woocommerce/changelog/fix-circular-dependencies b/plugins/woocommerce/changelog/fix-circular-dependencies
new file mode 100644
index 00000000000..faf6aa5cb60
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-circular-dependencies
@@ -0,0 +1,5 @@
+Significance: patch
+Type: fix
+Comment: Fix circular dependencies
+
+
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/index.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/index.tsx
index 06ec94aac8b..eb2a02f0f48 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/index.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/index.tsx
@@ -1,9 +1,6 @@
/**
* External dependencies
*/
-import { useMemo } from '@wordpress/element';
-import { useSelect } from '@wordpress/data';
-import { store as coreStore } from '@wordpress/core-data';
import ProductCategoryControl from '@woocommerce/editor-components/product-category-control';
import ProductTagControl from '@woocommerce/editor-components/product-tag-control';
import ProductBrandControl from '@woocommerce/editor-components/product-brand-control';
@@ -21,24 +18,7 @@ import TaxonomyItem from './taxonomy-item';
import { QueryControlProps } from '../../../types';
import useTaxonomyControls from './use-taxonomy-controls';
-/**
- * Hook that returns the taxonomies associated with product post type.
- */
-export const useTaxonomies = (): Taxonomy[] => {
- const taxonomies = useSelect( ( select ) => {
- const { getTaxonomies } = select( coreStore );
- const filteredTaxonomies: Taxonomy[] = getTaxonomies( {
- type: 'product',
- per_page: -1,
- } );
- return filteredTaxonomies;
- }, [] );
- return useMemo( () => {
- return taxonomies?.filter(
- ( { visibility } ) => !! visibility?.publicly_queryable
- );
- }, [ taxonomies ] );
-};
+export { useTaxonomies } from './use-taxonomies';
/**
* Normalize the name so first letter of every word is capitalized.
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/use-taxonomies.ts b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/use-taxonomies.ts
new file mode 100644
index 00000000000..a17baac3463
--- /dev/null
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/use-taxonomies.ts
@@ -0,0 +1,26 @@
+/**
+ * External dependencies
+ */
+import { useMemo } from '@wordpress/element';
+import { useSelect } from '@wordpress/data';
+import { store as coreStore } from '@wordpress/core-data';
+import type { Taxonomy } from '@wordpress/core-data';
+
+/**
+ * Hook that returns the taxonomies associated with product post type.
+ */
+export const useTaxonomies = (): Taxonomy[] => {
+ const taxonomies = useSelect( ( select ) => {
+ const { getTaxonomies } = select( coreStore );
+ const filteredTaxonomies: Taxonomy[] = getTaxonomies( {
+ type: 'product',
+ per_page: -1,
+ } );
+ return filteredTaxonomies;
+ }, [] );
+ return useMemo( () => {
+ return taxonomies?.filter(
+ ( { visibility } ) => !! visibility?.publicly_queryable
+ );
+ }, [ taxonomies ] );
+};
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/use-taxonomy-controls.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/use-taxonomy-controls.tsx
index ea9207427c2..c2183ce5c69 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/use-taxonomy-controls.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/taxonomy-controls/use-taxonomy-controls.tsx
@@ -6,7 +6,7 @@ import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
-import { useTaxonomies } from './index';
+import { useTaxonomies } from './use-taxonomies';
import {
QueryControlProps,
CoreFilterNames,
diff --git a/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/index.ts b/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/index.ts
index aa9e200d232..fa48a77da5c 100644
--- a/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/index.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/index.ts
@@ -1,142 +1,3 @@
-/**
- * External dependencies
- */
-import { createReduxStore, register, select } from '@wordpress/data';
-
-/**
- * Internal dependencies
- */
-import {
- ACTION_SET_PRODUCT_TYPES,
- ACTION_SWITCH_PRODUCT_TYPE,
- ACTION_REGISTER_LISTENER,
- ACTION_UNREGISTER_LISTENER,
- STORE_NAME,
-} from './constants';
-import { getProductTypeOptions } from '../../../utils/get-product-type-options';
-import type { ProductTypeProps } from './types';
-
-type StoreState = {
- productTypes: {
- list: ProductTypeProps[];
- current: string | undefined;
- };
- listeners: string[];
-};
-
-type Actions = {
- type:
- | typeof ACTION_SET_PRODUCT_TYPES
- | typeof ACTION_SWITCH_PRODUCT_TYPE
- | typeof ACTION_REGISTER_LISTENER
- | typeof ACTION_UNREGISTER_LISTENER;
- productTypes?: ProductTypeProps[];
- current?: string;
- listener?: string;
-};
-
-const productTypeOptions = getProductTypeOptions();
-
-const DEFAULT_STATE = {
- productTypes: {
- list: productTypeOptions,
- current: productTypeOptions[ 0 ]?.slug,
- },
- listeners: [],
-};
-
-const actions = {
- switchProductType( slug: string ) {
- return {
- type: ACTION_SWITCH_PRODUCT_TYPE,
- current: slug,
- };
- },
-
- setProductTypes( productTypes: ProductTypeProps[] ) {
- return {
- type: ACTION_SET_PRODUCT_TYPES,
- productTypes,
- };
- },
-
- registerListener( listener: string ) {
- return {
- type: ACTION_REGISTER_LISTENER,
- listener,
- };
- },
-
- unregisterListener( listener: string ) {
- return {
- type: ACTION_UNREGISTER_LISTENER,
- listener,
- };
- },
-};
-
-const selectors = {
- getProductTypes( state: StoreState ) {
- return state.productTypes.list;
- },
- getCurrentProductType( state: StoreState ) {
- return state.productTypes.list.find(
- ( productType ) => productType.slug === state.productTypes.current
- );
- },
- getRegisteredListeners( state: StoreState ) {
- return state.listeners;
- },
-};
-
-const reducer = ( state: StoreState = DEFAULT_STATE, action: Actions ) => {
- switch ( action.type ) {
- case ACTION_SET_PRODUCT_TYPES:
- return {
- ...state,
- productTypes: {
- ...state.productTypes,
- list: action.productTypes || [],
- },
- };
-
- case ACTION_SWITCH_PRODUCT_TYPE:
- return {
- ...state,
- productTypes: {
- ...state.productTypes,
- current: action.current,
- },
- };
-
- case ACTION_REGISTER_LISTENER:
- return {
- ...state,
- listeners: [ ...state.listeners, action.listener || '' ],
- };
-
- case ACTION_UNREGISTER_LISTENER:
- return {
- ...state,
- listeners: state.listeners.filter(
- ( listener ) => listener !== action.listener
- ),
- };
-
- default:
- return state;
- }
-};
-
-export const store = createReduxStore( STORE_NAME, {
- reducer,
- actions,
- selectors,
-} );
-
-if ( ! select( STORE_NAME ) ) {
- register( store );
-}
-
+export { store } from './store';
export { default as useProductTypeSelector } from './use-product-type-selector';
export type { ProductTypeProps } from './types';
diff --git a/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/store.ts b/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/store.ts
new file mode 100644
index 00000000000..cb9c8ce7a5b
--- /dev/null
+++ b/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/store.ts
@@ -0,0 +1,139 @@
+/**
+ * External dependencies
+ */
+import { createReduxStore, register, select } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import {
+ ACTION_SET_PRODUCT_TYPES,
+ ACTION_SWITCH_PRODUCT_TYPE,
+ ACTION_REGISTER_LISTENER,
+ ACTION_UNREGISTER_LISTENER,
+ STORE_NAME,
+} from './constants';
+import { getProductTypeOptions } from '../../../utils/get-product-type-options';
+import type { ProductTypeProps } from './types';
+
+type StoreState = {
+ productTypes: {
+ list: ProductTypeProps[];
+ current: string | undefined;
+ };
+ listeners: string[];
+};
+
+type Actions = {
+ type:
+ | typeof ACTION_SET_PRODUCT_TYPES
+ | typeof ACTION_SWITCH_PRODUCT_TYPE
+ | typeof ACTION_REGISTER_LISTENER
+ | typeof ACTION_UNREGISTER_LISTENER;
+ productTypes?: ProductTypeProps[];
+ current?: string;
+ listener?: string;
+};
+
+const productTypeOptions = getProductTypeOptions();
+
+const DEFAULT_STATE = {
+ productTypes: {
+ list: productTypeOptions,
+ current: productTypeOptions[ 0 ]?.slug,
+ },
+ listeners: [],
+};
+
+const actions = {
+ switchProductType( slug: string ) {
+ return {
+ type: ACTION_SWITCH_PRODUCT_TYPE,
+ current: slug,
+ };
+ },
+
+ setProductTypes( productTypes: ProductTypeProps[] ) {
+ return {
+ type: ACTION_SET_PRODUCT_TYPES,
+ productTypes,
+ };
+ },
+
+ registerListener( listener: string ) {
+ return {
+ type: ACTION_REGISTER_LISTENER,
+ listener,
+ };
+ },
+
+ unregisterListener( listener: string ) {
+ return {
+ type: ACTION_UNREGISTER_LISTENER,
+ listener,
+ };
+ },
+};
+
+const selectors = {
+ getProductTypes( state: StoreState ) {
+ return state.productTypes.list;
+ },
+ getCurrentProductType( state: StoreState ) {
+ return state.productTypes.list.find(
+ ( productType ) => productType.slug === state.productTypes.current
+ );
+ },
+ getRegisteredListeners( state: StoreState ) {
+ return state.listeners;
+ },
+};
+
+const reducer = ( state: StoreState = DEFAULT_STATE, action: Actions ) => {
+ switch ( action.type ) {
+ case ACTION_SET_PRODUCT_TYPES:
+ return {
+ ...state,
+ productTypes: {
+ ...state.productTypes,
+ list: action.productTypes || [],
+ },
+ };
+
+ case ACTION_SWITCH_PRODUCT_TYPE:
+ return {
+ ...state,
+ productTypes: {
+ ...state.productTypes,
+ current: action.current,
+ },
+ };
+
+ case ACTION_REGISTER_LISTENER:
+ return {
+ ...state,
+ listeners: [ ...state.listeners, action.listener || '' ],
+ };
+
+ case ACTION_UNREGISTER_LISTENER:
+ return {
+ ...state,
+ listeners: state.listeners.filter(
+ ( listener ) => listener !== action.listener
+ ),
+ };
+
+ default:
+ return state;
+ }
+};
+
+export const store = createReduxStore( STORE_NAME, {
+ reducer,
+ actions,
+ selectors,
+} );
+
+if ( ! select( STORE_NAME ) ) {
+ register( store );
+}
diff --git a/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/use-product-type-selector.ts b/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/use-product-type-selector.ts
index 93a7c821dcb..6ada98a7df0 100644
--- a/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/use-product-type-selector.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/shared/stores/product-type-template-state/use-product-type-selector.ts
@@ -5,7 +5,7 @@ import { useSelect, useDispatch } from '@wordpress/data';
/**
* Internal dependencies
*/
-import { store as productTypeTemplateStateStore } from '../product-type-template-state';
+import { store as productTypeTemplateStateStore } from './store';
import type { ProductTypeProps } from './types';
type ProductTypeSelector = {
diff --git a/plugins/woocommerce/client/blocks/assets/js/utils/get-product-type-options.ts b/plugins/woocommerce/client/blocks/assets/js/utils/get-product-type-options.ts
index 09bb7bb959b..474df72ff69 100644
--- a/plugins/woocommerce/client/blocks/assets/js/utils/get-product-type-options.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/utils/get-product-type-options.ts
@@ -6,7 +6,7 @@ import { getSetting } from '@woocommerce/settings';
/**
* Internal dependencies
*/
-import type { ProductTypeProps } from '../shared/stores/product-type-template-state';
+import type { ProductTypeProps } from '../shared/stores/product-type-template-state/types';
const productTypes = getSetting< Record< string, string > >(
'productTypes',
diff --git a/plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/observers.ts b/plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/observers.ts
index 38712d89d51..b5278ecb557 100644
--- a/plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/observers.ts
+++ b/plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/observers.ts
@@ -1,7 +1,8 @@
/**
* Internal dependencies
*/
-import { FieldValidationStatus, isObject, objectHasProp } from '../';
+import { isObject, objectHasProp } from './object';
+import type { FieldValidationStatus } from '../type-defs/validation';
export enum responseTypes {
SUCCESS = 'success',
diff --git a/plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/validation.ts b/plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/validation.ts
index 6b92e366677..b8b8e91c8dd 100644
--- a/plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/validation.ts
+++ b/plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/validation.ts
@@ -1,13 +1,10 @@
/**
* Internal dependencies
*/
-import {
- FieldValidationStatus,
- isBoolean,
- isObject,
- isString,
- objectHasProp,
-} from '../';
+import { isBoolean } from './boolean';
+import { isObject, objectHasProp } from './object';
+import { isString } from './string';
+import type { FieldValidationStatus } from '../type-defs/validation';
/**
* Whether the given status is a valid FieldValidationStatus.