Commit 5df7da7bf37 for woocommerce
commit 5df7da7bf37cd505b41f63ed85ebc062f08d975a
Author: Ali Raza <ali@alirazasolutions.com>
Date: Thu Oct 22 09:04:12 2026 +0500
Expose empty state on Product Filters wrapper (#69858)
* Expose Product Filters empty state
* refactor: collect filter empty states as boolean lists
Amp-Thread-ID: https://ampcode.com/threads/T-01a152f8-07da-73cc-8ed8-a97556a3a680
---------
Co-authored-by: Tung Du <dinhtungdu@gmail.com>
Co-authored-by: Amp <amp@ampcode.com>
diff --git a/plugins/woocommerce/changelog/product-filters-empty-state b/plugins/woocommerce/changelog/product-filters-empty-state
new file mode 100644
index 00000000000..5e160abeed2
--- /dev/null
+++ b/plugins/woocommerce/changelog/product-filters-empty-state
@@ -0,0 +1,4 @@
+Significance: patch
+Type: enhancement
+
+Expose an empty-state class when all Product Filters have no options.
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/block.json
index c2d55ca310f..ecf844fe1ee 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/active-filters/block.json
@@ -33,6 +33,6 @@
}
}
},
- "usesContext": [ "activeFilters" ],
+ "usesContext": [ "activeFilters", "productFiltersKey" ],
"viewScriptModule": "woocommerce/product-filter-active"
}
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/block.json
index d319e4e041a..f47cfdf2176 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/attribute-filter/block.json
@@ -53,7 +53,7 @@
}
}
},
- "usesContext": [ "query", "filterParams" ],
+ "usesContext": [ "query", "filterParams", "productFiltersKey" ],
"attributes": {
"attributeId": {
"type": "number",
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/block.json
index 90018500cc6..1852f94d674 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/price-filter/block.json
@@ -12,6 +12,6 @@
"interactivity": true,
"html": false
},
- "usesContext": [ "query", "filterParams" ],
+ "usesContext": [ "query", "filterParams", "productFiltersKey" ],
"viewScriptModule": "woocommerce/product-filter-price"
}
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/block.json
index a7732b69be1..303c990803d 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/rating-filter/block.json
@@ -12,7 +12,7 @@
}
},
"ancestor": [ "woocommerce/product-filters" ],
- "usesContext": [ "query", "filterParams" ],
+ "usesContext": [ "query", "filterParams", "productFiltersKey" ],
"attributes": {
"className": {
"type": "string",
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/status-filter/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/status-filter/block.json
index bbd621d79a5..975c7ec1daa 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/status-filter/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/status-filter/block.json
@@ -71,7 +71,7 @@
"default": true
}
},
- "usesContext": [ "query", "filterParams" ],
+ "usesContext": [ "query", "filterParams", "productFiltersKey" ],
"example": {
"attributes": {
"isPreview": true
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/taxonomy-filter/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/taxonomy-filter/block.json
index 773a611913f..c9fb404d605 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/taxonomy-filter/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-filters/inner-blocks/taxonomy-filter/block.json
@@ -53,7 +53,7 @@
}
}
},
- "usesContext": [ "query", "filterParams" ],
+ "usesContext": [ "query", "filterParams", "productFiltersKey" ],
"attributes": {
"taxonomy": {
"type": "string",
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index dbd35c83077..3351be5a359 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -50361,12 +50361,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductCollection/NoResults.php
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\NoResults\:\:render\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductCollection/NoResults.php
-
-
message: '#^Call to function is_array\(\) with array\<array\<int\>\> will always evaluate to true\.$#'
identifier: function.alreadyNarrowedType
@@ -50493,12 +50487,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductCollection/Renderer.php
- -
- message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block\.$#'
- identifier: class.notFound
- count: 6
- path: src/Blocks/BlockTypes/ProductCollection/Utils.php
-
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\Utils\:\:prepare_and_execute_query\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -50511,12 +50499,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductCollection/Utils.php
- -
- message: '#^Parameter \#1 \$block of function build_query_vars_from_query_block expects WP_Block, Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block given\.$#'
- identifier: argument.type
- count: 2
- path: src/Blocks/BlockTypes/ProductCollection/Utils.php
-
-
message: '#^Parameter \#1 \$object_or_string of function is_a expects object, WP_Post\|WP_Post_Type\|WP_Term\|WP_User\|null given\.$#'
identifier: argument.type
@@ -50529,18 +50511,6 @@ parameters:
count: 2
path: src/Blocks/BlockTypes/ProductCollection/Utils.php
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\Utils\:\:get_query_vars\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductCollection/Utils.php
-
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\Utils\:\:prepare_and_execute_query\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductCollection/Utils.php
-
-
message: '#^Property WooCommerce\:\:\$cart \(WC_Cart\) in isset\(\) is not nullable\.$#'
identifier: isset.property
@@ -50601,30 +50571,12 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductDetails.php
- -
- message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterActive.php
-
- -
- message: '#^Access to property \$parsed_block on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterActive.php
-
-
message: '#^Parameter \#1 \$extra_attributes of function get_block_wrapper_attributes expects array\<string, string\>, array\<string, string\|false\> given\.$#'
identifier: argument.type
count: 1
path: src/Blocks/BlockTypes/ProductFilterActive.php
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterActive\:\:render\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterActive.php
-
-
message: '#^Access to an undefined property object\:\:\$attribute_id\.$#'
identifier: property.notFound
@@ -50637,18 +50589,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterAttribute.php
- -
- message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 2
- path: src/Blocks/BlockTypes/ProductFilterAttribute.php
-
- -
- message: '#^Access to property \$parsed_block on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterAttribute.php
-
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterAttribute\:\:delete_default_attribute_id_transient\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -50685,12 +50625,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterAttribute.php
- -
- message: '#^Parameter \#1 \$block of static method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\Utils\:\:get_query_vars\(\) expects Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block, Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block given\.$#'
- identifier: argument.type
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterAttribute.php
-
-
message: '#^Parameter \#1 \$extra_attributes of function get_block_wrapper_attributes expects array\<string, string\>, array\<string, bool\|string\> given\.$#'
identifier: argument.type
@@ -50703,18 +50637,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterAttribute.php
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterAttribute\:\:get_attribute_counts\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterAttribute.php
-
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterAttribute\:\:render\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterAttribute.php
-
-
message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
identifier: class.notFound
@@ -50763,18 +50685,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterClearButton.php
- -
- message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 2
- path: src/Blocks/BlockTypes/ProductFilterPrice.php
-
- -
- message: '#^Access to property \$parsed_block on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 2
- path: src/Blocks/BlockTypes/ProductFilterPrice.php
-
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterPrice\:\:get_filtered_price\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -50787,12 +50697,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterPrice.php
- -
- message: '#^Parameter \#1 \$block of static method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\Utils\:\:get_query_vars\(\) expects Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block, Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block given\.$#'
- identifier: argument.type
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterPrice.php
-
-
message: '#^Parameter \#1 \$extra_attributes of function get_block_wrapper_attributes expects array\<string, string\>, array\<string, bool\|string\> given\.$#'
identifier: argument.type
@@ -50805,18 +50709,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterPrice.php
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterPrice\:\:get_filtered_price\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterPrice.php
-
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterPrice\:\:render\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterPrice.php
-
-
message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
identifier: class.notFound
@@ -50841,18 +50733,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterPriceSlider.php
- -
- message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 2
- path: src/Blocks/BlockTypes/ProductFilterRating.php
-
- -
- message: '#^Access to property \$parsed_block on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterRating.php
-
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterRating\:\:get_rating_counts\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -50865,12 +50745,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterRating.php
- -
- message: '#^Parameter \#1 \$block of static method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\Utils\:\:get_query_vars\(\) expects Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block, Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block given\.$#'
- identifier: argument.type
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterRating.php
-
-
message: '#^Parameter \#1 \$extra_attributes of function get_block_wrapper_attributes expects array\<string, string\>, array\<string, bool\|string\> given\.$#'
identifier: argument.type
@@ -50883,18 +50757,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterRating.php
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterRating\:\:get_rating_counts\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterRating.php
-
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterRating\:\:render\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterRating.php
-
-
message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
identifier: class.notFound
@@ -50925,18 +50787,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterRemovableChips.php
- -
- message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 2
- path: src/Blocks/BlockTypes/ProductFilterStatus.php
-
- -
- message: '#^Access to property \$parsed_block on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterStatus.php
-
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterStatus\:\:enqueue_data\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -50955,42 +50805,12 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterStatus.php
- -
- message: '#^Parameter \#1 \$block of static method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\Utils\:\:get_query_vars\(\) expects Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block, Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block given\.$#'
- identifier: argument.type
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterStatus.php
-
-
message: '#^Parameter \#1 \$extra_attributes of function get_block_wrapper_attributes expects array\<string, string\>, array\<string, bool\|string\> given\.$#'
identifier: argument.type
count: 1
path: src/Blocks/BlockTypes/ProductFilterStatus.php
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterStatus\:\:get_stock_status_counts\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterStatus.php
-
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterStatus\:\:render\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterStatus.php
-
- -
- message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 2
- path: src/Blocks/BlockTypes/ProductFilterTaxonomy.php
-
- -
- message: '#^Access to property \$parsed_block on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterTaxonomy.php
-
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterTaxonomy\:\:enqueue_data\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -51021,30 +50841,12 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterTaxonomy.php
- -
- message: '#^Parameter \#1 \$block of static method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\Utils\:\:get_query_vars\(\) expects Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block, Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block given\.$#'
- identifier: argument.type
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterTaxonomy.php
-
-
message: '#^Parameter \#1 \$extra_attributes of function get_block_wrapper_attributes expects array\<string, string\>, array\<string, bool\|string\> given\.$#'
identifier: argument.type
count: 1
path: src/Blocks/BlockTypes/ProductFilterTaxonomy.php
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterTaxonomy\:\:get_taxonomy_term_counts\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterTaxonomy.php
-
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterTaxonomy\:\:render\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/ProductFilterTaxonomy.php
-
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilters\:\:enqueue_data\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -51639,12 +51441,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductTemplate.php
- -
- message: '#^Parameter \#1 \$block of static method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\Utils\:\:prepare_and_execute_query\(\) expects Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductCollection\\WP_Block, WP_Block given\.$#'
- identifier: argument.type
- count: 1
- path: src/Blocks/BlockTypes/ProductTemplate.php
-
-
message: '#^Parameter \#1 \$inner_blocks of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductTemplate\:\:block_core_post_template_uses_featured_image\(\) expects Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block_List, WP_Block_List given\.$#'
identifier: argument.type
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/NoResults.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/NoResults.php
index c1b2e0927b7..0b0b7d76bd7 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/NoResults.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/NoResults.php
@@ -5,6 +5,7 @@ namespace Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection;
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
+use WP_Block;
/**
* NoResults class.
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/Utils.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/Utils.php
index f49ec22683c..c954a9f30a2 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/Utils.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/Utils.php
@@ -3,6 +3,7 @@ declare(strict_types=1);
namespace Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection;
+use WP_Block;
use WP_Query;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Utilities\ArrayUtil;
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterActive.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterActive.php
index de18788a701..96e0ec2d8b8 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterActive.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterActive.php
@@ -4,6 +4,8 @@ declare( strict_types = 1 );
namespace Automattic\WooCommerce\Blocks\BlockTypes;
+use WP_Block;
+
/**
* Product Filter: Active Block.
*/
@@ -66,6 +68,14 @@ final class ProductFilterActive extends AbstractBlock {
'storeNamespace' => 'woocommerce/product-filters',
);
+ $is_empty = empty( $removable_items );
+ $product_filters_key = $block->context['productFiltersKey'] ?? '';
+ if ( is_string( $product_filters_key ) && '' !== $product_filters_key ) {
+ $state = wp_interactivity_state( 'woocommerce/product-filters' );
+ $state['filterEmptyStates'][ $product_filters_key ][] = $is_empty;
+ wp_interactivity_state( 'woocommerce/product-filters', $state );
+ }
+
$wrapper_attributes = array(
'data-wp-interactive' => 'woocommerce/product-filters',
'data-wp-key' => wp_unique_prefixed_id( $this->get_full_block_name() ),
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterAttribute.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterAttribute.php
index 24f68a915dc..068c018c6d5 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterAttribute.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterAttribute.php
@@ -7,6 +7,7 @@ use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductC
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermMeta;
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
+use WP_Block;
/**
* Product Filter: Attribute Block.
@@ -250,7 +251,15 @@ final class ProductFilterAttribute extends AbstractBlock {
),
);
- if ( empty( $filter_context['items'] ) ) {
+ $is_empty = empty( $filter_context['items'] );
+ $product_filters_key = $block->context['productFiltersKey'] ?? '';
+ if ( is_string( $product_filters_key ) && '' !== $product_filters_key ) {
+ $state = wp_interactivity_state( 'woocommerce/product-filters' );
+ $state['filterEmptyStates'][ $product_filters_key ][] = $is_empty;
+ wp_interactivity_state( 'woocommerce/product-filters', $state );
+ }
+
+ if ( $is_empty ) {
$wrapper_attributes['hidden'] = true;
$wrapper_attributes['class'] = 'wc-block-product-filter--hidden';
}
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPrice.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPrice.php
index 7b31811cef7..df01e0220df 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPrice.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPrice.php
@@ -7,6 +7,7 @@ namespace Automattic\WooCommerce\Blocks\BlockTypes;
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
+use WP_Block;
/**
* Product Filter: Price Block.
@@ -155,7 +156,15 @@ final class ProductFilterPrice extends AbstractBlock {
)
);
- if ( $min_range === $max_range || ! $max_range ) {
+ $is_empty = $min_range === $max_range || ! $max_range;
+ $product_filters_key = $block->context['productFiltersKey'] ?? '';
+ if ( is_string( $product_filters_key ) && '' !== $product_filters_key ) {
+ $state = wp_interactivity_state( 'woocommerce/product-filters' );
+ $state['filterEmptyStates'][ $product_filters_key ][] = $is_empty;
+ wp_interactivity_state( 'woocommerce/product-filters', $state );
+ }
+
+ if ( $is_empty ) {
$wrapper_attributes['hidden'] = true;
$wrapper_attributes['class'] = 'wc-block-product-filter--hidden';
return sprintf(
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterRating.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterRating.php
index aeebec806dc..2971b16fb91 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterRating.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterRating.php
@@ -7,6 +7,7 @@ namespace Automattic\WooCommerce\Blocks\BlockTypes;
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
+use WP_Block;
/**
* Product Filter: Rating Block
@@ -151,7 +152,15 @@ final class ProductFilterRating extends AbstractBlock {
),
);
- if ( empty( $filter_options ) ) {
+ $is_empty = empty( $filter_options );
+ $product_filters_key = $block->context['productFiltersKey'] ?? '';
+ if ( is_string( $product_filters_key ) && '' !== $product_filters_key ) {
+ $state = wp_interactivity_state( 'woocommerce/product-filters' );
+ $state['filterEmptyStates'][ $product_filters_key ][] = $is_empty;
+ wp_interactivity_state( 'woocommerce/product-filters', $state );
+ }
+
+ if ( $is_empty ) {
$wrapper_attributes['hidden'] = true;
$wrapper_attributes['class'] = 'wc-block-product-filter--hidden';
}
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterStatus.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterStatus.php
index 5c9861b44fa..57bcb0d4b2d 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterStatus.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterStatus.php
@@ -5,6 +5,7 @@ namespace Automattic\WooCommerce\Blocks\BlockTypes;
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
+use WP_Block;
/**
* Product Filter: Status Block.
@@ -151,7 +152,15 @@ final class ProductFilterStatus extends AbstractBlock {
),
);
- if ( empty( $filter_options ) ) {
+ $is_empty = empty( $filter_options );
+ $product_filters_key = $block->context['productFiltersKey'] ?? '';
+ if ( is_string( $product_filters_key ) && '' !== $product_filters_key ) {
+ $state = wp_interactivity_state( 'woocommerce/product-filters' );
+ $state['filterEmptyStates'][ $product_filters_key ][] = $is_empty;
+ wp_interactivity_state( 'woocommerce/product-filters', $state );
+ }
+
+ if ( $is_empty ) {
$wrapper_attributes['hidden'] = true;
$wrapper_attributes['class'] = 'wc-block-product-filter--hidden';
}
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterTaxonomy.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterTaxonomy.php
index 9db3982fdd0..df9e6d4dcde 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterTaxonomy.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterTaxonomy.php
@@ -7,6 +7,7 @@ use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductC
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
use Automattic\WooCommerce\Internal\ProductFilters\TaxonomyHierarchyData;
+use WP_Block;
/**
* Product Filter: Taxonomy Block.
@@ -292,7 +293,15 @@ final class ProductFilterTaxonomy extends AbstractBlock {
),
);
- if ( empty( $filter_context['items'] ) ) {
+ $is_empty = empty( $filter_context['items'] );
+ $product_filters_key = $block->context['productFiltersKey'] ?? '';
+ if ( is_string( $product_filters_key ) && '' !== $product_filters_key ) {
+ $state = wp_interactivity_state( 'woocommerce/product-filters' );
+ $state['filterEmptyStates'][ $product_filters_key ][] = $is_empty;
+ wp_interactivity_state( 'woocommerce/product-filters', $state );
+ }
+
+ if ( $is_empty ) {
$wrapper_attributes['hidden'] = true;
$wrapper_attributes['class'] = 'wc-block-product-filter--hidden';
}
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilters.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilters.php
index c654546ea19..cdaf3e120b0 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilters.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilters.php
@@ -195,11 +195,14 @@ CSS;
}
);
+ $navigation_id = $this->generate_navigation_id( $block );
+ $product_filters_key = wp_unique_prefixed_id( $navigation_id . '-' );
$block_context = array_merge(
$block->context,
array(
- 'filterParams' => $filter_params,
- 'activeFilters' => $active_filters,
+ 'filterParams' => $filter_params,
+ 'activeFilters' => $active_filters,
+ 'productFiltersKey' => $product_filters_key,
),
);
$inner_blocks = array_reduce(
@@ -221,7 +224,13 @@ CSS;
$overlay_mode = $this->get_overlay_mode( $attributes );
$has_overlay = 'off' !== $overlay_mode;
$overlay_position = isset( $attributes['overlayPosition'] ) && 'right' === $attributes['overlayPosition'] ? 'right' : 'left';
- $wrapper_classes = array( 'wc-block-product-filters' );
+
+ $state = wp_interactivity_state( 'woocommerce/product-filters' );
+ $filter_empty_states = $state['filterEmptyStates'][ $product_filters_key ] ?? array();
+ $wrapper_classes = array( 'wc-block-product-filters' );
+ if ( ! empty( $filter_empty_states ) && ! in_array( false, $filter_empty_states, true ) ) {
+ $wrapper_classes[] = 'wc-block-product-filters--empty';
+ }
if ( ! $has_overlay ) {
$wrapper_classes[] = 'is-filter-drawer-disabled';
}
@@ -234,7 +243,7 @@ CSS;
$wrapper_attributes = array(
'class' => implode( ' ', $wrapper_classes ),
- 'data-wp-router-region' => $this->generate_navigation_id( $block ),
+ 'data-wp-router-region' => $navigation_id,
'data-wp-interactive' => $this->get_full_block_name(),
'data-wp-init---colors' => 'callbacks.initColors',
'data-wp-watch---active-filters' => 'callbacks.syncActiveFiltersWithServer',
diff --git a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductFilters.php b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductFilters.php
index 8bef33692aa..80973557b17 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductFilters.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductFilters.php
@@ -15,6 +15,11 @@ use Automattic\WooCommerce\Tests\Blocks\Mocks\AssetDataRegistryMock;
*/
class ProductFilters extends \WP_UnitTestCase {
+ /**
+ * Test-only filter block name.
+ */
+ private const TEST_FILTER_BLOCK = 'woocommerce/test-product-filter-empty-state';
+
/**
* Instance of the Product Filters block under test.
*
@@ -36,6 +41,13 @@ class ProductFilters extends \WP_UnitTestCase {
*/
private $canonical_method;
+ /**
+ * Reflection method used to invoke the protected render method.
+ *
+ * @var \ReflectionMethod
+ */
+ private $render_method;
+
/**
* Set up the test subject and dependencies.
*
@@ -58,6 +70,33 @@ class ProductFilters extends \WP_UnitTestCase {
$this->canonical_method = new \ReflectionMethod( ProductFiltersBlock::class, 'get_canonical_url_no_pagination' );
$this->canonical_method->setAccessible( true );
+
+ $this->render_method = new \ReflectionMethod( ProductFiltersBlock::class, 'render' );
+ $this->render_method->setAccessible( true );
+
+ register_block_type(
+ self::TEST_FILTER_BLOCK,
+ array(
+ 'api_version' => 3,
+ 'uses_context' => array( 'productFiltersKey' ),
+ 'attributes' => array(
+ 'empty' => array(
+ 'type' => 'boolean',
+ 'default' => true,
+ ),
+ ),
+ 'render_callback' => static function ( $attributes, $content, $block ) {
+ $product_filters_key = $block->context['productFiltersKey'] ?? '';
+ if ( is_string( $product_filters_key ) && '' !== $product_filters_key ) {
+ $state = wp_interactivity_state( 'woocommerce/product-filters' );
+ $state['filterEmptyStates'][ $product_filters_key ][] = (bool) $attributes['empty'];
+ wp_interactivity_state( 'woocommerce/product-filters', $state );
+ }
+
+ return '<div class="test-product-filter"></div>';
+ },
+ )
+ );
}
/**
@@ -71,6 +110,11 @@ class ProductFilters extends \WP_UnitTestCase {
}
$this->registered_filters = [];
+
+ if ( \WP_Block_Type_Registry::get_instance()->is_registered( self::TEST_FILTER_BLOCK ) ) {
+ unregister_block_type( self::TEST_FILTER_BLOCK );
+ }
+
parent::tearDown();
}
@@ -103,6 +147,98 @@ class ProductFilters extends \WP_UnitTestCase {
return (string) $this->canonical_method->invoke( $this->product_filters, $filter_params );
}
+ /**
+ * Render Product Filters with test filter states.
+ *
+ * @param bool[] $empty_states Empty-state value for each test filter.
+ * @return string Rendered Product Filters markup.
+ */
+ private function render_with_filter_states( array $empty_states ): string {
+ $inner_blocks = array_map(
+ static function ( $is_empty ) {
+ return array(
+ 'blockName' => self::TEST_FILTER_BLOCK,
+ 'attrs' => array( 'empty' => $is_empty ),
+ 'innerBlocks' => array(),
+ 'innerHTML' => '',
+ 'innerContent' => array(),
+ );
+ },
+ $empty_states
+ );
+
+ $parsed_block = array(
+ 'blockName' => 'woocommerce/product-filters',
+ 'attrs' => array(),
+ 'innerBlocks' => $inner_blocks,
+ 'innerHTML' => '',
+ 'innerContent' => array(),
+ );
+ $block = new \WP_Block( $parsed_block, array() );
+
+ return (string) $this->render_method->invoke( $this->product_filters, array(), '', $block );
+ }
+
+ /**
+ * @testdox All participating filters being empty marks the wrapper as empty.
+ *
+ * @return void
+ */
+ public function test_wrapper_has_empty_class_when_all_filters_are_empty(): void {
+ $output = $this->render_with_filter_states( array( true, true ) );
+
+ $this->assertStringContainsString( 'wc-block-product-filters--empty', $output );
+ }
+
+ /**
+ * @testdox One visible filter keeps the wrapper out of the empty state in either order.
+ *
+ * @param bool[] $empty_states Empty-state value for each test filter.
+ * @return void
+ *
+ * @testWith [[true, false]]
+ * [[false, true]]
+ */
+ public function test_wrapper_has_no_empty_class_when_one_filter_has_options( array $empty_states ): void {
+ $output = $this->render_with_filter_states( $empty_states );
+
+ $this->assertStringNotContainsString( 'wc-block-product-filters--empty', $output );
+ }
+
+ /**
+ * @testdox Empty state is scoped independently for identical and different Product Filters wrappers.
+ *
+ * @return void
+ */
+ public function test_empty_state_is_scoped_per_wrapper(): void {
+ $previous_states = wp_interactivity_state( 'woocommerce/product-filters' )['filterEmptyStates'] ?? array();
+ $empty_output = $this->render_with_filter_states( array( true ) );
+ $duplicate_empty_output = $this->render_with_filter_states( array( true ) );
+ $visible_output = $this->render_with_filter_states( array( false ) );
+
+ $this->assertStringContainsString( 'wc-block-product-filters--empty', $empty_output );
+ $this->assertStringContainsString( 'wc-block-product-filters--empty', $duplicate_empty_output );
+ $this->assertStringNotContainsString( 'wc-block-product-filters--empty', $visible_output );
+
+ $current_states = wp_interactivity_state( 'woocommerce/product-filters' )['filterEmptyStates'];
+ $wrapper_states = array_diff_key( $current_states, $previous_states );
+ $this->assertCount( 3, $wrapper_states );
+ foreach ( $wrapper_states as $empty_states ) {
+ $this->assertCount( 1, $empty_states );
+ }
+ }
+
+ /**
+ * @testdox A wrapper with no participating filters is not marked empty.
+ *
+ * @return void
+ */
+ public function test_wrapper_without_participating_filters_is_not_empty(): void {
+ $output = $this->render_with_filter_states( array() );
+
+ $this->assertStringNotContainsString( 'wc-block-product-filters--empty', $output );
+ }
+
/**
* Ensures get_pagenum_link filters receive the expected argument types.
*