Commit b01d5af8c74 for woocommerce

commit b01d5af8c7487245612385670ff3de366950fb86
Author: Luigi Teschio <gigitux@gmail.com>
Date:   Wed May 13 10:14:59 2026 +0200

    Update quick edit field ordering (#64812)

    * show right fields bulk editing

    * Update quick edit field ordering

    * Add changefile(s) from automation for the following project(s): @woocommerce/experimental-products-app

    ---------

    Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>

diff --git a/packages/js/experimental-products-app/changelog/64812-fix-bulk-editing-field b/packages/js/experimental-products-app/changelog/64812-fix-bulk-editing-field
new file mode 100644
index 00000000000..60cbe154750
--- /dev/null
+++ b/packages/js/experimental-products-app/changelog/64812-fix-bulk-editing-field
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Ensure product quick edit shows the correct fields in the expected order.
\ No newline at end of file
diff --git a/packages/js/experimental-products-app/src/fields/components/dimension.tsx b/packages/js/experimental-products-app/src/fields/components/dimension.tsx
index 4abcb6249db..1a42f1016c1 100644
--- a/packages/js/experimental-products-app/src/fields/components/dimension.tsx
+++ b/packages/js/experimental-products-app/src/fields/components/dimension.tsx
@@ -17,6 +17,7 @@ export const createDimensionField = (
 	key: DimensionKey
 ): Partial< Field< ProductEntityRecord > > => {
 	return {
+		isVisible: ( item ) => ! item.virtual,
 		Edit: ( { data, onChange, field } ) => {
 			const {
 				record: storeProductsSettings,
diff --git a/packages/js/experimental-products-app/src/fields/downloadable/field.tsx b/packages/js/experimental-products-app/src/fields/downloadable/field.tsx
index 3774bad3711..e5f9b2751dd 100644
--- a/packages/js/experimental-products-app/src/fields/downloadable/field.tsx
+++ b/packages/js/experimental-products-app/src/fields/downloadable/field.tsx
@@ -37,7 +37,8 @@ const fieldDefinition = {
 export const fieldExtensions: Partial< Field< ProductEntityRecord > > = {
 	...fieldDefinition,
 	type: 'boolean',
-	isVisible: ( item ) => item.downloadable === true,
+	isVisible: ( item ) =>
+		item.downloadable === true && item.type !== 'variable',
 	getValue: ( { item } ) => item.downloadable,
 	Edit: ( { data, onChange } ) => {
 		const downloads = ( data.downloads ?? [] ) as Array<
diff --git a/packages/js/experimental-products-app/src/fields/registry.tsx b/packages/js/experimental-products-app/src/fields/registry.tsx
index 21134f6d03a..cd3782d0ad6 100644
--- a/packages/js/experimental-products-app/src/fields/registry.tsx
+++ b/packages/js/experimental-products-app/src/fields/registry.tsx
@@ -64,11 +64,11 @@ export const PRODUCT_FIELD_IDS = [
 	'sku',
 	'price',
 	'regular_price',
+	'on_sale',
 	'sale_price',
 	'schedule_sale',
 	'date_on_sale_from',
 	'date_on_sale_to',
-	'on_sale',
 	'price_summary',
 	'stock',
 	'stock_quantity',
diff --git a/packages/js/experimental-products-app/src/fields/shipping_class/field.tsx b/packages/js/experimental-products-app/src/fields/shipping_class/field.tsx
index 4e174986834..389700c3470 100644
--- a/packages/js/experimental-products-app/src/fields/shipping_class/field.tsx
+++ b/packages/js/experimental-products-app/src/fields/shipping_class/field.tsx
@@ -34,6 +34,7 @@ export const fieldExtensions: Partial< Field< ProductEntityRecord > > = {
 	label: __( 'Shipping Class', 'woocommerce' ),
 	enableSorting: false,
 	type: 'text',
+	isVisible: ( item ) => ! item.virtual,
 	getValue: ( { item } ) => item.shipping_class,
 	Edit: ( { data, onChange, field } ) => {
 		const { shippingClasses } = useSelect( ( select ) => {
diff --git a/packages/js/experimental-products-app/src/fields/weight/field.tsx b/packages/js/experimental-products-app/src/fields/weight/field.tsx
index ec53e70ff5c..f4473271a15 100644
--- a/packages/js/experimental-products-app/src/fields/weight/field.tsx
+++ b/packages/js/experimental-products-app/src/fields/weight/field.tsx
@@ -23,6 +23,7 @@ const fieldDefinition = {
 export const fieldExtensions: Partial< Field< ProductEntityRecord > > = {
 	...fieldDefinition,
 	label: __( 'Weight', 'woocommerce' ),
+	isVisible: ( item ) => ! item.virtual,
 	Edit: ( { data, onChange, field } ) => {
 		const {
 			record: storeProductsSettings,
diff --git a/packages/js/experimental-products-app/src/product-edit/utils.test.ts b/packages/js/experimental-products-app/src/product-edit/utils.test.ts
index aeeef708fbb..70ede4ed98c 100644
--- a/packages/js/experimental-products-app/src/product-edit/utils.test.ts
+++ b/packages/js/experimental-products-app/src/product-edit/utils.test.ts
@@ -234,6 +234,20 @@ describe( 'product edit utils', () => {
 				expect( fieldIds ).not.toContain( fieldId );
 			} );
 		};
+		const expectFieldOrder = (
+			fieldIds: string[],
+			orderedFieldIds: string[]
+		) => {
+			orderedFieldIds.forEach( ( fieldId, index ) => {
+				const previousFieldId = orderedFieldIds[ index - 1 ];
+
+				if ( previousFieldId ) {
+					expect( fieldIds.indexOf( previousFieldId ) ).toBeLessThan(
+						fieldIds.indexOf( fieldId )
+					);
+				}
+			} );
+		};
 		const parentOwnedFieldIds = [
 			'name',
 			'short_description',
@@ -241,6 +255,7 @@ describe( 'product edit utils', () => {
 			'product_status',
 			'catalog_visibility',
 			'categories',
+			'brands',
 			'tags',
 			'type',
 			'featured',
@@ -258,23 +273,26 @@ describe( 'product edit utils', () => {
 			'date_on_sale_from',
 			'date_on_sale_to',
 		];
-		const universalFieldIds = [
-			'images',
-			'sku',
-			'manage_stock',
-			'stock_quantity',
+		const basePriceFieldIds = [ 'regular_price', 'on_sale' ];
+		const managedStockFieldIds = [ 'manage_stock', 'stock_quantity' ];
+		const stockStatusFieldIds = [ 'stock', 'manage_stock' ];
+		const shippingFieldIds = [
 			'weight',
 			'length',
 			'width',
 			'height',
 			'shipping_class',
-			'tax_status',
 		];
-		const bulkUniversalFieldIds = universalFieldIds.filter(
+		const sellableInstanceFieldIds = [
+			'images',
+			'sku',
+			...managedStockFieldIds,
+		];
+		const bulkSellableInstanceFieldIds = sellableInstanceFieldIds.filter(
 			( fieldId ) => fieldId !== 'sku'
 		);

-		it( 'shows pricing, shipping, and linked product fields for simple physical products', () => {
+		it( 'shows simple product fields in quick edit order', () => {
 			const fieldIds = getVisibleFieldIds( [
 				buildProduct( {
 					type: 'simple',
@@ -286,24 +304,35 @@ describe( 'product edit utils', () => {
 				} ),
 			] );

-			expect( fieldIds ).toEqual(
-				expect.arrayContaining( [
-					'price',
-					'regular_price',
-					'on_sale',
-					'sale_price',
-					'schedule_sale',
-					'date_on_sale_from',
-					'weight',
-					'length',
-					'width',
-					'height',
-					'shipping_class',
-					'upsell_ids',
-					'cross_sell_ids',
-				] )
-			);
-			expectFieldsHidden( fieldIds, [ 'external_url', 'button_text' ] );
+			expect( fieldIds ).toEqual( [
+				'name',
+				'product_status',
+				'catalog_visibility',
+				'regular_price',
+				'on_sale',
+				'sale_price',
+				'images',
+				'sku',
+				'stock',
+				'manage_stock',
+				'categories',
+				'brands',
+				'tags',
+			] );
+			expectFieldsHidden( fieldIds, [
+				'price',
+				'schedule_sale',
+				'date_on_sale_from',
+				'date_on_sale_to',
+				'downloadable',
+				'external_url',
+				'button_text',
+				...shippingFieldIds,
+				'tax_status',
+				'upsell_ids',
+				'cross_sell_ids',
+				'featured',
+			] );
 		} );

 		it( 'does not include excluded fields in product type compatibility', () => {
@@ -318,7 +347,24 @@ describe( 'product edit utils', () => {
 			);
 		} );

-		it( 'uses the same compatible fields for simple products regardless of virtual status', () => {
+		it( 'orders pricing fields for the quick edit form', () => {
+			const fieldIds = getVisibleFieldIds( [
+				buildProduct( {
+					type: 'simple',
+					on_sale: true,
+					sale_price: '12',
+					date_on_sale_from: '2026-05-06T00:00:00',
+				} ),
+			] );
+
+			expectFieldOrder( fieldIds, [
+				'regular_price',
+				'on_sale',
+				'sale_price',
+			] );
+		} );
+
+		it( 'hides shipping fields for virtual simple products', () => {
 			const fieldIds = getVisibleFieldIds( [
 				buildProduct( {
 					type: 'simple',
@@ -329,18 +375,19 @@ describe( 'product edit utils', () => {

 			expect( fieldIds ).toEqual(
 				expect.arrayContaining( [
-					'price',
 					'regular_price',
-					'weight',
-					'length',
-					'width',
-					'height',
-					'shipping_class',
-					'upsell_ids',
-					'cross_sell_ids',
+					'categories',
+					'brands',
+					'tags',
 				] )
 			);
-			expectFieldsHidden( fieldIds, [ 'external_url', 'button_text' ] );
+			expectFieldsHidden( fieldIds, [
+				...shippingFieldIds,
+				'external_url',
+				'button_text',
+				'upsell_ids',
+				'cross_sell_ids',
+			] );
 		} );

 		it( 'shows downloads for simple downloadable products', () => {
@@ -353,15 +400,40 @@ describe( 'product edit utils', () => {
 			] );

 			expect( fieldIds ).toContain( 'downloadable' );
-			expect( fieldIds ).toEqual(
-				expect.arrayContaining( [
-					'weight',
-					'length',
-					'width',
-					'height',
-					'shipping_class',
-				] )
-			);
+			expectFieldOrder( fieldIds, [ 'images', 'downloadable', 'sku' ] );
+			expectFieldsHidden( fieldIds, shippingFieldIds );
+		} );
+
+		it( 'shows grouped product fields in quick edit order', () => {
+			const fieldIds = getVisibleFieldIds( [
+				buildProduct( {
+					type: 'grouped',
+				} ),
+			] );
+
+			expect( fieldIds ).toEqual( [
+				'name',
+				'product_status',
+				'catalog_visibility',
+				'upsell_ids',
+				'images',
+				'sku',
+				'categories',
+				'brands',
+				'tags',
+				'featured',
+			] );
+			expectFieldsHidden( fieldIds, [
+				...priceFieldIds,
+				'downloadable',
+				'cross_sell_ids',
+				'external_url',
+				'button_text',
+				...shippingFieldIds,
+				...stockStatusFieldIds,
+				'stock_quantity',
+				'tax_status',
+			] );
 		} );

 		it( 'shows external fields for external products', () => {
@@ -371,23 +443,33 @@ describe( 'product edit utils', () => {
 				} ),
 			] );

-			expect( fieldIds ).toEqual(
-				expect.arrayContaining( [
-					'price',
-					'regular_price',
-					'external_url',
-					'button_text',
-					'upsell_ids',
-				] )
-			);
+			expect( fieldIds ).toEqual( [
+				'name',
+				'product_status',
+				'catalog_visibility',
+				'regular_price',
+				'on_sale',
+				'images',
+				'external_url',
+				'button_text',
+				'sku',
+				'categories',
+				'brands',
+				'tags',
+				'featured',
+			] );
 			expectFieldsHidden( fieldIds, [
+				'price',
+				'sale_price',
+				'schedule_sale',
+				'date_on_sale_from',
+				'date_on_sale_to',
 				'cross_sell_ids',
 				'downloadable',
-				'weight',
-				'length',
-				'width',
-				'height',
-				'shipping_class',
+				'upsell_ids',
+				...shippingFieldIds,
+				...stockStatusFieldIds,
+				'stock_quantity',
 			] );
 		} );

@@ -395,7 +477,6 @@ describe( 'product edit utils', () => {
 			const fieldIds = getVisibleFieldIds( [
 				buildProduct( {
 					type: 'variable',
-					manage_stock: true,
 				} ),
 			] );

@@ -411,11 +492,16 @@ describe( 'product edit utils', () => {
 			] );
 			expect( fieldIds ).toEqual(
 				expect.arrayContaining( [
+					'sku',
 					'upsell_ids',
 					'cross_sell_ids',
-					...universalFieldIds,
+					'stock',
+					'manage_stock',
+					...shippingFieldIds,
+					'tax_status',
 				] )
 			);
+			expectFieldsHidden( fieldIds, [ 'stock_quantity' ] );
 		} );

 		it( 'shows parent-owned and universal fields for simple and variable products', () => {
@@ -443,33 +529,46 @@ describe( 'product edit utils', () => {
 					'catalog_visibility',
 					'categories',
 					'tags',
-					'featured',
-					'upsell_ids',
-					'cross_sell_ids',
-					...bulkUniversalFieldIds,
+					...bulkSellableInstanceFieldIds,
 				] )
 			);
+			expectFieldsHidden( fieldIds, [
+				'featured',
+				'upsell_ids',
+				'cross_sell_ids',
+				...shippingFieldIds,
+				'tax_status',
+			] );
 		} );

-		it( 'shows price but not SKU when bulk editing simple products', () => {
+		it( 'shows sale fields but not SKU when bulk editing simple products', () => {
 			const fieldIds = getVisibleFieldIds( [
 				buildProduct( {
 					id: 1,
 					type: 'simple',
 					regular_price: '12',
 					price: '12',
+					on_sale: false,
 				} ),
 				buildProduct( {
 					id: 2,
 					type: 'simple',
 					regular_price: '15',
 					price: '15',
+					on_sale: true,
+					sale_price: '12',
 				} ),
 			] );

 			expect( fieldIds ).toEqual(
-				expect.arrayContaining( [ 'price', 'regular_price' ] )
+				expect.arrayContaining( basePriceFieldIds )
 			);
+			expectFieldsHidden( fieldIds, [
+				'sale_price',
+				'schedule_sale',
+				'date_on_sale_from',
+				'date_on_sale_to',
+			] );
 			expectFieldsHidden( fieldIds, [ 'sku' ] );
 		} );

@@ -488,16 +587,77 @@ describe( 'product edit utils', () => {

 			expect( fieldIds ).toEqual(
 				expect.arrayContaining( [
-					...priceFieldIds,
-					...universalFieldIds,
+					'regular_price',
+					'on_sale',
+					'sale_price',
+					'images',
+					'sku',
+					'manage_stock',
+					'stock_quantity',
 				] )
 			);
 			expectFieldsHidden( fieldIds, [
 				...parentOwnedFieldIds,
+				'stock',
 				'downloadable',
+				'price',
+				'schedule_sale',
+				'date_on_sale_from',
+				'date_on_sale_to',
+				...shippingFieldIds,
+				'tax_status',
 			] );
 		} );

+		it( 'computes variation fields from parent IDs even when type differs', () => {
+			const fieldIds = getVisibleFieldIds( [
+				buildProduct( {
+					id: 34,
+					parent_id: 12,
+					type: 'simple',
+					on_sale: true,
+					sale_price: '12',
+					date_on_sale_from: '2026-05-06T00:00:00',
+				} ),
+			] );
+
+			expect( fieldIds ).toEqual(
+				expect.arrayContaining( [
+					'images',
+					'sku',
+					'regular_price',
+					'on_sale',
+					'sale_price',
+					'stock',
+					'manage_stock',
+				] )
+			);
+			expectFieldsHidden( fieldIds, parentOwnedFieldIds );
+			expectFieldsHidden( fieldIds, [
+				'price',
+				'schedule_sale',
+				'date_on_sale_from',
+				'date_on_sale_to',
+				...shippingFieldIds,
+				'tax_status',
+			] );
+		} );
+
+		it( 'shows downloads and hides shipping for virtual downloadable variations', () => {
+			const fieldIds = getVisibleFieldIds( [
+				buildProduct( {
+					id: 34,
+					parent_id: 12,
+					type: 'variation',
+					virtual: true,
+					downloadable: true,
+				} ),
+			] );
+
+			expect( fieldIds ).toContain( 'downloadable' );
+			expectFieldsHidden( fieldIds, shippingFieldIds );
+		} );
+
 		it( 'shows shared sellable instance fields for simple products and variations', () => {
 			const fieldIds = getVisibleFieldIds( [
 				buildProduct( {
@@ -521,17 +681,89 @@ describe( 'product edit utils', () => {

 			expect( fieldIds ).toEqual(
 				expect.arrayContaining( [
-					...priceFieldIds,
-					...bulkUniversalFieldIds,
+					'regular_price',
+					'on_sale',
+					'sale_price',
+					...bulkSellableInstanceFieldIds,
 				] )
 			);
 			expectFieldsHidden( fieldIds, [
 				...parentOwnedFieldIds,
 				'downloadable',
 				'sku',
+				'price',
+				'schedule_sale',
+				'date_on_sale_from',
+				'date_on_sale_to',
 			] );
 		} );

+		it( 'hides shipping fields when a bulk variation selection includes virtual items', () => {
+			const fieldIds = getVisibleFieldIds( [
+				buildProduct( {
+					id: 1,
+					type: 'simple',
+					virtual: false,
+					manage_stock: true,
+				} ),
+				buildProduct( {
+					id: 34,
+					parent_id: 12,
+					type: 'variation',
+					virtual: true,
+					manage_stock: true,
+				} ),
+			] );
+
+			expect( fieldIds ).toEqual(
+				expect.arrayContaining( [
+					...basePriceFieldIds,
+					'images',
+					...managedStockFieldIds,
+				] )
+			);
+			expectFieldsHidden( fieldIds, [
+				...shippingFieldIds,
+				'tax_status',
+				'sku',
+			] );
+		} );
+
+		it( 'shows downloadable fields when every bulk sellable item is downloadable', () => {
+			const fieldIds = getVisibleFieldIds( [
+				buildProduct( {
+					id: 1,
+					type: 'simple',
+					downloadable: true,
+				} ),
+				buildProduct( {
+					id: 34,
+					parent_id: 12,
+					type: 'variation',
+					downloadable: true,
+				} ),
+			] );
+
+			expect( fieldIds ).toContain( 'downloadable' );
+		} );
+
+		it( 'hides downloadable fields unless every bulk item supports downloads', () => {
+			const fieldIds = getVisibleFieldIds( [
+				buildProduct( {
+					id: 1,
+					type: 'simple',
+					downloadable: true,
+				} ),
+				buildProduct( {
+					id: 2,
+					type: 'simple',
+					downloadable: false,
+				} ),
+			] );
+
+			expectFieldsHidden( fieldIds, [ 'downloadable' ] );
+		} );
+
 		it( 'shows only universal fields for variable products and variations', () => {
 			const fieldIds = getVisibleFieldIds( [
 				buildProduct( {
@@ -551,13 +783,15 @@ describe( 'product edit utils', () => {
 			] );

 			expect( fieldIds ).toEqual(
-				expect.arrayContaining( bulkUniversalFieldIds )
+				expect.arrayContaining( [ ...managedStockFieldIds ] )
 			);
 			expectFieldsHidden( fieldIds, [
 				...parentOwnedFieldIds,
 				...priceFieldIds,
 				'downloadable',
 				'sku',
+				...shippingFieldIds,
+				'tax_status',
 			] );
 		} );

@@ -588,13 +822,15 @@ describe( 'product edit utils', () => {
 			] );

 			expect( fieldIds ).toEqual(
-				expect.arrayContaining( bulkUniversalFieldIds )
+				expect.arrayContaining( [ 'images', ...managedStockFieldIds ] )
 			);
 			expectFieldsHidden( fieldIds, [
 				...parentOwnedFieldIds,
 				...priceFieldIds,
 				'downloadable',
 				'sku',
+				...shippingFieldIds,
+				'tax_status',
 			] );
 		} );

diff --git a/packages/js/experimental-products-app/src/product-edit/utils.ts b/packages/js/experimental-products-app/src/product-edit/utils.ts
index badf7158313..683e5807bb2 100644
--- a/packages/js/experimental-products-app/src/product-edit/utils.ts
+++ b/packages/js/experimental-products-app/src/product-edit/utils.ts
@@ -50,6 +50,7 @@ const PRODUCT_EDIT_FIELD_IDS = [
 	'manage_stock',
 	'inventory_summary',
 	'categories',
+	'brands',
 	'tags',
 	'organization_summary',
 	'type',
@@ -72,66 +73,31 @@ const PRODUCT_EDIT_FIELD_IDS = [
 	'linked_products_count',
 ] as const;

-const COMMON_PRODUCT_EDIT_FIELD_IDS = [
+const SIMPLE_PRODUCT_EDIT_FIELD_IDS = [
 	'name',
-	'short_description',
-	'description',
-	'images',
 	'product_status',
-	'sku',
-	'categories',
-	'tags',
-	'featured',
 	'catalog_visibility',
-	'upsell_ids',
-] satisfies ProductEditFieldId[];
-
-const SIMPLE_PRODUCT_EDIT_FIELD_IDS = [
-	...COMMON_PRODUCT_EDIT_FIELD_IDS,
-	'price',
 	'regular_price',
 	'on_sale',
 	'sale_price',
-	'schedule_sale',
-	'date_on_sale_from',
-	'date_on_sale_to',
-	'stock',
-	'stock_quantity',
-	'manage_stock',
+	'images',
 	'downloadable',
-	'weight',
-	'length',
-	'width',
-	'height',
-	'shipping_class',
-	'tax_status',
-	'cross_sell_ids',
-] satisfies ProductEditFieldId[];
-
-const VARIABLE_PRODUCT_EDIT_FIELD_IDS = [
-	...COMMON_PRODUCT_EDIT_FIELD_IDS,
+	'sku',
 	'stock',
-	'stock_quantity',
 	'manage_stock',
-	'weight',
-	'length',
-	'width',
-	'height',
-	'shipping_class',
-	'tax_status',
-	'cross_sell_ids',
+	'stock_quantity',
+	'categories',
+	'brands',
+	'tags',
 ] satisfies ProductEditFieldId[];

-const VARIATION_PRODUCT_EDIT_FIELD_IDS = [
+const VARIABLE_PRODUCT_EDIT_FIELD_IDS = [
+	'name',
+	'short_description',
+	'description',
 	'images',
+	'product_status',
 	'sku',
-	'price',
-	'regular_price',
-	'on_sale',
-	'sale_price',
-	'schedule_sale',
-	'date_on_sale_from',
-	'date_on_sale_to',
 	'stock',
 	'stock_quantity',
 	'manage_stock',
@@ -141,33 +107,53 @@ const VARIATION_PRODUCT_EDIT_FIELD_IDS = [
 	'height',
 	'shipping_class',
 	'tax_status',
+	'categories',
+	'tags',
+	'featured',
+	'catalog_visibility',
+	'upsell_ids',
+	'cross_sell_ids',
 ] satisfies ProductEditFieldId[];

 const EXTERNAL_PRODUCT_EDIT_FIELD_IDS = [
-	...COMMON_PRODUCT_EDIT_FIELD_IDS,
-	'price',
+	'name',
+	'product_status',
+	'catalog_visibility',
 	'regular_price',
 	'on_sale',
 	'sale_price',
-	'schedule_sale',
-	'date_on_sale_from',
-	'date_on_sale_to',
+	'images',
 	'external_url',
 	'button_text',
-	'tax_status',
+	'sku',
+	'categories',
+	'brands',
+	'tags',
+	'featured',
 ] satisfies ProductEditFieldId[];

 const GROUPED_PRODUCT_EDIT_FIELD_IDS = [
-	...COMMON_PRODUCT_EDIT_FIELD_IDS,
-] as const;
+	'name',
+	'product_status',
+	'catalog_visibility',
+	'upsell_ids',
+	'images',
+	'sku',
+	'categories',
+	'brands',
+	'tags',
+	'featured',
+] satisfies ProductEditFieldId[];

 const PRODUCT_TYPE_COMPATIBLE_FIELD_IDS = {
 	simple: SIMPLE_PRODUCT_EDIT_FIELD_IDS,
 	variable: VARIABLE_PRODUCT_EDIT_FIELD_IDS,
-	variation: VARIATION_PRODUCT_EDIT_FIELD_IDS,
 	grouped: GROUPED_PRODUCT_EDIT_FIELD_IDS,
 	external: EXTERNAL_PRODUCT_EDIT_FIELD_IDS,
-} satisfies Record< string, readonly ProductEditFieldId[] >;
+} satisfies Record<
+	'simple' | 'variable' | 'grouped' | 'external',
+	readonly ProductEditFieldId[]
+>;

 const PARENT_OWNED_PRODUCT_EDIT_FIELD_ID_SET = new Set< ProductEditFieldId >( [
 	'name',
@@ -176,6 +162,7 @@ const PARENT_OWNED_PRODUCT_EDIT_FIELD_ID_SET = new Set< ProductEditFieldId >( [
 	'product_status',
 	'catalog_visibility',
 	'categories',
+	'brands',
 	'tags',
 	'type',
 	'featured',
@@ -222,28 +209,6 @@ function getMixedValueFallback( sample: unknown ) {
 	return undefined;
 }

-function getFieldValue( field: ProductField, item: ProductEntityRecord ) {
-	if ( typeof field.getValue === 'function' ) {
-		return field.getValue( {
-			item,
-		} );
-	}
-
-	return item[ field.id as keyof ProductEntityRecord ];
-}
-
-function getProductTypeCompatibleFieldIds( product: ProductEntityRecord ) {
-	const productType = product.type;
-
-	if ( productType && productType in PRODUCT_TYPE_COMPATIBLE_FIELD_IDS ) {
-		return PRODUCT_TYPE_COMPATIBLE_FIELD_IDS[
-			productType as keyof typeof PRODUCT_TYPE_COMPATIBLE_FIELD_IDS
-		];
-	}
-
-	return COMMON_PRODUCT_EDIT_FIELD_IDS;
-}
-
 function isVariableProductParent( product: ProductEntityRecord ) {
 	return product.type === 'variable' && ! product.parent_id;
 }
@@ -254,6 +219,19 @@ export function isProductVariation(
 	return product.type === 'variation' || Boolean( product.parent_id );
 }

+function getProductTypeCompatibleFieldIds(
+	product: ProductEntityRecord
+): readonly ProductEditFieldId[] {
+	const productType =
+		product.type === 'variable' ||
+		product.type === 'grouped' ||
+		product.type === 'external'
+			? product.type
+			: 'simple';
+
+	return PRODUCT_TYPE_COMPATIBLE_FIELD_IDS[ productType ];
+}
+
 function isFieldVisibleForProductRelationships(
 	fieldId: string,
 	products: ProductEntityRecord[]
@@ -343,27 +321,20 @@ function getCommonProductTypeCompatibleFieldIds(
 	products: ProductEntityRecord[]
 ) {
 	if ( products.length === 0 ) {
-		return new Set< string >();
+		return [];
 	}

 	const [ firstProduct, ...remainingProducts ] = products;
-	const commonFieldIds = new Set(
-		getProductTypeCompatibleFieldIds( firstProduct )
+	const remainingCompatibleFieldIdSets = remainingProducts.map(
+		( product ) => new Set( getProductTypeCompatibleFieldIds( product ) )
 	);

-	remainingProducts.forEach( ( product ) => {
-		const compatibleFieldIds = new Set(
-			getProductTypeCompatibleFieldIds( product )
-		);
-
-		commonFieldIds.forEach( ( fieldId ) => {
-			if ( ! compatibleFieldIds.has( fieldId ) ) {
-				commonFieldIds.delete( fieldId );
-			}
-		} );
-	} );
-
-	return commonFieldIds;
+	return getProductTypeCompatibleFieldIds( firstProduct ).filter(
+		( fieldId ) =>
+			remainingCompatibleFieldIdSets.every( ( compatibleFieldIds ) =>
+				compatibleFieldIds.has( fieldId )
+			)
+	);
 }

 export function getProductEditFields( fields: ProductField[] ): ProductField[] {
@@ -407,31 +378,6 @@ export function buildMergedProductEditData(
 	return mergedData as ProductEntityRecord;
 }

-export function getMixedProductEditFieldIds(
-	fields: ProductField[],
-	products: ProductEntityRecord[]
-) {
-	if ( products.length <= 1 ) {
-		return [];
-	}
-
-	return fields.reduce< string[] >( ( mixedFields, field ) => {
-		const values = products.map( ( product ) =>
-			getFieldValue( field, product )
-		);
-		const isMixed = values.some(
-			( value ) =>
-				normalizeValue( value ) !== normalizeValue( values[ 0 ] )
-		);
-
-		if ( isMixed ) {
-			mixedFields.push( field.id );
-		}
-
-		return mixedFields;
-	}, [] );
-}
-
 export function getVisibleProductEditFields(
 	fields: ProductField[],
 	products: ProductEntityRecord[]
@@ -439,39 +385,49 @@ export function getVisibleProductEditFields(
 	const compatibleFieldIds =
 		getCommonProductTypeCompatibleFieldIds( products );
 	const isBulkEdit = products.length > 1;
+	const fieldsById = new Map(
+		fields.map( ( field ) => [ field.id, field ] )
+	);

-	return fields.reduce< ProductField[] >( ( visibleFields, field ) => {
-		if ( ! compatibleFieldIds.has( field.id ) ) {
-			return visibleFields;
-		}
+	return compatibleFieldIds.reduce< ProductField[] >(
+		( visibleFields, fieldId ) => {
+			const field = fieldsById.get( fieldId );

-		if (
-			isBulkEdit &&
-			BULK_UNSUPPORTED_PRODUCT_EDIT_FIELD_ID_SET.has(
-				field.id as ProductEditFieldId
-			)
-		) {
-			return visibleFields;
-		}
+			if ( ! field ) {
+				return visibleFields;
+			}

-		if ( ! isFieldVisibleForProductRelationships( field.id, products ) ) {
-			return visibleFields;
-		}
+			if (
+				isBulkEdit &&
+				BULK_UNSUPPORTED_PRODUCT_EDIT_FIELD_ID_SET.has(
+					field.id as ProductEditFieldId
+				)
+			) {
+				return visibleFields;
+			}

-		const { isVisible } = field;
+			if (
+				! isFieldVisibleForProductRelationships( field.id, products )
+			) {
+				return visibleFields;
+			}

-		if ( typeof isVisible !== 'function' ) {
-			visibleFields.push( field );
-			return visibleFields;
-		}
+			const { isVisible } = field;

-		if ( products.every( ( product ) => isVisible( product ) ) ) {
-			visibleFields.push( {
-				...field,
-				isVisible: undefined,
-			} );
-		}
+			if ( typeof isVisible !== 'function' ) {
+				visibleFields.push( field );
+				return visibleFields;
+			}
+
+			if ( products.every( ( product ) => isVisible( product ) ) ) {
+				visibleFields.push( {
+					...field,
+					isVisible: undefined,
+				} );
+			}

-		return visibleFields;
-	}, [] );
+			return visibleFields;
+		},
+		[]
+	);
 }