-
- render_widget_edit_filter( $filter ); ?>
-
+ render_widget_edit_filter( $filter, false, false, $filter_index );
+ ++$filter_index;
+ endforeach;
+ ?>
Date: Tue, 14 Oct 2025 18:09:01 +0100
Subject: [PATCH 07/11] Cleanup
- Refactor class-search-widget.php to remove unnecessary PHP tags
- Update class-search-widget.php product_attribute case to move where 'count' attribute is added
- Refactor get_filters_from_widgets() to separate concerns
- Fix product_attribute case in class-classic-search.php to prevent slugs from being re-added to an array unnecessarily
---
projects/packages/search/src/class-helper.php | 77 ++++++++++---------
.../classic-search/class-classic-search.php | 18 +++--
.../src/widgets/class-search-widget.php | 67 ++++++++--------
3 files changed, 88 insertions(+), 74 deletions(-)
diff --git a/projects/packages/search/src/class-helper.php b/projects/packages/search/src/class-helper.php
index 262024e6d88b3..318c8d0d93bd1 100644
--- a/projects/packages/search/src/class-helper.php
+++ b/projects/packages/search/src/class-helper.php
@@ -185,31 +185,7 @@ public static function get_filters_from_widgets( $allowed_widget_ids = null ) {
// If this is a product_attribute filter with no specific attribute, expand it to all global attributes.
if ( 'product_attribute' === $type && empty( $widget_filter['attribute'] ) ) {
- if ( function_exists( 'wc_get_attribute_taxonomies' ) && function_exists( 'wc_attribute_taxonomy_name' ) ) {
- $product_attributes = wc_get_attribute_taxonomies(); // @phan-suppress-current-line PhanUndeclaredFunction We're checking for the existence of this function.
- $included_attributes = isset( $widget_filter['included_attributes'] ) ? (array) $widget_filter['included_attributes'] : array();
-
- // If no attributes are explicitly included, show all attributes (backward compatibility).
- // Also optimize by treating "all selected" the same as "none selected" to avoid O(n²) in_array() checks.
- $show_all = empty( $included_attributes ) || count( $included_attributes ) === count( $product_attributes );
-
- foreach ( $product_attributes as $attribute ) {
- $attribute_name = wc_attribute_taxonomy_name( $attribute->attribute_name ); // @phan-suppress-current-line PhanUndeclaredFunction We're checking for the existence of this function.
-
- // Only include attributes that are in the included_attributes list (or show all if none specified).
- if ( ! $show_all && ! in_array( $attribute_name, $included_attributes, true ) ) {
- continue;
- }
-
- $key = sprintf( '%s_%d', $type, count( $filters ) );
- $expanded_filter = $widget_filter;
- $expanded_filter['attribute'] = $attribute_name;
- $expanded_filter['name'] = $attribute->attribute_label;
- // Remove included_attributes from the expanded filter as it's no longer needed.
- unset( $expanded_filter['included_attributes'] );
- $filters[ $key ] = $expanded_filter;
- }
- }
+ $filters = self::expand_product_attribute_filters( $widget_filter, $filters );
} else {
$key = sprintf( '%s_%d', $type, count( $filters ) );
$filters[ $key ] = $widget_filter;
@@ -220,6 +196,45 @@ public static function get_filters_from_widgets( $allowed_widget_ids = null ) {
return $filters;
}
+ /**
+ * Expands a product_attribute filter into individual filters for each attribute.
+ *
+ * @since 5.8.0
+ *
+ * @param array $widget_filter The filter configuration.
+ * @param array $filters The existing filters array.
+ * @return array The filters array with expanded product attribute filters.
+ */
+ private static function expand_product_attribute_filters( $widget_filter, $filters ) {
+ if ( ! function_exists( 'wc_get_attribute_taxonomies' ) || ! function_exists( 'wc_attribute_taxonomy_name' ) ) {
+ return $filters;
+ }
+
+ $product_attributes = wc_get_attribute_taxonomies(); // @phan-suppress-current-line PhanUndeclaredFunction We're checking for the existence of this function.
+ $included_attributes = isset( $widget_filter['included_attributes'] ) ? (array) $widget_filter['included_attributes'] : array();
+
+ // If no attributes are explicitly included, show all attributes (backward compatibility).
+ // Also optimize by treating "all selected" the same as "none selected" to avoid O(n²) in_array() checks.
+ $show_all = empty( $included_attributes ) || count( $included_attributes ) === count( $product_attributes );
+
+ foreach ( $product_attributes as $attribute ) {
+ $attribute_name = wc_attribute_taxonomy_name( $attribute->attribute_name ); // @phan-suppress-current-line PhanUndeclaredFunction We're checking for the existence of this function.
+
+ if ( ! $show_all && ! in_array( $attribute_name, $included_attributes, true ) ) {
+ continue;
+ }
+
+ $key = sprintf( 'product_attribute_%d', count( $filters ) );
+ $expanded_filter = $widget_filter;
+ $expanded_filter['attribute'] = $attribute_name;
+ $expanded_filter['name'] = $attribute->attribute_label;
+ unset( $expanded_filter['included_attributes'] );
+ $filters[ $key ] = $expanded_filter;
+ }
+
+ return $filters;
+ }
+
/**
* Get the localized default label for a date filter.
*
@@ -313,17 +328,9 @@ public static function generate_widget_filter_name( $widget_filter ) {
break;
case 'product_attribute':
- if ( ! empty( $widget_filter['attribute'] ) ) {
- $attribute_taxonomy = get_taxonomy( $widget_filter['attribute'] );
- if ( $attribute_taxonomy && isset( $attribute_taxonomy->label ) ) {
- $name = $attribute_taxonomy->label;
- } else {
- $name = _x( 'Product Attributes', 'label for filtering posts', 'jetpack-search-pkg' );
- }
- } else {
- $name = _x( 'Product Attributes', 'label for filtering posts', 'jetpack-search-pkg' );
- }
+ $name = _x( 'Product Attributes', 'label for filtering posts', 'jetpack-search-pkg' );
break;
+
}
return $name;
diff --git a/projects/packages/search/src/classic-search/class-classic-search.php b/projects/packages/search/src/classic-search/class-classic-search.php
index 4f183e2991122..70af3539dfd9e 100644
--- a/projects/packages/search/src/classic-search/class-classic-search.php
+++ b/projects/packages/search/src/classic-search/class-classic-search.php
@@ -1639,16 +1639,19 @@ public function get_filters( ?WP_Query $query = null ) {
}
}
- $query_vars = array(
- $tax_query_var => implode( '+', array_merge( $existing_attribute_slugs, array( $attribute_term->slug ) ) ),
- );
-
$name = $attribute_term->name;
// Let's determine if this attribute is active or not.
- if ( in_array( $item['key'], $existing_attribute_slugs, true ) ) {
+ $is_active = in_array( $item['key'], $existing_attribute_slugs, true );
+
+ if ( $is_active ) {
$active = true;
+ // For active items, maintain the current state (don't redundantly add the slug again).
+ $query_vars = array(
+ $tax_query_var => implode( '+', $existing_attribute_slugs ),
+ );
+
$slug_count = count( $existing_attribute_slugs );
if ( $slug_count > 1 ) {
@@ -1659,6 +1662,11 @@ public function get_filters( ?WP_Query $query = null ) {
} else {
$remove_url = Helper::remove_query_arg( $tax_query_var );
}
+ } else {
+ // For inactive items, add this slug to the existing ones.
+ $query_vars = array(
+ $tax_query_var => implode( '+', array_merge( $existing_attribute_slugs, array( $attribute_term->slug ) ) ),
+ );
}
break;
diff --git a/projects/packages/search/src/widgets/class-search-widget.php b/projects/packages/search/src/widgets/class-search-widget.php
index 65f9323273238..b52b34c665406 100644
--- a/projects/packages/search/src/widgets/class-search-widget.php
+++ b/projects/packages/search/src/widgets/class-search-widget.php
@@ -702,17 +702,15 @@ public function update( $new_instance, $old_instance ) { // phpcs:ignore Variabl
break;
case 'product_attribute':
$filter_data = array(
- 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ),
- 'type' => 'product_attribute',
+ 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ),
+ 'type' => 'product_attribute',
+ 'count' => $count,
);
// Save included attributes if any are selected.
if ( isset( $new_instance[ 'included_attributes_' . $index ] ) && is_array( $new_instance[ 'included_attributes_' . $index ] ) ) {
$filter_data['included_attributes'] = array_map( 'sanitize_key', $new_instance[ 'included_attributes_' . $index ] );
}
- // For product attributes, we don't use the count field since we show all selected attributes.
- // But we still need it in the array for backward compatibility with other filter types.
- $filter_data['count'] = $count;
- $filters[] = $filter_data;
+ $filters[] = $filter_data;
break;
}
}
@@ -1101,36 +1099,37 @@ class="widefat"
From fcc02faac2ec2d24bfdb937da76f2e8289ab8683 Mon Sep 17 00:00:00 2001
From: Katja Paavola
Date: Tue, 14 Oct 2025 19:01:49 +0100
Subject: [PATCH 08/11] Replace eval() with proper WooCommerce mock file
- Create tests/php/woocommerce-mocks.php with mock functions
- Remove eval() calls from product attribute tests
- Mock functions defined in global namespace for proper testing
- Test expansion of generic product_attribute filters into specific attributes
- Test preservation of specific product_attribute filters (no expansion)
- Test included_attributes filtering to limit expansion
- Verify property inheritance (widget_id, count, name)
- Add helper methods for product attribute filter data providers
---
.../src/instant-search/lib/test/api.test.js | 92 ++++++++-
.../instant-search/lib/test/filters.test.js | 40 ++++
.../search/tests/php/Helpers_Test.php | 174 ++++++++++++++++++
.../search/tests/php/woocommerce-mocks.php | 42 +++++
4 files changed, 347 insertions(+), 1 deletion(-)
create mode 100644 projects/packages/search/tests/php/woocommerce-mocks.php
diff --git a/projects/packages/search/src/instant-search/lib/test/api.test.js b/projects/packages/search/src/instant-search/lib/test/api.test.js
index f50ae75b867c8..fa9ec02e0ba74 100644
--- a/projects/packages/search/src/instant-search/lib/test/api.test.js
+++ b/projects/packages/search/src/instant-search/lib/test/api.test.js
@@ -1,7 +1,97 @@
/**
* @jest-environment jsdom
*/
-import { generateDateRangeFilter, setDocumentCountsToZero } from '../api';
+import { buildFilterAggregations, generateDateRangeFilter, setDocumentCountsToZero } from '../api';
+
+describe( 'buildFilterAggregations', () => {
+ test( 'generates aggregations for product_attribute filters', () => {
+ const widgets = [
+ {
+ filters: [
+ {
+ type: 'product_attribute',
+ attribute: 'pa_color',
+ count: 10,
+ filter_id: 'product_attribute_color',
+ },
+ ],
+ },
+ ];
+ expect( buildFilterAggregations( widgets ) ).toEqual( {
+ product_attribute_color: {
+ terms: {
+ field: 'taxonomy.pa_color.slug_slash_name',
+ size: 10,
+ },
+ },
+ } );
+ } );
+
+ test( 'generates aggregations for multiple product_attribute filters', () => {
+ const widgets = [
+ {
+ filters: [
+ {
+ type: 'product_attribute',
+ attribute: 'pa_color',
+ count: 10,
+ filter_id: 'product_attribute_color',
+ },
+ {
+ type: 'product_attribute',
+ attribute: 'pa_size',
+ count: 5,
+ filter_id: 'product_attribute_size',
+ },
+ ],
+ },
+ ];
+ expect( buildFilterAggregations( widgets ) ).toEqual( {
+ product_attribute_color: {
+ terms: {
+ field: 'taxonomy.pa_color.slug_slash_name',
+ size: 10,
+ },
+ },
+ product_attribute_size: {
+ terms: {
+ field: 'taxonomy.pa_size.slug_slash_name',
+ size: 5,
+ },
+ },
+ } );
+ } );
+
+ test( 'generates aggregations for mixed filter types including product_attribute', () => {
+ const widgets = [
+ {
+ filters: [
+ {
+ type: 'taxonomy',
+ taxonomy: 'category',
+ count: 5,
+ filter_id: 'category_filter',
+ },
+ {
+ type: 'product_attribute',
+ attribute: 'pa_color',
+ count: 10,
+ filter_id: 'product_attribute_color',
+ },
+ ],
+ },
+ ];
+ const result = buildFilterAggregations( widgets );
+ expect( result ).toHaveProperty( 'category_filter' );
+ expect( result ).toHaveProperty( 'product_attribute_color' );
+ expect( result.product_attribute_color ).toEqual( {
+ terms: {
+ field: 'taxonomy.pa_color.slug_slash_name',
+ size: 10,
+ },
+ } );
+ } );
+} );
describe( 'generateDateRangeFilter', () => {
test( 'generates correct ranges for yearly date ranges', () => {
diff --git a/projects/packages/search/src/instant-search/lib/test/filters.test.js b/projects/packages/search/src/instant-search/lib/test/filters.test.js
index 8c2fe18fa90a5..05b5f1bc93373 100644
--- a/projects/packages/search/src/instant-search/lib/test/filters.test.js
+++ b/projects/packages/search/src/instant-search/lib/test/filters.test.js
@@ -44,6 +44,32 @@ describe( 'getFilterKeys', () => {
'subject',
] );
} );
+
+ test( 'includes product attributes from widget configurations without duplicates', () => {
+ const widgets = [
+ { filters: [ { type: 'product_attribute', attribute: 'pa_color' } ] },
+ { filters: [ { type: 'product_attribute', attribute: 'pa_size' } ] },
+ { filters: [ { type: 'product_attribute', attribute: 'pa_color' } ] },
+ ];
+ expect( getFilterKeys( widgets, [] ) ).toEqual( [
+ 'blog_ids',
+ 'authors',
+ 'post_types',
+ 'category',
+ 'post_format',
+ 'post_tag',
+ 'month_post_date',
+ 'month_post_date_gmt',
+ 'month_post_modified',
+ 'month_post_modified_gmt',
+ 'year_post_date',
+ 'year_post_date_gmt',
+ 'year_post_modified',
+ 'year_post_modified_gmt',
+ 'pa_color',
+ 'pa_size',
+ ] );
+ } );
} );
describe( 'getSelectableFilterKeys', () => {
@@ -174,4 +200,18 @@ describe( 'mapFilterKeyToFilter', () => {
taxonomy: 'arcade_reviews',
} );
} );
+ test( 'handles product attribute filter keys', () => {
+ expect( mapFilterKeyToFilter( 'pa_color' ) ).toEqual( {
+ type: 'product_attribute',
+ attribute: 'pa_color',
+ } );
+ expect( mapFilterKeyToFilter( 'pa_size' ) ).toEqual( {
+ type: 'product_attribute',
+ attribute: 'pa_size',
+ } );
+ expect( mapFilterKeyToFilter( 'pa_material' ) ).toEqual( {
+ type: 'product_attribute',
+ attribute: 'pa_material',
+ } );
+ } );
} );
diff --git a/projects/packages/search/tests/php/Helpers_Test.php b/projects/packages/search/tests/php/Helpers_Test.php
index 6c67a63040773..5f9014e83b503 100644
--- a/projects/packages/search/tests/php/Helpers_Test.php
+++ b/projects/packages/search/tests/php/Helpers_Test.php
@@ -13,6 +13,7 @@
require_once __DIR__ . '/class-test-helpers-customize.php';
require_once __DIR__ . '/class-test-helpers-query.php';
+require_once __DIR__ . '/woocommerce-mocks.php';
/**
* Helpers for Classic and Instant Search tests
@@ -1637,4 +1638,177 @@ public static function get_date_histogram_posts_modified_by_year_gmt_filter() {
'count' => 10,
);
}
+
+ /**
+ * Data provider for product attribute filter.
+ */
+ public static function get_product_attribute_filter() {
+ return array(
+ 'type' => 'product_attribute',
+ 'name' => 'Product Attributes',
+ 'count' => 10,
+ );
+ }
+
+ /**
+ * Data provider for product attribute filter with specific attribute.
+ */
+ public static function get_product_attribute_filter_with_attribute() {
+ return array(
+ 'type' => 'product_attribute',
+ 'name' => 'Color',
+ 'attribute' => 'pa_color',
+ 'count' => 10,
+ );
+ }
+
+ /**
+ * Test case for get_filters_from_widgets with product_attribute filters
+ */
+ public function test_get_filters_from_widgets_with_product_attributes() {
+ $raw_option = static::get_sample_widgets_option();
+ // Add a product_attribute filter without specific attribute (should expand).
+ $raw_option[22]['filters'][] = array(
+ 'type' => 'product_attribute',
+ 'name' => 'Product Attributes',
+ 'count' => 10,
+ );
+
+ // Add a product_attribute filter with specific attribute (should not expand).
+ $raw_option[22]['filters'][] = array(
+ 'type' => 'product_attribute',
+ 'name' => 'Color',
+ 'attribute' => 'pa_color',
+ 'count' => 5,
+ );
+
+ update_option( Helper::get_widget_option_name(), $raw_option );
+ $this->register_fake_widgets();
+
+ $filters = Helper::get_filters_from_widgets();
+
+ // Collect product_attribute filters.
+ $product_attributes = array_filter(
+ $filters,
+ function ( $filter ) {
+ return isset( $filter['type'] ) && $filter['type'] === 'product_attribute';
+ }
+ );
+
+ // Should have 4 product_attribute filters total (3 expanded + 1 specific)
+ $this->assertCount( 4, $product_attributes, 'Should have 4 product attribute filters' );
+
+ // Find specific attributes and verify their properties
+ $found_pa_color = 0;
+ $found_pa_size = 0;
+ $found_pa_material = 0;
+ $found_pa_color_count_5 = false;
+ $found_expanded_color = false;
+
+ foreach ( $product_attributes as $filter ) {
+ $this->assertArrayHasKey( 'attribute', $filter, 'Filter should have attribute key' );
+ $this->assertArrayHasKey( 'widget_id', $filter, 'Filter should have widget_id' );
+ $this->assertSame( 'jetpack-search-filters-22', $filter['widget_id'], 'widget_id should be inherited' );
+
+ if ( $filter['attribute'] === 'pa_color' ) {
+ ++$found_pa_color;
+ if ( isset( $filter['count'] ) && $filter['count'] === 5 ) {
+ $found_pa_color_count_5 = true;
+ // This is the specific filter, name should be preserved
+ $this->assertSame( 'Color', $filter['name'], 'Specific filter should preserve its name' );
+ } else {
+ // This is the expanded filter
+ $found_expanded_color = true;
+ $this->assertSame( 'Color', $filter['name'], 'Expanded filter should use attribute label' );
+ $this->assertSame( 10, $filter['count'], 'Expanded filter should inherit count from parent' );
+ }
+ }
+ if ( $filter['attribute'] === 'pa_size' ) {
+ ++$found_pa_size;
+ $this->assertSame( 'Size', $filter['name'], 'Expanded filter should use attribute label' );
+ $this->assertSame( 10, $filter['count'], 'Expanded filter should inherit count from parent' );
+ }
+ if ( $filter['attribute'] === 'pa_material' ) {
+ ++$found_pa_material;
+ $this->assertSame( 'Material', $filter['name'], 'Expanded filter should use attribute label' );
+ $this->assertSame( 10, $filter['count'], 'Expanded filter should inherit count from parent' );
+ }
+ }
+
+ $this->assertSame( 2, $found_pa_color, 'Should have 2 pa_color filters (1 expanded, 1 specific)' );
+ $this->assertSame( 1, $found_pa_size, 'Should have 1 pa_size filter (expanded)' );
+ $this->assertSame( 1, $found_pa_material, 'Should have 1 pa_material filter (expanded)' );
+ $this->assertTrue( $found_pa_color_count_5, 'Should have pa_color filter with count=5' );
+ $this->assertTrue( $found_expanded_color, 'Should have expanded pa_color filter with count=10' );
+ }
+
+ /**
+ * Test case for get_filters_from_widgets with product_attribute and included_attributes
+ */
+ public function test_get_filters_from_widgets_with_product_attributes_inclusion() {
+ // WooCommerce functions are already mocked in the previous test
+
+ $raw_option = static::get_sample_widgets_option();
+ // Add a product_attribute filter with specific included attributes.
+ $raw_option[22]['filters'][] = array(
+ 'type' => 'product_attribute',
+ 'name' => 'Product Attributes',
+ 'count' => 10,
+ 'included_attributes' => array( 'pa_color', 'pa_size' ),
+ );
+
+ update_option( Helper::get_widget_option_name(), $raw_option );
+ $this->register_fake_widgets();
+
+ $filters = Helper::get_filters_from_widgets();
+
+ // Collect product_attribute filters.
+ $product_attributes = array_filter(
+ $filters,
+ function ( $filter ) {
+ return isset( $filter['type'] ) && $filter['type'] === 'product_attribute';
+ }
+ );
+
+ // Should have 2 product_attribute filters (color and size from included_attributes)
+ $this->assertCount( 2, $product_attributes, 'Should have 2 product attribute filters' );
+
+ // Check that only included attributes are present and verify all properties
+ $found_pa_color = false;
+ $found_pa_size = false;
+ $found_pa_material = false;
+
+ foreach ( $product_attributes as $filter ) {
+ // Verify required keys exist
+ $this->assertArrayHasKey( 'attribute', $filter, 'Filter should have attribute key' );
+ $this->assertArrayHasKey( 'widget_id', $filter, 'Filter should have widget_id' );
+ $this->assertArrayHasKey( 'count', $filter, 'Filter should have count' );
+ $this->assertArrayHasKey( 'name', $filter, 'Filter should have name' );
+
+ // Verify inherited properties
+ $this->assertSame( 'jetpack-search-filters-22', $filter['widget_id'], 'widget_id should be inherited' );
+ $this->assertSame( 10, $filter['count'], 'count should be inherited from parent filter' );
+
+ // Verify included_attributes was removed from expanded filters
+ $this->assertArrayNotHasKey( 'included_attributes', $filter, 'included_attributes should be removed from expanded filters' );
+
+ // Track which attributes were found
+ if ( $filter['attribute'] === 'pa_color' ) {
+ $found_pa_color = true;
+ $this->assertSame( 'Color', $filter['name'], 'pa_color filter should use attribute label as name' );
+ }
+ if ( $filter['attribute'] === 'pa_size' ) {
+ $found_pa_size = true;
+ $this->assertSame( 'Size', $filter['name'], 'pa_size filter should use attribute label as name' );
+ }
+ if ( $filter['attribute'] === 'pa_material' ) {
+ $found_pa_material = true;
+ }
+ }
+
+ // Verify the inclusion filtering worked correctly
+ $this->assertTrue( $found_pa_color, 'Should have pa_color attribute (was in included_attributes)' );
+ $this->assertTrue( $found_pa_size, 'Should have pa_size attribute (was in included_attributes)' );
+ $this->assertFalse( $found_pa_material, 'Should NOT have pa_material attribute (was NOT in included_attributes)' );
+ }
}
diff --git a/projects/packages/search/tests/php/woocommerce-mocks.php b/projects/packages/search/tests/php/woocommerce-mocks.php
new file mode 100644
index 0000000000000..c1e3da6829f76
--- /dev/null
+++ b/projects/packages/search/tests/php/woocommerce-mocks.php
@@ -0,0 +1,42 @@
+ 'color',
+ 'attribute_label' => 'Color',
+ ),
+ (object) array(
+ 'attribute_name' => 'size',
+ 'attribute_label' => 'Size',
+ ),
+ (object) array(
+ 'attribute_name' => 'material',
+ 'attribute_label' => 'Material',
+ ),
+ );
+ }
+}
+
+if ( ! function_exists( 'wc_attribute_taxonomy_name' ) ) {
+ /**
+ * Mock WooCommerce function to get taxonomy name from attribute name.
+ *
+ * @param string $attribute_name The attribute name.
+ * @return string The taxonomy name with 'pa_' prefix.
+ */
+ function wc_attribute_taxonomy_name( $attribute_name ) {
+ return 'pa_' . $attribute_name;
+ }
+}
From e1b7fd7a60fe4edc885772af75b085d4ae9ac46e Mon Sep 17 00:00:00 2001
From: Katja Paavola
Date: Tue, 14 Oct 2025 19:20:38 +0100
Subject: [PATCH 09/11] Remove PHAN exclusion as no longer necessary given
mocks added for tests
---
projects/packages/search/src/class-helper.php | 4 ++--
.../search/src/classic-search/class-classic-search.php | 4 ++--
projects/packages/search/src/widgets/class-search-widget.php | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/projects/packages/search/src/class-helper.php b/projects/packages/search/src/class-helper.php
index 318c8d0d93bd1..c199a1ea8861a 100644
--- a/projects/packages/search/src/class-helper.php
+++ b/projects/packages/search/src/class-helper.php
@@ -210,7 +210,7 @@ private static function expand_product_attribute_filters( $widget_filter, $filte
return $filters;
}
- $product_attributes = wc_get_attribute_taxonomies(); // @phan-suppress-current-line PhanUndeclaredFunction We're checking for the existence of this function.
+ $product_attributes = wc_get_attribute_taxonomies();
$included_attributes = isset( $widget_filter['included_attributes'] ) ? (array) $widget_filter['included_attributes'] : array();
// If no attributes are explicitly included, show all attributes (backward compatibility).
@@ -218,7 +218,7 @@ private static function expand_product_attribute_filters( $widget_filter, $filte
$show_all = empty( $included_attributes ) || count( $included_attributes ) === count( $product_attributes );
foreach ( $product_attributes as $attribute ) {
- $attribute_name = wc_attribute_taxonomy_name( $attribute->attribute_name ); // @phan-suppress-current-line PhanUndeclaredFunction We're checking for the existence of this function.
+ $attribute_name = wc_attribute_taxonomy_name( $attribute->attribute_name );
if ( ! $show_all && ! in_array( $attribute_name, $included_attributes, true ) ) {
continue;
diff --git a/projects/packages/search/src/classic-search/class-classic-search.php b/projects/packages/search/src/classic-search/class-classic-search.php
index 70af3539dfd9e..ee307621afd71 100644
--- a/projects/packages/search/src/classic-search/class-classic-search.php
+++ b/projects/packages/search/src/classic-search/class-classic-search.php
@@ -1366,14 +1366,14 @@ public function add_product_attribute_aggregation_to_es_query_builder( array $ag
return;
}
- $product_attributes = wc_get_attribute_taxonomies(); // @phan-suppress-current-line PhanUndeclaredFunction We're checking for the existence of this function.
+ $product_attributes = wc_get_attribute_taxonomies();
if ( empty( $product_attributes ) ) {
return;
}
foreach ( $product_attributes as $attribute ) {
- $attribute_name = wc_attribute_taxonomy_name( $attribute->attribute_name ); // @phan-suppress-current-line PhanUndeclaredFunction We're checking for the existence of this function.
+ $attribute_name = wc_attribute_taxonomy_name( $attribute->attribute_name );
$agg_label = $label . '_' . $attribute_name;
$this->build_product_attribute_agg( $attribute_name, $aggregation['count'], $agg_label, $builder );
diff --git a/projects/packages/search/src/widgets/class-search-widget.php b/projects/packages/search/src/widgets/class-search-widget.php
index b52b34c665406..0fc93d3e6479d 100644
--- a/projects/packages/search/src/widgets/class-search-widget.php
+++ b/projects/packages/search/src/widgets/class-search-widget.php
@@ -1101,7 +1101,7 @@ class="widefat"
attribute_name ); // @phan-suppress-current-line PhanUndeclaredFunction
+ $attribute_name = wc_attribute_taxonomy_name( $attribute->attribute_name );
$is_included = in_array( $attribute_name, $included_attributes, true );
?>
From edb5c66a5d01de3cd43fdab9e58473e796a26763 Mon Sep 17 00:00:00 2001
From: Katja Paavola
Date: Wed, 22 Oct 2025 17:15:57 +0100
Subject: [PATCH 11/11] Update comments to keep PHAN happy
---
.../src/widgets/class-search-widget.php | 29 ++++++++++---------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/projects/packages/search/src/widgets/class-search-widget.php b/projects/packages/search/src/widgets/class-search-widget.php
index 621f499684604..148e3d371c78f 100644
--- a/projects/packages/search/src/widgets/class-search-widget.php
+++ b/projects/packages/search/src/widgets/class-search-widget.php
@@ -700,18 +700,21 @@ public function update( $new_instance, $old_instance ) { // phpcs:ignore Variabl
'interval' => sanitize_key( $new_instance['date_histogram_interval'][ $index ] ),
);
break;
- case 'product_attribute':
- $filter_data = array(
- 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ),
- 'type' => 'product_attribute',
- 'count' => $count,
- );
- // Save included attributes if any are selected.
- if ( isset( $new_instance[ 'included_attributes_' . $index ] ) && is_array( $new_instance[ 'included_attributes_' . $index ] ) ) {
- $filter_data['included_attributes'] = array_map( 'sanitize_key', $new_instance[ 'included_attributes_' . $index ] );
- }
- $filters[] = $filter_data;
- break;
+ // phpcs:disable Squiz.PHP.CommentedOutCode.Found
+ // TODO: Uncomment when Search rebuild is complete (search for: product_attribute filter).
+ // case 'product_attribute':
+ // $filter_data = array(
+ // 'name' => sanitize_text_field( $new_instance['filter_name'][ $index ] ),
+ // 'type' => 'product_attribute',
+ // 'count' => $count,
+ // );
+ // Save included attributes if any are selected.
+ // if ( isset( $new_instance[ 'included_attributes_' . $index ] ) && is_array( $new_instance[ 'included_attributes_' . $index ] ) ) {
+ // $filter_data['included_attributes'] = array_map( 'sanitize_key', $new_instance[ 'included_attributes_' . $index ] );
+ // }
+ // $filters[] = $filter_data;
+ // break.
+ // phpcs:enable Squiz.PHP.CommentedOutCode.Found
}
}
}
@@ -1017,7 +1020,7 @@ public function render_widget_edit_filter( $filter, $is_template = false, $is_in
-