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 );
+	}
+}