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