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.