Commit 2f4c23919b4 for woocommerce
commit 2f4c23919b480ea80888a750dd0d93a3d73013d4
Author: Tung Du <dinhtungdu@gmail.com>
Date: Mon Apr 6 11:00:57 2026 +0700
Fix fatal error on shop page when Product Filters block references deleted attribute (#63982)
* Fix fatal error when Product Filters block references a deleted attribute taxonomy
When a product attribute taxonomy is deleted from Products → Attributes,
the Product Filters block still references it and `wc_get_attribute()`
returns null, causing a fatal error (HTTP 500) on shop/archive pages.
Add a null check after `wc_get_attribute()` to return empty string when
the attribute no longer exists, so the block gracefully skips rendering
instead of crashing.
Fixes #63791
Co-Authored-By: Bhavik Kalpesh <53536925+bhavz-10@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/fix-product-filter-deleted-attribute-fatal b/plugins/woocommerce/changelog/fix-product-filter-deleted-attribute-fatal
new file mode 100644
index 00000000000..d0505ab04bf
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-product-filter-deleted-attribute-fatal
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix fatal error on shop page when a product attribute taxonomy used in Product Filters block is deleted.
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 5510c4505be..c60b25eaf38 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -53733,17 +53733,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/ProductFilterAttribute.php
- -
- message: '#^Cannot access property \$name on stdClass\|null\.$#'
- identifier: property.nonObject
- count: 2
- path: src/Blocks/BlockTypes/ProductFilterAttribute.php
-
- -
- message: '#^Cannot access property \$slug on stdClass\|null\.$#'
- identifier: property.nonObject
- count: 5
- path: src/Blocks/BlockTypes/ProductFilterAttribute.php
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilterAttribute\:\:delete_default_attribute_id_transient\(\) has no return type specified\.$#'
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterAttribute.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterAttribute.php
index 3e65a320d54..c11e4dcb6b5 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterAttribute.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterAttribute.php
@@ -152,10 +152,15 @@ final class ProductFilterAttribute extends AbstractBlock {
}
$product_attribute = wc_get_attribute( $block_attributes['attributeId'] );
- $attribute_counts = $this->get_attribute_counts( $block, $product_attribute->slug, $block_attributes['queryType'] );
- $hide_empty = $block_attributes['hideEmpty'] ?? true;
- $orderby = $block_attributes['sortOrder'] ? explode( '-', $block_attributes['sortOrder'] )[0] : 'name';
- $order = $block_attributes['sortOrder'] ? strtoupper( explode( '-', $block_attributes['sortOrder'] )[1] ) : 'DESC';
+
+ if ( ! $product_attribute ) {
+ return '';
+ }
+
+ $attribute_counts = $this->get_attribute_counts( $block, $product_attribute->slug, $block_attributes['queryType'] );
+ $hide_empty = $block_attributes['hideEmpty'] ?? true;
+ $orderby = $block_attributes['sortOrder'] ? explode( '-', $block_attributes['sortOrder'] )[0] : 'name';
+ $order = $block_attributes['sortOrder'] ? strtoupper( explode( '-', $block_attributes['sortOrder'] )[1] ) : 'DESC';
$args = array(
'taxonomy' => $product_attribute->slug,
diff --git a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductFilterAttributeTest.php b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductFilterAttributeTest.php
new file mode 100644
index 00000000000..385f17e6072
--- /dev/null
+++ b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductFilterAttributeTest.php
@@ -0,0 +1,31 @@
+<?php
+declare( strict_types = 1 );
+
+namespace Automattic\WooCommerce\Tests\Blocks\BlockTypes;
+
+/**
+ * Tests for the ProductFilterAttribute block type.
+ */
+class ProductFilterAttributeTest extends \WP_UnitTestCase {
+
+ /**
+ * Test that rendering returns empty string when the attribute ID references a deleted taxonomy.
+ *
+ * Regression test for https://github.com/woocommerce/woocommerce/issues/63791
+ */
+ public function test_render_returns_empty_for_deleted_attribute() {
+ $non_existent_attribute_id = 999999;
+
+ $block_markup = sprintf(
+ '<!-- wp:woocommerce/product-filter-attribute {"attributeId":%d,"queryType":"or","sortOrder":"name-asc"} -->
+ <div class="wp-block-woocommerce-product-filter-attribute"></div>
+ <!-- /wp:woocommerce/product-filter-attribute -->',
+ $non_existent_attribute_id
+ );
+
+ $blocks = parse_blocks( $block_markup );
+ $output = render_block( $blocks[0] );
+
+ $this->assertSame( '', $output );
+ }
+}