Commit a11eadff11a for woocommerce
commit a11eadff11a9fabf5efe621756057031a6d2abc9
Author: Mike Jolley <mike.jolley@me.com>
Date: Mon Oct 26 15:32:41 2026 +0000
Fix Store API attribute filters for variations (#70232)
* Keep Store API variation attribute filters on attribute meta
Variations store attribute selections as attribute_* meta, never as
terms. If an extension registers a pa_* taxonomy for product_variation,
the routing added in #70124 sent the filter to a term query, so "in"
filters matched nothing and "not_in" filters matched everything.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Add changelog entry for variation attribute filter routing fix
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/fix-variation-attribute-filter-routing b/plugins/woocommerce/changelog/fix-variation-attribute-filter-routing
new file mode 100644
index 00000000000..00a55d5125b
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-variation-attribute-filter-routing
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+Comment: Keep variation attribute filters on attribute meta; follow-up to an unreleased Store API fix.
+
diff --git a/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php b/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php
index 18e49b1425e..96e446df11d 100644
--- a/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php
+++ b/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php
@@ -178,11 +178,13 @@ class ProductQuery implements QueryClausesGenerator {
if ( ! empty( $tax_query ) && 'product_variation' !== $args['post_type'] ) {
$args['tax_query'] = $tax_query; // phpcs:ignore
} else {
- // Taxonomies registered for variations are queried directly. The rest are stored on variations as attribute meta.
+ // Taxonomies registered for variations are queried directly. Attributes are always stored on variations as meta, even when registered for them.
$variation_tax_query = array_filter(
$tax_query,
function ( $tax_query_item ) {
- return isset( $tax_query_item['taxonomy'] ) && is_object_in_taxonomy( 'product_variation', $tax_query_item['taxonomy'] );
+ return isset( $tax_query_item['taxonomy'] )
+ && ! taxonomy_is_product_attribute( $tax_query_item['taxonomy'] )
+ && is_object_in_taxonomy( 'product_variation', $tax_query_item['taxonomy'] );
}
);
diff --git a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Utilities/ProductQueryTest.php b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Utilities/ProductQueryTest.php
index 3fa9f535d93..c80cf0a8058 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Utilities/ProductQueryTest.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Utilities/ProductQueryTest.php
@@ -432,6 +432,37 @@ class ProductQueryTest extends \WC_Unit_Test_Case {
$this->assertSame( array( $alpha_variation->get_id() ), $results['results'], 'Only the variation assigned the requested term should be returned.' );
}
+ /**
+ * @testdox Attribute filters on variations use attribute meta even when the attribute taxonomy is registered for variations.
+ */
+ public function test_variation_attribute_filter_uses_meta_when_attribute_is_registered_for_variations(): void {
+ $fixtures = new FixtureData();
+ $attribute = $fixtures->get_product_attribute( 'variation-registered', array( 'red', 'blue' ) );
+ $taxonomy = $attribute['attribute_taxonomy'];
+ register_taxonomy_for_object_type( $taxonomy, 'product_variation' );
+
+ $parent_product = $fixtures->get_variable_product( array(), array( $attribute ) );
+ $red_variation = $fixtures->get_variation_product( $parent_product->get_id(), array( $taxonomy => 'red' ) );
+ $blue_variation = $fixtures->get_variation_product( $parent_product->get_id(), array( $taxonomy => 'blue' ) );
+
+ $request = new \WP_REST_Request( 'GET', '/wc/store/v1/products' );
+ $request->set_param( 'type', 'variation' );
+ $request->set_param( 'include', array( $red_variation->get_id(), $blue_variation->get_id() ) );
+ $request->set_param(
+ 'attributes',
+ array(
+ array(
+ 'attribute' => $taxonomy,
+ 'slug' => array( 'red' ),
+ ),
+ )
+ );
+
+ $results = $this->product_query->get_results( $request );
+
+ $this->assertSame( array( $red_variation->get_id() ), $results['results'], 'Only the variation with the requested attribute value should be returned.' );
+ }
+
/**
* Get product IDs matched by a Store API slug filter.
*