Commit 73fc5621528 for woocommerce
commit 73fc5621528c09c9f1d6ec6945f63aa2fce3325a
Author: Karol Manijak <20098064+kmanijak@users.noreply.github.com>
Date: Mon Aug 31 15:23:10 2026 +0200
Restore plain-text product search responses (#68186)
* Restore plain-text product search responses
* Add changelog for product search response fix
* Decode product names before stripping tags
diff --git a/plugins/woocommerce/changelog/fix-plain-text-product-search-responses b/plugins/woocommerce/changelog/fix-plain-text-product-search-responses
new file mode 100644
index 00000000000..857a2964838
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-plain-text-product-search-responses
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Restore plain-text product names in AJAX search responses.
diff --git a/plugins/woocommerce/includes/class-wc-ajax.php b/plugins/woocommerce/includes/class-wc-ajax.php
index b76180fabfe..f9c73389b87 100644
--- a/plugins/woocommerce/includes/class-wc-ajax.php
+++ b/plugins/woocommerce/includes/class-wc-ajax.php
@@ -2137,7 +2137,7 @@ class WC_AJAX {
}
}//end if
- $products[ $product_object->get_id() ] = esc_html( wp_strip_all_tags( $formatted_name ) );
+ $products[ $product_object->get_id() ] = wp_strip_all_tags( rawurldecode( $formatted_name ) );
}
wp_send_json( apply_filters( 'woocommerce_json_search_found_products', $products ) );
@@ -2188,7 +2188,7 @@ class WC_AJAX {
$products = array();
foreach ( $product_objects as $product_object ) {
- $products[ $product_object->get_id() ] = esc_html( wp_strip_all_tags( $product_object->get_formatted_name() ) );
+ $products[ $product_object->get_id() ] = wp_strip_all_tags( rawurldecode( $product_object->get_formatted_name() ) );
}
wp_send_json( $products );
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php b/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php
index 2cf59e79be7..705255dc4c1 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php
@@ -757,6 +757,52 @@ class WC_AJAX_Test extends \WP_Ajax_UnitTestCase {
$this->assertEquals( 45, $order->get_total() );
}
+ /**
+ * @testdox Product search decodes URL-encoded characters before returning plain text names.
+ * @dataProvider product_search_name_provider
+ *
+ * @param string $search_term Product search term.
+ * @param string $product_name Product name.
+ * @param string $expected_result_name Expected product name in the response.
+ */
+ public function test_json_search_products_returns_plain_text_names( string $search_term, string $product_name, string $expected_result_name ): void {
+ $this->_setRole( 'administrator' );
+
+ $product = WC_Helper_Product::create_simple_product();
+ $product->set_name( $product_name );
+ $product->save();
+
+ $_GET['term'] = $search_term;
+ $_GET['include'] = array( $product->get_id() );
+ $_GET['security'] = wp_create_nonce( 'search-products' );
+
+ try {
+ $response = $this->do_ajax( 'woocommerce_json_search_products' );
+ } finally {
+ unset( $_GET['term'], $_GET['include'], $_GET['security'] );
+ }
+
+ $this->assertSame(
+ sprintf( '%s (%s)', $expected_result_name, $product->get_sku() ),
+ $response[ $product->get_id() ],
+ 'Product search should return a stripped, plain text product name.'
+ );
+ }
+
+ /**
+ * Product names used to verify AJAX search response formatting.
+ *
+ * @return array<string, array<string>>
+ */
+ public function product_search_name_provider(): array {
+ return array(
+ 'plain punctuation' => array( 'Ben', "Ben & Jerry's", "Ben & Jerry's" ),
+ 'URL-encoded space' => array( 'Coffee', 'Coffee%20Mug', 'Coffee Mug' ),
+ 'URL-encoded HTML tag' => array( 'Text', 'Text %3Cspan%3Einside%3C/span%3E', 'Text inside' ),
+ 'HTML tag' => array( 'Text', 'Text <span>inside</span>', 'Text inside' ),
+ );
+ }
+
/**
* Describe JSON search, particularly as it relates to handling searches for users in a
* multisite context (it should generally not be possible to retrieve information about