Commit 7f1b9ec77a7 for woocommerce
commit 7f1b9ec77a7333e5bc2d6c80ed9629d6012b3a62
Author: malinajirka <malinajirka@gmail.com>
Date: Thu Jul 23 13:45:04 2026 +0200
Fix is_rest_api_request() missing ?rest_route= REST requests (#66816)
* Detect rest_route query-string REST requests in is_rest_api_request()
is_rest_api_request() only matched the pretty-permalink form of REST
requests (/wp-json/...), so the equally valid ?rest_route=/... form
(plain permalinks, Jetpack-signed requests) was wrongly treated as a
non-REST request. Check the rest_route query parameter as well,
mirroring the approach already used by is_store_api_request().
* Add unit tests for rest_route detection in is_rest_api_request()
* Add changelog entry
* Explain why core REST detection functions cannot replace is_rest_api_request()
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/fix-wooplug-7135-rest-route-detection b/plugins/woocommerce/changelog/fix-wooplug-7135-rest-route-detection
new file mode 100644
index 00000000000..c4b36f22253
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-wooplug-7135-rest-route-detection
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Detect REST API requests made via the ?rest_route= query parameter (plain permalinks, Jetpack-signed requests) in is_rest_api_request().
diff --git a/plugins/woocommerce/includes/class-woocommerce.php b/plugins/woocommerce/includes/class-woocommerce.php
index a7bed480c95..3ca44822882 100644
--- a/plugins/woocommerce/includes/class-woocommerce.php
+++ b/plugins/woocommerce/includes/class-woocommerce.php
@@ -612,7 +612,12 @@ final class WooCommerce {
*
* Legacy REST requests should still run some extra code for backwards compatibility.
*
- * @todo: replace this function once core WP function is available: https://core.trac.wordpress.org/ticket/42061.
+ * This method cannot be replaced with core's wp_is_serving_rest_request(): that function reads the
+ * REST_REQUEST constant, which is only defined once rest_api_loaded() runs on parse_request — long
+ * after this method is first called during plugin bootstrap (e.g. to decide whether to load the
+ * frontend includes). Sniffing the request URI is the only signal available that early. Code that
+ * runs after parse_request should prefer wp_is_serving_rest_request(), or wp_is_rest_endpoint(),
+ * which also covers internal REST requests dispatched during a regular page load.
*
* @return bool
*/
@@ -621,8 +626,13 @@ final class WooCommerce {
return false;
}
+ // Pretty permalinks: the REST prefix is part of the path, e.g. /wp-json/wc/v3/products.
+ // Plain permalinks: the route is passed as a query parameter instead, e.g. ?rest_route=/wc/v3/products
+ // (also used by Jetpack-signed REST requests regardless of the permalink structure).
+ // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Recommended
$rest_prefix = trailingslashit( rest_get_url_prefix() );
- $is_rest_api_request = ( false !== strpos( $_SERVER['REQUEST_URI'], $rest_prefix ) ); // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ $is_rest_api_request = ( false !== strpos( $_SERVER['REQUEST_URI'], $rest_prefix ) ) || ! empty( $_GET['rest_route'] );
+ // phpcs:enable
/**
* Whether this is a REST API request.
diff --git a/plugins/woocommerce/tests/php/includes/class-woocommerce-test.php b/plugins/woocommerce/tests/php/includes/class-woocommerce-test.php
index 236b03c5ab0..b77c9a1de94 100644
--- a/plugins/woocommerce/tests/php/includes/class-woocommerce-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-woocommerce-test.php
@@ -73,6 +73,26 @@ class WooCommerce_Test extends \WC_Unit_Test_Case {
$this->assertEquals( WC()->is_rest_api_request(), true );
}
+ /**
+ * @testdox Should detect a REST API request that uses plain permalinks (?rest_route=).
+ */
+ public function test_is_rest_api_request_returns_true_for_plain_permalinks(): void {
+ $_SERVER['REQUEST_URI'] = '/index.php?rest_route=/wc/v3/products';
+ $_GET['rest_route'] = '/wc/v3/products';
+
+ $this->assertTrue( WC()->is_rest_api_request(), 'A ?rest_route= request should be detected as a REST API request.' );
+ }
+
+ /**
+ * @testdox Should not detect a request with an empty rest_route parameter as a REST API request.
+ */
+ public function test_is_rest_api_request_returns_false_for_empty_rest_route(): void {
+ $_SERVER['REQUEST_URI'] = '/index.php?rest_route=';
+ $_GET['rest_route'] = '';
+
+ $this->assertFalse( WC()->is_rest_api_request(), 'An empty rest_route parameter should not be detected as a REST API request.' );
+ }
+
/**
* Restore the request globals after each test.
*/