Commit 47ffbcf6fd0 for woocommerce
commit 47ffbcf6fd06da303907a232063a992e7c36ec26
Author: Tung Du <dinhtungdu@gmail.com>
Date: Tue Oct 6 14:39:10 2026 +0700
Fix product filters with unresolved taxonomy groups (#69403)
* Fix product filters with unresolved taxonomy groups
* Add changelog for product filter taxonomy fix
* Remove stale product filter PHPStan baseline entry
diff --git a/plugins/woocommerce/changelog/fix-product-filter-taxonomy-groups b/plugins/woocommerce/changelog/fix-product-filter-taxonomy-groups
new file mode 100644
index 00000000000..0d06bf0355f
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-product-filter-taxonomy-groups
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Return no products when a selected category or tag filter has no valid values.
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index de5852b1cfc..09642122ad3 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -62448,12 +62448,6 @@ parameters:
count: 1
path: src/Internal/ProductFilters/QueryClauses.php
- -
- message: '#^Variable \$term_ids in empty\(\) always exists and is not falsy\.$#'
- identifier: empty.variable
- count: 1
- path: src/Internal/ProductFilters/QueryClauses.php
-
-
message: '#^Method Automattic\\WooCommerce\\Internal\\ProductFilters\\TaxonomyHierarchyData\:\:build_term_tree\(\) has no return type specified\.$#'
identifier: missingType.return
diff --git a/plugins/woocommerce/src/Internal/ProductFilters/QueryClauses.php b/plugins/woocommerce/src/Internal/ProductFilters/QueryClauses.php
index b9d13a099c6..e5fc122235b 100644
--- a/plugins/woocommerce/src/Internal/ProductFilters/QueryClauses.php
+++ b/plugins/woocommerce/src/Internal/ProductFilters/QueryClauses.php
@@ -450,8 +450,11 @@ class QueryClauses implements QueryClausesGenerator, MainQueryClausesGenerator {
$term_ids_by_taxonomy[ $term->taxonomy ][] = $term->term_id;
}
- foreach ( $term_ids_by_taxonomy as $taxonomy => $term_ids ) {
+ foreach ( array_keys( $chosen_taxonomies ) as $taxonomy ) {
+ $term_ids = $term_ids_by_taxonomy[ $taxonomy ] ?? array();
+
if ( empty( $term_ids ) ) {
+ $tax_queries[] = '0=1';
continue;
}
@@ -501,11 +504,7 @@ class QueryClauses implements QueryClausesGenerator, MainQueryClausesGenerator {
);
}
- if ( ! empty( $tax_queries ) ) {
- $args['where'] .= ' AND (' . implode( ' AND ', $tax_queries ) . ')';
- } else {
- $args['where'] .= ' AND 1=0';
- }
+ $args['where'] .= ' AND (' . implode( ' AND ', $tax_queries ) . ')';
return $args;
}
diff --git a/plugins/woocommerce/tests/php/src/Internal/ProductFilters/QueryClausesTest.php b/plugins/woocommerce/tests/php/src/Internal/ProductFilters/QueryClausesTest.php
index 0256af2a4a5..d0a3893523e 100644
--- a/plugins/woocommerce/tests/php/src/Internal/ProductFilters/QueryClausesTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/ProductFilters/QueryClausesTest.php
@@ -275,6 +275,7 @@ class QueryClausesTest extends AbstractProductFiltersTest {
* @testWith ["product_cat", ["cat-1"]]
* ["product_cat", ["cat-2"]]
* ["product_cat", ["cat-1", "cat-2"]]
+ * ["product_cat", ["cat-1", "not-exist-slug"]]
* ["product_tag", ["tag-1"]]
* ["product_tag", ["tag-2", "tag-3"]]
*
@@ -320,9 +321,9 @@ class QueryClausesTest extends AbstractProductFiltersTest {
}
/**
- * @testdox Taxonomy filtering ignores selected taxonomies with no matching term.
+ * @testdox Taxonomy filtering returns no products when a selected taxonomy has no matching terms.
*/
- public function test_taxonomy_clauses_ignore_taxonomies_without_matching_terms(): void {
+ public function test_taxonomy_clauses_fail_closed_when_a_taxonomy_has_no_matching_terms(): void {
$chosen_taxonomies = array(
'product_cat' => array( 'cat-1' ),
'product_tag' => array( 'not-exist-slug' ),
@@ -335,7 +336,26 @@ class QueryClausesTest extends AbstractProductFiltersTest {
$received_products = $this->get_data_from_products_array( wc_get_products( array() ) );
remove_filter( 'posts_clauses', $filter_callback );
- $this->assertEqualsCanonicalizing( array( 'Product 1', 'Product 4', 'Product 5', 'Product 6' ), $received_products );
+ $this->assertSame( array(), $received_products );
+ }
+
+ /**
+ * @testdox Taxonomy filtering ignores unknown terms when that taxonomy also has a matching term.
+ */
+ public function test_taxonomy_clauses_ignore_unknown_terms_in_a_matching_taxonomy(): void {
+ $chosen_taxonomies = array(
+ 'product_cat' => array( 'cat-1' ),
+ 'product_tag' => array( 'tag-1', 'not-exist-slug' ),
+ );
+ $filter_callback = function ( $args ) use ( $chosen_taxonomies ) {
+ return $this->sut->add_taxonomy_clauses( $args, $chosen_taxonomies );
+ };
+
+ add_filter( 'posts_clauses', $filter_callback );
+ $received_products = $this->get_data_from_products_array( wc_get_products( array() ) );
+ remove_filter( 'posts_clauses', $filter_callback );
+
+ $this->assertEqualsCanonicalizing( array( 'Product 1', 'Product 4' ), $received_products );
}
/**