Commit 5449ce65a3c for woocommerce
commit 5449ce65a3cedf6025156891ee67e5985878aa94
Author: Thomas Roberts <5656702+opr@users.noreply.github.com>
Date: Tue Oct 20 15:30:08 2026 +0100
Reject invalid Store API product price filters (#69998)
* Fix Store API price filter validation
* Add changelog entry for Store API price filter validation
* Fix empty Store API price filters
diff --git a/plugins/woocommerce/changelog/fix-store-api-price-filter-validation b/plugins/woocommerce/changelog/fix-store-api-price-filter-validation
new file mode 100644
index 00000000000..481d1b1055d
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-store-api-price-filter-validation
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Reject invalid minimum and maximum price filters instead of returning a server error.
diff --git a/plugins/woocommerce/src/StoreApi/Routes/V1/Products.php b/plugins/woocommerce/src/StoreApi/Routes/V1/Products.php
index 91fad8b3d7e..d20201f72bb 100644
--- a/plugins/woocommerce/src/StoreApi/Routes/V1/Products.php
+++ b/plugins/woocommerce/src/StoreApi/Routes/V1/Products.php
@@ -350,6 +350,7 @@ class Products extends AbstractRoute {
$params['min_price'] = array(
'description' => __( 'Limit result set to products based on a minimum price, provided using the smallest unit of the currency.', 'woocommerce' ),
'type' => 'string',
+ 'pattern' => '^[0-9]*$',
'sanitize_callback' => 'sanitize_text_field',
'validate_callback' => 'rest_validate_request_arg',
);
@@ -357,6 +358,7 @@ class Products extends AbstractRoute {
$params['max_price'] = array(
'description' => __( 'Limit result set to products based on a maximum price, provided using the smallest unit of the currency.', 'woocommerce' ),
'type' => 'string',
+ 'pattern' => '^[0-9]*$',
'sanitize_callback' => 'sanitize_text_field',
'validate_callback' => 'rest_validate_request_arg',
);
diff --git a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Products.php b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Products.php
index 9b073a566cc..98393fcfe7c 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Products.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Products.php
@@ -214,6 +214,39 @@ class Products extends ControllerTestCase {
$this->assertEquals( 'search-for-this-value', $data[0]['sku'] );
}
+ /**
+ * @testdox Should return a bad request response for invalid price filter values.
+ * @testWith ["min_price", "true"]
+ * ["max_price", "10.99"]
+ * ["min_price", "-1"]
+ *
+ * @param string $param Price filter parameter.
+ * @param string $value Price filter value.
+ */
+ public function test_rejects_invalid_price_filter_values( string $param, string $value ): void {
+ $request = new \WP_REST_Request( 'GET', '/wc/store/v1/products' );
+ $request->set_param( $param, $value );
+
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 400, $response->get_status(), 'Invalid price filters should return HTTP 400.' );
+ $this->assertSame( 'rest_invalid_param', $data['code'], 'The response should identify an invalid request parameter.' );
+ }
+
+ /**
+ * @testdox Should allow empty price filter values used by product filter blocks.
+ */
+ public function test_allows_empty_price_filter_values(): void {
+ $request = new \WP_REST_Request( 'GET', '/wc/store/v1/products' );
+ $request->set_param( 'min_price', '' );
+ $request->set_param( 'max_price', '' );
+
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertSame( 200, $response->get_status(), 'Empty price filters should be ignored.' );
+ }
+
/**
* Test conversion of product to rest response.
*/