Commit 9491ed4ce8 for wordpress.org
commit 9491ed4ce874163f4034affb2a388b0c7f16a4c2
Author: westonruter <westonruter@git.wordpress.org>
Date: Mon Oct 19 17:40:58 2026 +0000
Code Quality: Narrow types for REST requests and responses.
Adds array shapes and narrowed types to `WP_HTTP_Response`, `WP_REST_Request` and `WP_REST_Response`, and to the parts of `WP_REST_Server` that pass data to them, reusing the route handler and endpoint argument aliases the server already defines. Several existing types were wrong rather than merely loose, and are corrected:
* A request's body is null until one is set.
* A request's JSON params decode to a scalar for a JSON body that is not an object or array.
* A request's headers hold lists of values.
* A file param may describe a failed upload, or a field named with brackets such as `files[]`.
The status code is typed `int<100, 599>`, and `absint()` gains a template conditional return so that an argument already known to be a non-negative integer keeps its narrower type through it. The one call where that type cannot be inferred, in the deprecated numeric branch of `wp_get_recent_posts()`, is added to the PHPStan baseline. The no-cache check for a 4xx response to a method-overridden request now compares the status numerically instead of passing an integer to `str_starts_with()`, which removes another baseline entry, and a test now covers that path.
The narrower types also expose existing bugs that are left for follow-up: a scalar JSON body makes `WP_REST_Request::set_param()` fatal and `WP_REST_Request::sanitize_params()` warn, and uploading to the media endpoint with a `file[]` field makes `WP_REST_Attachments_Controller::create_item()` throw a `TypeError`.
Developed in https://github.com/WordPress/wordpress-develop/pull/14471.
Follow-up to r34928, r56834, r57126, r62618, r63646, r63756.
Props westonruter, apermo.
See #65817.
Built from https://develop.svn.wordpress.org/trunk@64527
git-svn-id: http://core.svn.wordpress.org/trunk@63677 1a063a9b-81f0-0310-95a4-ce76da25c4cd
diff --git a/wp-includes/class-wp-http-response.php b/wp-includes/class-wp-http-response.php
index d102877885..d9d8d871c4 100644
--- a/wp-includes/class-wp-http-response.php
+++ b/wp-includes/class-wp-http-response.php
@@ -27,7 +27,7 @@ class WP_HTTP_Response {
* Response headers.
*
* @since 4.4.0
- * @var array
+ * @var array<string, string>
*/
public $headers;
@@ -36,6 +36,7 @@ class WP_HTTP_Response {
*
* @since 4.4.0
* @var int
+ * @phpstan-var int<100, 599>
*/
public $status;
@@ -44,9 +45,11 @@ class WP_HTTP_Response {
*
* @since 4.4.0
*
- * @param mixed $data Response data. Default null.
- * @param int $status Optional. HTTP status code. Default 200.
- * @param array $headers Optional. HTTP header map. Default empty array.
+ * @param mixed $data Response data. Default null.
+ * @param int $status Optional. HTTP status code. Default 200.
+ * @param array<string, string> $headers Optional. HTTP header map. Default empty array.
+ *
+ * @phpstan-param int<100, 599> $status
*/
public function __construct( $data = null, $status = 200, $headers = array() ) {
$this->set_data( $data );
@@ -59,7 +62,7 @@ class WP_HTTP_Response {
*
* @since 4.4.0
*
- * @return array Map of header name to header value.
+ * @return array<string, string> Map of header name to header value.
*/
public function get_headers() {
return $this->headers;
@@ -70,7 +73,7 @@ class WP_HTTP_Response {
*
* @since 4.4.0
*
- * @param array $headers Map of header name to header value.
+ * @param array<string, string> $headers Map of header name to header value.
*/
public function set_headers( $headers ) {
$this->headers = $headers;
@@ -100,6 +103,8 @@ class WP_HTTP_Response {
* @since 4.4.0
*
* @return int The 3-digit HTTP status code.
+ *
+ * @phpstan-return int<100, 599>
*/
public function get_status() {
return $this->status;
@@ -111,6 +116,8 @@ class WP_HTTP_Response {
* @since 4.4.0
*
* @param int $code HTTP status.
+ *
+ * @phpstan-param int<100, 599> $code
*/
public function set_status( $code ) {
$this->status = absint( $code );
diff --git a/wp-includes/load.php b/wp-includes/load.php
index f736afb5b6..ecd4220e5a 100644
--- a/wp-includes/load.php
+++ b/wp-includes/load.php
@@ -1538,7 +1538,10 @@ function is_multisite() {
*
* @param mixed $maybeint Data you wish to have converted to a non-negative integer.
* @return int A non-negative integer.
- * @phpstan-return non-negative-int
+ *
+ * @phpstan-template T
+ * @phpstan-param T $maybeint
+ * @phpstan-return (T is non-negative-int ? T : non-negative-int)
*/
function absint( $maybeint ): int {
if ( is_float( $maybeint ) ) {
diff --git a/wp-includes/rest-api/class-wp-rest-request.php b/wp-includes/rest-api/class-wp-rest-request.php
index 6e2619afeb..7773a40aaf 100644
--- a/wp-includes/rest-api/class-wp-rest-request.php
+++ b/wp-includes/rest-api/class-wp-rest-request.php
@@ -25,6 +25,54 @@
* @since 4.4.0
*
* @link https://www.php.net/manual/en/class.arrayaccess.php
+ *
+ * @phpstan-import-type Endpoint_Arg from WP_REST_Server
+ *
+ * @phpstan-type Attributes array{
+ * methods?: array<uppercase-string, true>,
+ * callback?: callable|null,
+ * permission_callback?: callable|null,
+ * validate_callback?: callable|null,
+ * args?: array<non-empty-string, Endpoint_Arg>,
+ * accept_json?: bool,
+ * accept_raw?: bool,
+ * show_in_index?: bool,
+ * allow_batch?: array{v1?: bool}|false,
+ * ...
+ * }
+ * @phpstan-type File_Param array{
+ * name: non-empty-string,
+ * type: string,
+ * size: non-negative-int,
+ * tmp_name: non-empty-string,
+ * error: 0,
+ * full_path?: non-empty-string,
+ * }|array{
+ * name: string,
+ * type: string,
+ * size: non-negative-int,
+ * tmp_name: string,
+ * error: int<1, 8>,
+ * full_path?: string,
+ * }|array{
+ * name: array<mixed>,
+ * type: array<mixed>,
+ * size: array<mixed>,
+ * tmp_name: array<mixed>,
+ * error: array<mixed>,
+ * full_path?: array<mixed>,
+ * }
+ * @phpstan-type Parameter_Type 'URL'|'GET'|'POST'|'FILES'|'JSON'|'defaults'
+ * @phpstan-type Params array{
+ * URL: array<string, mixed>,
+ * GET: array<mixed>,
+ * POST: array<mixed>,
+ * FILES: array<string, File_Param>,
+ * JSON: array<mixed>|string|int|float|bool|null,
+ * defaults: array<string, mixed>,
+ * }
+ *
+ * @phpstan-implements ArrayAccess<string, mixed>
*/
#[AllowDynamicProperties]
class WP_REST_Request implements ArrayAccess {
@@ -34,6 +82,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
* @var string
+ * @phpstan-var uppercase-string
*/
protected $method = '';
@@ -44,7 +93,8 @@ class WP_REST_Request implements ArrayAccess {
* superglobals when being created from the global scope.
*
* @since 4.4.0
- * @var array Contains GET, POST and FILES keys mapping to arrays of data.
+ * @var array<string, mixed> Contains GET, POST and FILES keys mapping to arrays of data.
+ * @phpstan-var Params
*/
protected $params;
@@ -52,7 +102,8 @@ class WP_REST_Request implements ArrayAccess {
* HTTP headers for the request.
*
* @since 4.4.0
- * @var array Map of key to value. Key is always lowercase, as per HTTP specification.
+ * @var array<string, string[]> Map of key to list of values. Key is always lowercase, as per HTTP specification.
+ * @phpstan-var array<lowercase-string, string[]>
*/
protected $headers = array();
@@ -60,7 +111,7 @@ class WP_REST_Request implements ArrayAccess {
* Body data.
*
* @since 4.4.0
- * @var string Binary data from the request.
+ * @var string|null Binary data from the request, or null if no body has been set.
*/
protected $body = null;
@@ -79,7 +130,8 @@ class WP_REST_Request implements ArrayAccess {
* containing the callback as well as the valid methods for the route.
*
* @since 4.4.0
- * @var array Attributes for the request.
+ * @var array<string, mixed> Attributes for the request.
+ * @phpstan-var Attributes
*/
protected $attributes = array();
@@ -106,9 +158,11 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param string $method Optional. Request method. Default empty.
- * @param string $route Optional. Request route. Default empty.
- * @param array $attributes Optional. Request attributes. Default empty array.
+ * @param string $method Optional. Request method. Default empty.
+ * @param string $route Optional. Request route. Default empty.
+ * @param array<string, mixed> $attributes Optional. Request attributes. Default empty array.
+ *
+ * @phpstan-param Attributes $attributes
*/
public function __construct( $method = '', $route = '', $attributes = array() ) {
$this->params = array(
@@ -134,6 +188,8 @@ class WP_REST_Request implements ArrayAccess {
* @since 4.4.0
*
* @return string HTTP method.
+ *
+ * @phpstan-return uppercase-string
*/
public function get_method() {
return $this->method;
@@ -155,7 +211,9 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array Map of key to value. Key is always lowercase, as per HTTP specification.
+ * @return array<string, string[]> Map of key to list of values. Key is always lowercase, as per HTTP specification.
+ *
+ * @phpstan-return array<lowercase-string, string[]>
*/
public function get_headers() {
return $this->headers;
@@ -190,6 +248,8 @@ class WP_REST_Request implements ArrayAccess {
*
* @param string $key Header name.
* @return string Canonicalized name.
+ *
+ * @phpstan-return lowercase-string
*/
public static function canonicalize_header_name( $key ) {
$key = strtolower( $key );
@@ -226,7 +286,7 @@ class WP_REST_Request implements ArrayAccess {
* @since 4.4.0
*
* @param string $key Header name, will be canonicalized to lowercase.
- * @return array|null List of string values if set, null otherwise.
+ * @return string[]|null List of string values if set, null otherwise.
*/
public function get_header_as_array( $key ) {
$key = static::canonicalize_header_name( $key );
@@ -243,8 +303,8 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param string $key Header name.
- * @param string $value Header value, or list of values.
+ * @param string $key Header name.
+ * @param string|string[] $value Header value, or list of values.
*/
public function set_header( $key, $value ) {
$key = static::canonicalize_header_name( $key );
@@ -258,8 +318,8 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param string $key Header name.
- * @param string $value Header value, or list of values.
+ * @param string $key Header name.
+ * @param string|string[] $value Header value, or list of values.
*/
public function add_header( $key, $value ) {
$key = static::canonicalize_header_name( $key );
@@ -289,8 +349,8 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param array $headers Map of header name to value.
- * @param bool $override If true, replace the request's headers. Otherwise, merge with existing.
+ * @param array<string, string|string[]> $headers Map of header name to value, or list of values.
+ * @param bool $override If true, replace the request's headers. Otherwise, merge with existing.
*/
public function set_headers( $headers, $override = true ) {
if ( true === $override ) {
@@ -307,9 +367,16 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array|null Map containing 'value' and 'parameters' keys
- * or null when no valid Content-Type header was
- * available.
+ * @return array|null {
+ * The parsed Content-Type header, or null when no valid Content-Type
+ * header was available.
+ *
+ * @type string $value Media type, lowercased, such as `application/json`.
+ * @type string $type Top-level type, such as `application`.
+ * @type string $subtype Subtype, such as `json`.
+ * @type string $parameters Parameters following the media type, such as
+ * `charset=UTF-8`. Empty string if none.
+ * }
*/
public function get_content_type() {
$value = $this->get_header( 'Content-Type' );
@@ -357,6 +424,8 @@ class WP_REST_Request implements ArrayAccess {
* @since 4.4.0
*
* @return string[] Array of types to check, in order of priority.
+ *
+ * @phpstan-return list<Parameter_Type>
*/
protected function get_parameter_order() {
$order = array();
@@ -393,6 +462,8 @@ class WP_REST_Request implements ArrayAccess {
*
* @param string[] $order Array of types to check, in order of priority.
* @param WP_REST_Request $request The request object.
+ *
+ * @phpstan-param list<Parameter_Type> $order
*/
return apply_filters( 'rest_request_parameter_order', $order, $this );
}
@@ -477,7 +548,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array Map of key to value.
+ * @return array<mixed> Map of key to value.
*/
public function get_params() {
$order = $this->get_parameter_order();
@@ -509,7 +580,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array Parameter map of key to value.
+ * @return array<string, mixed> Parameter map of key to value.
*/
public function get_url_params() {
return $this->params['URL'];
@@ -522,7 +593,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param array $params Parameter map of key to value.
+ * @param array<string, mixed> $params Parameter map of key to value.
*/
public function set_url_params( $params ) {
$this->params['URL'] = $params;
@@ -535,7 +606,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array Parameter map of key to value.
+ * @return array<mixed> Parameter map of key to value.
*/
public function get_query_params() {
return $this->params['GET'];
@@ -548,7 +619,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param array $params Parameter map of key to value.
+ * @param array<mixed> $params Parameter map of key to value.
*/
public function set_query_params( $params ) {
$this->params['GET'] = $params;
@@ -561,7 +632,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array Parameter map of key to value.
+ * @return array<mixed> Parameter map of key to value.
*/
public function get_body_params() {
return $this->params['POST'];
@@ -574,7 +645,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param array $params Parameter map of key to value.
+ * @param array<mixed> $params Parameter map of key to value.
*/
public function set_body_params( $params ) {
$this->params['POST'] = $params;
@@ -587,16 +658,9 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array Parameter map of key to value.
+ * @return array<string, array<string, mixed>> Parameter map of key to value.
*
- * @phpstan-return array<string, array{
- * name: non-empty-string,
- * type: non-empty-string,
- * size: non-negative-int,
- * tmp_name: non-empty-string,
- * error: int<0, 8>,
- * full_path?: non-empty-string,
- * }>
+ * @phpstan-return array<string, File_Param>
*/
public function get_file_params() {
return $this->params['FILES'];
@@ -609,16 +673,9 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param array $params Parameter map of key to value.
+ * @param array<string, array<string, mixed>> $params Parameter map of key to value.
*
- * @phpstan-param array<string, array{
- * name: non-empty-string,
- * type: non-empty-string,
- * size: non-negative-int,
- * tmp_name: non-empty-string,
- * error: int<0, 8>,
- * full_path?: non-empty-string,
- * }> $params
+ * @phpstan-param array<string, File_Param> $params
*/
public function set_file_params( $params ) {
$this->params['FILES'] = $params;
@@ -631,7 +688,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array Parameter map of key to value.
+ * @return array<string, mixed> Parameter map of key to value.
*/
public function get_default_params() {
return $this->params['defaults'];
@@ -644,7 +701,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param array $params Parameter map of key to value.
+ * @param array<string, mixed> $params Parameter map of key to value.
*/
public function set_default_params( $params ) {
$this->params['defaults'] = $params;
@@ -655,7 +712,7 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return string Binary data from the request body.
+ * @return string|null Binary data from the request body, or null if no body has been set.
*/
public function get_body() {
return $this->body;
@@ -682,7 +739,9 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array Parameter map of key to value.
+ * @return array<mixed>|string|int|float|bool|null Parameter map of key to value, or null if the request
+ * has no valid JSON body. A JSON body that is not an
+ * object or array decodes to the scalar it contains.
*/
public function get_json_params() {
// Ensure the parameters have been parsed out.
@@ -803,7 +862,9 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @return array Attributes for the request.
+ * @return array<string, mixed> Attributes for the request.
+ *
+ * @phpstan-return Attributes
*/
public function get_attributes() {
return $this->attributes;
@@ -814,7 +875,9 @@ class WP_REST_Request implements ArrayAccess {
*
* @since 4.4.0
*
- * @param array $attributes Attributes for the request.
+ * @param array<string, mixed> $attributes Attributes for the request.
+ *
+ * @phpstan-param Attributes $attributes
*/
public function set_attributes( $attributes ) {
$this->attributes = $attributes;
diff --git a/wp-includes/rest-api/class-wp-rest-response.php b/wp-includes/rest-api/class-wp-rest-response.php
index ddb1fb27f4..7624e01d61 100644
--- a/wp-includes/rest-api/class-wp-rest-response.php
+++ b/wp-includes/rest-api/class-wp-rest-response.php
@@ -13,6 +13,33 @@
* @since 4.4.0
*
* @see WP_HTTP_Response
+ *
+ * @phpstan-import-type Route_Handler from WP_REST_Server
+ *
+ * @phpstan-type Target_Hints array{
+ * allow?: list<uppercase-string>,
+ * ...<lowercase-string, mixed>
+ * }
+ * @phpstan-type Link_Attributes array{
+ * embeddable?: bool,
+ * targetHints?: Target_Hints,
+ * ...<string, mixed>
+ * }
+ * @phpstan-type Link array{
+ * href: non-falsy-string,
+ * attributes: Link_Attributes,
+ * }
+ * @phpstan-type Link_Input array{
+ * href: non-falsy-string,
+ * embeddable?: bool,
+ * targetHints?: array<string, mixed>, // Not narrowed like in Link_Attributes, since PHPStan merges this shape with its list form in add_links(). The merged attributes passed to add_link() there are only accepted while they include `mixed`; with the nested shape, the call would be an argument.type error even when `mixed` is not checked.
+ * ...<string, mixed>
+ * }
+ * @phpstan-type Curie array{
+ * name: string, // An empty name is a valid empty CURIE prefix, which WP_REST_Server::get_compact_response_links() handles consistently.
+ * href: non-falsy-string,
+ * templated?: bool,
+ * }
*/
class WP_REST_Response extends WP_HTTP_Response {
@@ -20,7 +47,8 @@ class WP_REST_Response extends WP_HTTP_Response {
* Links related to the response.
*
* @since 4.4.0
- * @var array
+ * @var array<string, array<string, mixed>[]> Map of link relation to list of links.
+ * @phpstan-var array<non-falsy-string, array<Link>>
*/
protected $links = array();
@@ -36,7 +64,8 @@ class WP_REST_Response extends WP_HTTP_Response {
* The handler that was used to create the response.
*
* @since 4.4.0
- * @var null|array
+ * @var array<string, mixed>|null
+ * @phpstan-var Route_Handler|null
*/
protected $matched_handler = null;
@@ -50,10 +79,14 @@ class WP_REST_Response extends WP_HTTP_Response {
* @link https://tools.ietf.org/html/rfc5988
* @link https://www.iana.org/assignments/link-relations/link-relations.xml
*
- * @param string $rel Link relation. Either an IANA registered type,
- * or an absolute URL.
- * @param string $href Target URI for the link.
- * @param array $attributes Optional. Link parameters to send along with the URL. Default empty array.
+ * @param string $rel Link relation. Either an IANA registered type,
+ * or an absolute URL.
+ * @param string $href Target URI for the link.
+ * @param array<string, mixed> $attributes Optional. Link parameters to send along with the URL. Default empty array.
+ *
+ * @phpstan-param non-falsy-string $rel
+ * @phpstan-param non-falsy-string $href
+ * @phpstan-param Link_Attributes $attributes
*/
public function add_link( $rel, $href, $attributes = array() ) {
if ( empty( $this->links[ $rel ] ) ) {
@@ -79,6 +112,8 @@ class WP_REST_Response extends WP_HTTP_Response {
* @param string $rel Link relation. Either an IANA registered type, or an absolute URL.
* @param string|null $href Optional. Only remove links for the relation matching the given href.
* Default null.
+ *
+ * @phpstan-param non-falsy-string $rel
*/
public function remove_link( $rel, $href = null ) {
if ( ! isset( $this->links[ $rel ] ) ) {
@@ -106,7 +141,9 @@ class WP_REST_Response extends WP_HTTP_Response {
*
* @since 4.4.0
*
- * @param array $links Map of link relation to list of links.
+ * @param array<string, array<mixed>> $links Map of link relation to a link's attributes, or to a list of these.
+ *
+ * @phpstan-param array<non-falsy-string, Link_Input|list<Link_Input>> $links
*/
public function add_links( $links ) {
foreach ( $links as $rel => $set ) {
@@ -126,7 +163,9 @@ class WP_REST_Response extends WP_HTTP_Response {
*
* @since 4.4.0
*
- * @return array List of links.
+ * @return array<string, array<string, mixed>[]> Map of link relation to list of links.
+ *
+ * @phpstan-return array<non-falsy-string, array<Link>>
*/
public function get_links() {
return $this->links;
@@ -142,10 +181,12 @@ class WP_REST_Response extends WP_HTTP_Response {
* @link https://tools.ietf.org/html/rfc5988
* @link https://www.iana.org/assignments/link-relations/link-relations.xml
*
- * @param string $rel Link relation. Either an IANA registered type, or an absolute URL.
- * @param string $link Target IRI for the link.
- * @param array $other Optional. Other parameters to send, as an associative array.
- * Default empty array.
+ * @param string $rel Link relation. Either an IANA registered type, or an absolute URL.
+ * @param string $link Target IRI for the link.
+ * @param array<string, string> $other Optional. Other parameters to send, as an associative array.
+ * Default empty array.
+ *
+ * @phpstan-param non-falsy-string $rel
*/
public function link_header( $rel, $link, $other = array() ) {
$header = '<' . $link . '>; rel="' . $rel . '"';
@@ -187,7 +228,9 @@ class WP_REST_Response extends WP_HTTP_Response {
*
* @since 4.4.0
*
- * @return null|array The handler that was used to create the response.
+ * @return array<string, mixed>|null The handler that was used to create the response.
+ *
+ * @phpstan-return Route_Handler|null
*/
public function get_matched_handler() {
return $this->matched_handler;
@@ -198,7 +241,9 @@ class WP_REST_Response extends WP_HTTP_Response {
*
* @since 4.4.0
*
- * @param array $handler The matched handler.
+ * @param array<string, mixed> $handler The matched handler.
+ *
+ * @phpstan-param Route_Handler $handler
*/
public function set_matched_handler( $handler ) {
$this->matched_handler = $handler;
@@ -250,7 +295,9 @@ class WP_REST_Response extends WP_HTTP_Response {
*
* @since 4.5.0
*
- * @return array Compact URIs.
+ * @return array<string, string|bool>[] Compact URIs.
+ *
+ * @phpstan-return array<Curie>
*/
public function get_curies() {
$curies = array(
@@ -284,7 +331,9 @@ class WP_REST_Response extends WP_HTTP_Response {
*
* @since 4.5.0
*
- * @param array $additional Additional CURIEs to register with the REST API.
+ * @param array<string, string|bool>[] $additional Additional CURIEs to register with the REST API.
+ *
+ * @phpstan-param array<Curie> $additional
*/
$additional = apply_filters( 'rest_response_link_curies', array() );
diff --git a/wp-includes/rest-api/class-wp-rest-server.php b/wp-includes/rest-api/class-wp-rest-server.php
index 48eb61f494..0603f79497 100644
--- a/wp-includes/rest-api/class-wp-rest-server.php
+++ b/wp-includes/rest-api/class-wp-rest-server.php
@@ -20,6 +20,8 @@
*
* @since 4.4.0
*
+ * @phpstan-import-type Target_Hints from WP_REST_Response
+ *
* @phpstan-type Endpoint_Arg array{
* required?: bool,
* default?: mixed,
@@ -32,6 +34,7 @@
* methods: array<uppercase-string, true>,
* callback?: callable|null,
* permission_callback?: callable|null,
+ * validate_callback?: callable|null,
* args: array<non-empty-string, Endpoint_Arg>,
* accept_json: bool,
* accept_raw: bool,
@@ -270,6 +273,8 @@ class WP_REST_Server {
* @param string $message Human-readable message.
* @param int|null $status Optional. HTTP status code to send. Default null.
* @return string JSON representation of the error.
+ *
+ * @phpstan-param int<100, 599>|null $status
*/
protected function json_error( $code, $message, $status = null ) {
if ( $status ) {
@@ -531,7 +536,7 @@ class WP_REST_Server {
* Send no-cache headers if $send_no_cache_headers is true,
* OR if the HTTP_X_HTTP_METHOD_OVERRIDE is used but resulted a 4xx response code.
*/
- if ( $send_no_cache_headers || ( true === $method_overridden && str_starts_with( $code, '4' ) ) ) {
+ if ( $send_no_cache_headers || ( true === $method_overridden && $code >= 400 && $code < 500 ) ) {
foreach ( wp_get_nocache_headers() as $header => $header_value ) {
if ( empty( $header_value ) ) {
$this->remove_header( $header );
@@ -701,8 +706,17 @@ class WP_REST_Server {
*
* @since 6.7.0
*
- * @param array $link The link to get target hints for.
- * @return array|null
+ * @param array<string, mixed> $link The link to get target hints for.
+ * @return array<string, string[]>|null Map of hint name to list of values, which is empty if the route
+ * allows no methods. Null if the link already has an `allow` hint,
+ * or its URL does not resolve to a valid REST API request.
+ *
+ * @phpstan-param array{
+ * href: non-falsy-string,
+ * targetHints?: Target_Hints,
+ * ...<string, mixed>
+ * } $link
+ * @phpstan-return array<lowercase-string, list<string>>|null
*/
protected static function get_target_hints_for_link( $link ) {
// Prefer targetHints that were specifically designated by the developer.
@@ -1213,7 +1227,9 @@ class WP_REST_Server {
* @since 5.6.0
*
* @param WP_REST_Request $request The request object.
- * @return array|WP_Error The route and request handler on success or a WP_Error instance if no handler was found.
+ * @return array<int, string|array<string, mixed>>|WP_Error The route and request handler on success or a WP_Error instance if no handler was found.
+ *
+ * @phpstan-return array{non-empty-string, Route_Handler}|WP_Error
*/
protected function match_request_to_handler( $request ) {
$method = $request->get_method();
@@ -1294,11 +1310,13 @@ class WP_REST_Server {
* @access private
* @since 5.6.0
*
- * @param WP_REST_Request $request The request object.
- * @param string $route The matched route regex.
- * @param array $handler The matched route handler.
- * @param WP_Error|null $response The current error object if any.
+ * @param WP_REST_Request $request The request object.
+ * @param string $route The matched route regex.
+ * @param array<string, mixed> $handler The matched route handler.
+ * @param WP_Error|null $response The current error object if any.
* @return WP_REST_Response
+ *
+ * @phpstan-param Route_Handler $handler
*/
protected function respond_to_request( $request, $route, $handler, $response ) {
/**
@@ -1315,8 +1333,10 @@ class WP_REST_Server {
*
* @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client.
* Usually a WP_REST_Response or WP_Error.
- * @param array $handler Route handler used for the request.
+ * @param array<string, mixed> $handler Route handler used for the request.
* @param WP_REST_Request $request Request used to generate the response.
+ *
+ * @phpstan-param Route_Handler $handler
*/
$response = apply_filters( 'rest_request_before_callbacks', $response, $handler, $request );
@@ -1344,10 +1364,12 @@ class WP_REST_Server {
* @since 4.4.0
* @since 4.5.0 Added `$route` and `$handler` parameters.
*
- * @param mixed $dispatch_result Dispatch result, will be used if not empty.
- * @param WP_REST_Request $request Request used to generate the response.
- * @param string $route Route matched for the request.
- * @param array $handler Route handler used for the request.
+ * @param mixed $dispatch_result Dispatch result, will be used if not empty.
+ * @param WP_REST_Request $request Request used to generate the response.
+ * @param string $route Route matched for the request.
+ * @param array<string, mixed> $handler Route handler used for the request.
+ *
+ * @phpstan-param Route_Handler $handler
*/
$dispatch_result = apply_filters( 'rest_dispatch_request', null, $request, $route, $handler );
@@ -1377,8 +1399,10 @@ class WP_REST_Server {
*
* @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client.
* Usually a WP_REST_Response or WP_Error.
- * @param array $handler Route handler used for the request.
+ * @param array<string, mixed> $handler Route handler used for the request.
* @param WP_REST_Request $request Request used to generate the response.
+ *
+ * @phpstan-param Route_Handler $handler
*/
$response = apply_filters( 'rest_request_after_callbacks', $response, $handler, $request );
@@ -1987,6 +2011,8 @@ class WP_REST_Server {
* @since 4.4.0
*
* @param int $code HTTP status.
+ *
+ * @phpstan-param int<100, 599> $code
*/
protected function set_status( $code ) {
status_header( $code );
@@ -2017,7 +2043,7 @@ class WP_REST_Server {
*
* @since 4.4.0
*
- * @param array $headers Map of header name to header value.
+ * @param array<string, string> $headers Map of header name to header value.
*/
public function send_headers( $headers ) {
foreach ( $headers as $key => $value ) {
diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php
index 442e100f3e..61087ef598 100644
--- a/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php
+++ b/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php
@@ -1683,6 +1683,8 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
* @param WP_Comment $comment Comment object.
* @param WP_REST_Request $request Request object.
* @return string[] List of link relations.
+ *
+ * @phpstan-return array<non-falsy-string>
*/
protected function get_available_actions( $comment, $request ) {
if ( 'edit' !== $request['context'] ) {
diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php
index 190eea6b20..b2429f1f48 100644
--- a/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php
+++ b/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php
@@ -1013,6 +1013,8 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
* @since 5.8.0
*
* @return string[] List of link relations.
+ *
+ * @phpstan-return array<non-falsy-string>
*/
protected function get_available_actions() {
$rels = array();
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 4018ec1656..6ac6f367cc 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '7.2-alpha-64526';
+$wp_version = '7.2-alpha-64527';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.