--- a/wp/wp-includes/rest-api.php Thu Sep 29 08:06:27 2022 +0200
+++ b/wp/wp-includes/rest-api.php Fri Sep 05 18:40:08 2025 +0200
@@ -23,16 +23,16 @@
* @since 5.1.0 Added a `_doing_it_wrong()` notice when not called on or after the `rest_api_init` hook.
* @since 5.5.0 Added a `_doing_it_wrong()` notice when the required `permission_callback` argument is not set.
*
- * @param string $namespace The first URL segment after core prefix. Should be unique to your package/plugin.
- * @param string $route The base URL for route you are adding.
- * @param array $args Optional. Either an array of options for the endpoint, or an array of arrays for
- * multiple methods. Default empty array.
- * @param bool $override Optional. If the route already exists, should we override it? True overrides,
- * false merges (with newer overriding if duplicate keys exist). Default false.
+ * @param string $route_namespace The first URL segment after core prefix. Should be unique to your package/plugin.
+ * @param string $route The base URL for route you are adding.
+ * @param array $args Optional. Either an array of options for the endpoint, or an array of arrays for
+ * multiple methods. Default empty array.
+ * @param bool $override Optional. If the route already exists, should we override it? True overrides,
+ * false merges (with newer overriding if duplicate keys exist). Default false.
* @return bool True on success, false on error.
*/
-function register_rest_route( $namespace, $route, $args = array(), $override = false ) {
- if ( empty( $namespace ) ) {
+function register_rest_route( $route_namespace, $route, $args = array(), $override = false ) {
+ if ( empty( $route_namespace ) ) {
/*
* Non-namespaced routes are not allowed, with the exception of the main
* and namespace indexes. If you really need to register a
@@ -45,9 +45,9 @@
return false;
}
- $clean_namespace = trim( $namespace, '/' );
-
- if ( $clean_namespace !== $namespace ) {
+ $clean_namespace = trim( $route_namespace, '/' );
+
+ if ( $clean_namespace !== $route_namespace ) {
_doing_it_wrong( __FUNCTION__, __( 'Namespace must not start or end with a slash.' ), '5.4.2' );
}
@@ -103,6 +103,22 @@
'5.5.0'
);
}
+
+ foreach ( $arg_group['args'] as $arg ) {
+ if ( ! is_array( $arg ) ) {
+ _doing_it_wrong(
+ __FUNCTION__,
+ sprintf(
+ /* translators: 1: $args, 2: The REST API route being registered. */
+ __( 'REST API %1$s should be an array of arrays. Non-array value detected for %2$s.' ),
+ '<code>$args</code>',
+ '<code>' . $clean_namespace . '/' . trim( $route, '/' ) . '</code>'
+ ),
+ '6.1.0'
+ );
+ break; // Leave the foreach loop once a non-array argument was found.
+ }
+ }
}
$full_route = '/' . $clean_namespace . '/' . trim( $route, '/' );
@@ -193,7 +209,7 @@
* @since 4.4.0
*/
function rest_api_default_filters() {
- if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
+ if ( wp_is_serving_rest_request() ) {
// Deprecated reporting.
add_action( 'deprecated_function_run', 'rest_handle_deprecated_function', 10, 3 );
add_filter( 'deprecated_function_trigger_error', '__return_false' );
@@ -225,29 +241,35 @@
continue;
}
- $controller->register_routes();
-
- if ( post_type_supports( $post_type->name, 'revisions' ) ) {
- $revisions_controller = new WP_REST_Revisions_Controller( $post_type->name );
+ if ( ! $post_type->late_route_registration ) {
+ $controller->register_routes();
+ }
+
+ $revisions_controller = $post_type->get_revisions_rest_controller();
+ if ( $revisions_controller ) {
$revisions_controller->register_routes();
}
- if ( 'attachment' !== $post_type->name ) {
- $autosaves_controller = new WP_REST_Autosaves_Controller( $post_type->name );
+ $autosaves_controller = $post_type->get_autosave_rest_controller();
+ if ( $autosaves_controller ) {
$autosaves_controller->register_routes();
}
+
+ if ( $post_type->late_route_registration ) {
+ $controller->register_routes();
+ }
}
// Post types.
- $controller = new WP_REST_Post_Types_Controller;
+ $controller = new WP_REST_Post_Types_Controller();
$controller->register_routes();
// Post statuses.
- $controller = new WP_REST_Post_Statuses_Controller;
+ $controller = new WP_REST_Post_Statuses_Controller();
$controller->register_routes();
// Taxonomies.
- $controller = new WP_REST_Taxonomies_Controller;
+ $controller = new WP_REST_Taxonomies_Controller();
$controller->register_routes();
// Terms.
@@ -262,7 +284,7 @@
}
// Users.
- $controller = new WP_REST_Users_Controller;
+ $controller = new WP_REST_Users_Controller();
$controller->register_routes();
// Application Passwords
@@ -270,7 +292,7 @@
$controller->register_routes();
// Comments.
- $controller = new WP_REST_Comments_Controller;
+ $controller = new WP_REST_Comments_Controller();
$controller->register_routes();
$search_handlers = array(
@@ -301,16 +323,12 @@
$controller = new WP_REST_Block_Types_Controller();
$controller->register_routes();
- // Global Styles.
- $controller = new WP_REST_Global_Styles_Controller;
- $controller->register_routes();
-
// Settings.
- $controller = new WP_REST_Settings_Controller;
+ $controller = new WP_REST_Settings_Controller();
$controller->register_routes();
// Themes.
- $controller = new WP_REST_Themes_Controller;
+ $controller = new WP_REST_Themes_Controller();
$controller->register_routes();
// Plugins.
@@ -361,6 +379,14 @@
// Site Editor Export.
$controller = new WP_REST_Edit_Site_Export_Controller();
$controller->register_routes();
+
+ // Navigation Fallback.
+ $controller = new WP_REST_Navigation_Fallback_Controller();
+ $controller->register_routes();
+
+ // Font Collections.
+ $font_collections_controller = new WP_REST_Font_Collections_Controller();
+ $font_collections_controller->register_routes();
}
/**
@@ -449,9 +475,11 @@
$url .= $path;
} else {
$url = trailingslashit( get_home_url( $blog_id, '', $scheme ) );
- // nginx only allows HTTP/1.0 methods when redirecting from / to /index.php.
- // To work around this, we manually add index.php to the URL, avoiding the redirect.
- if ( 'index.php' !== substr( $url, 9 ) ) {
+ /*
+ * nginx only allows HTTP/1.0 methods when redirecting from / to /index.php.
+ * To work around this, we manually add index.php to the URL, avoiding the redirect.
+ */
+ if ( ! str_ends_with( $url, 'index.php' ) ) {
$url .= 'index.php';
}
@@ -546,7 +574,7 @@
* @param string $class_name The name of the server class. Default 'WP_REST_Server'.
*/
$wp_rest_server_class = apply_filters( 'wp_rest_server_class', 'WP_REST_Server' );
- $wp_rest_server = new $wp_rest_server_class;
+ $wp_rest_server = new $wp_rest_server_class();
/**
* Fires when preparing to serve a REST API request.
@@ -608,8 +636,10 @@
return $response;
}
- // While WP_HTTP_Response is the base class of WP_REST_Response, it doesn't provide
- // all the required methods used in WP_REST_Server::dispatch().
+ /*
+ * While WP_HTTP_Response is the base class of WP_REST_Response, it doesn't provide
+ * all the required methods used in WP_REST_Server::dispatch().
+ */
if ( $response instanceof WP_HTTP_Response ) {
return new WP_REST_Response(
$response->get_data(),
@@ -626,20 +656,20 @@
*
* @since 4.4.0
*
- * @param string $function The function that was called.
- * @param string $replacement The function that should have been called.
- * @param string $version Version.
+ * @param string $function_name The function that was called.
+ * @param string $replacement The function that should have been called.
+ * @param string $version Version.
*/
-function rest_handle_deprecated_function( $function, $replacement, $version ) {
+function rest_handle_deprecated_function( $function_name, $replacement, $version ) {
if ( ! WP_DEBUG || headers_sent() ) {
return;
}
if ( ! empty( $replacement ) ) {
/* translators: 1: Function name, 2: WordPress version number, 3: New function name. */
- $string = sprintf( __( '%1$s (since %2$s; use %3$s instead)' ), $function, $version, $replacement );
+ $string = sprintf( __( '%1$s (since %2$s; use %3$s instead)' ), $function_name, $version, $replacement );
} else {
/* translators: 1: Function name, 2: WordPress version number. */
- $string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
+ $string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function_name, $version );
}
header( sprintf( 'X-WP-DeprecatedFunction: %s', $string ) );
@@ -650,20 +680,20 @@
*
* @since 4.4.0
*
- * @param string $function The function that was called.
- * @param string $message A message regarding the change.
- * @param string $version Version.
+ * @param string $function_name The function that was called.
+ * @param string $message A message regarding the change.
+ * @param string $version Version.
*/
-function rest_handle_deprecated_argument( $function, $message, $version ) {
+function rest_handle_deprecated_argument( $function_name, $message, $version ) {
if ( ! WP_DEBUG || headers_sent() ) {
return;
}
if ( $message ) {
/* translators: 1: Function name, 2: WordPress version number, 3: Error message. */
- $string = sprintf( __( '%1$s (since %2$s; %3$s)' ), $function, $version, $message );
+ $string = sprintf( __( '%1$s (since %2$s; %3$s)' ), $function_name, $version, $message );
} else {
/* translators: 1: Function name, 2: WordPress version number. */
- $string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
+ $string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function_name, $version );
}
header( sprintf( 'X-WP-DeprecatedParam: %s', $string ) );
@@ -674,11 +704,11 @@
*
* @since 5.5.0
*
- * @param string $function The function that was called.
- * @param string $message A message explaining what has been done incorrectly.
- * @param string|null $version The version of WordPress where the message was added.
+ * @param string $function_name The function that was called.
+ * @param string $message A message explaining what has been done incorrectly.
+ * @param string|null $version The version of WordPress where the message was added.
*/
-function rest_handle_doing_it_wrong( $function, $message, $version ) {
+function rest_handle_doing_it_wrong( $function_name, $message, $version ) {
if ( ! WP_DEBUG || headers_sent() ) {
return;
}
@@ -686,11 +716,11 @@
if ( $version ) {
/* translators: Developer debugging message. 1: PHP function name, 2: WordPress version number, 3: Explanatory message. */
$string = __( '%1$s (since %2$s; %3$s)' );
- $string = sprintf( $string, $function, $version, $message );
+ $string = sprintf( $string, $function_name, $version, $message );
} else {
/* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message. */
$string = __( '%1$s (%2$s)' );
- $string = sprintf( $string, $function, $message );
+ $string = sprintf( $string, $function_name, $message );
}
header( sprintf( 'X-WP-DoingItWrong: %s', $string ) );
@@ -710,7 +740,7 @@
if ( $origin ) {
// Requests from file:// and data: URLs send "Origin: null".
if ( 'null' !== $origin ) {
- $origin = esc_url_raw( $origin );
+ $origin = sanitize_url( $origin );
}
header( 'Access-Control-Allow-Origin: ' . $origin );
header( 'Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, PATCH, DELETE' );
@@ -842,7 +872,7 @@
}
/**
- * Filters the REST API response to include only a white-listed set of response object fields.
+ * Filters the REST API response to include only an allow-listed set of response object fields.
*
* @since 4.8.0
*
@@ -921,14 +951,18 @@
}
foreach ( $fields as $accepted_field ) {
- // Check to see if $field is the parent of any item in $fields.
- // A field "parent" should be accepted if "parent.child" is accepted.
- if ( strpos( $accepted_field, "$field." ) === 0 ) {
+ /*
+ * Check to see if $field is the parent of any item in $fields.
+ * A field "parent" should be accepted if "parent.child" is accepted.
+ */
+ if ( str_starts_with( $accepted_field, "$field." ) ) {
return true;
}
- // Conversely, if "parent" is accepted, all "parent.child" fields
- // should also be accepted.
- if ( strpos( $field, "$accepted_field." ) === 0 ) {
+ /*
+ * Conversely, if "parent" is accepted, all "parent.child" fields
+ * should also be accepted.
+ */
+ if ( str_starts_with( $field, "$accepted_field." ) ) {
return true;
}
}
@@ -973,7 +1007,11 @@
$resource = rest_get_queried_resource_route();
if ( $resource ) {
- printf( '<link rel="alternate" type="application/json" href="%s" />', esc_url( rest_url( $resource ) ) );
+ printf(
+ '<link rel="alternate" title="%1$s" type="application/json" href="%2$s" />',
+ _x( 'JSON', 'REST API resource link name' ),
+ esc_url( rest_url( $resource ) )
+ );
}
}
@@ -993,12 +1031,19 @@
return;
}
- header( sprintf( 'Link: <%s>; rel="https://api.w.org/"', esc_url_raw( $api_root ) ), false );
+ header( sprintf( 'Link: <%s>; rel="https://api.w.org/"', sanitize_url( $api_root ) ), false );
$resource = rest_get_queried_resource_route();
if ( $resource ) {
- header( sprintf( 'Link: <%s>; rel="alternate"; type="application/json"', esc_url_raw( rest_url( $resource ) ) ), false );
+ header(
+ sprintf(
+ 'Link: <%1$s>; rel="alternate"; title="%2$s"; type="application/json"',
+ sanitize_url( rest_url( $resource ) ),
+ _x( 'JSON', 'REST API resource link name' )
+ ),
+ false
+ );
}
}
@@ -1052,6 +1097,7 @@
$result = wp_verify_nonce( $nonce, 'wp_rest' );
if ( ! $result ) {
+ add_filter( 'rest_send_nocache_headers', '__return_true', 20 );
return new WP_Error( 'rest_cookie_invalid_nonce', __( 'Cookie check failed' ), array( 'status' => 403 ) );
}
@@ -1183,15 +1229,15 @@
}
/**
- * Retrieves the avatar urls in various sizes.
+ * Retrieves the avatar URLs in various sizes.
*
* @since 4.7.0
*
* @see get_avatar_url()
*
- * @param mixed $id_or_email The Gravatar to retrieve a URL for. Accepts a user_id, gravatar md5 hash,
+ * @param mixed $id_or_email The avatar to retrieve a URL for. Accepts a user ID, Gravatar MD5 hash,
* user email, WP_User object, WP_Post object, or WP_Comment object.
- * @return array Avatar URLs keyed by size. Each value can be a URL string or boolean false.
+ * @return (string|false)[] Avatar URLs keyed by size. Each value can be a URL string or boolean false.
*/
function rest_get_avatar_urls( $id_or_email ) {
$avatar_sizes = rest_get_avatar_sizes();
@@ -1234,7 +1280,7 @@
* @param string $date RFC3339 timestamp.
* @param bool $force_utc Optional. Whether to force UTC timezone instead of using
* the timestamp's timezone. Default false.
- * @return int Unix timestamp.
+ * @return int|false Unix timestamp on success, false on failure.
*/
function rest_parse_date( $date, $force_utc = false ) {
if ( $force_utc ) {
@@ -1256,7 +1302,7 @@
* @since 5.4.0
*
* @param string $color 3 or 6 digit hex color (with #).
- * @return string|false
+ * @return string|false Color value on success, false on failure.
*/
function rest_parse_hex_color( $color ) {
$regex = '|^#([A-Fa-f0-9]{3}){1,2}$|';
@@ -1276,8 +1322,13 @@
*
* @param string $date RFC3339 timestamp.
* @param bool $is_utc Whether the provided date should be interpreted as UTC. Default false.
- * @return array|null Local and UTC datetime strings, in MySQL datetime format (Y-m-d H:i:s),
- * null on failure.
+ * @return array|null {
+ * Local and UTC datetime strings, in MySQL datetime format (Y-m-d H:i:s),
+ * null on failure.
+ *
+ * @type string $0 Local datetime string.
+ * @type string $1 UTC datetime string.
+ * }
*/
function rest_get_date_with_gmt( $date, $is_utc = false ) {
/*
@@ -1398,7 +1449,7 @@
function rest_is_ip_address( $ip ) {
$ipv4_pattern = '/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/';
- if ( ! preg_match( $ipv4_pattern, $ip ) && ! Requests_IPv6::check_ipv6( $ip ) ) {
+ if ( ! preg_match( $ipv4_pattern, $ip ) && ! WpOrg\Requests\Ipv6::check_ipv6( $ip ) ) {
return false;
}
@@ -1533,12 +1584,12 @@
}
/**
- * Converts an object-like value to an object.
+ * Converts an object-like value to an array.
*
* @since 5.5.0
*
* @param mixed $maybe_object The value being evaluated.
- * @return array Returns the object extracted from the value.
+ * @return array Returns the object extracted from the value as an associative array.
*/
function rest_sanitize_object( $maybe_object ) {
if ( '' === $maybe_object ) {
@@ -1565,8 +1616,8 @@
*
* @since 5.5.0
*
- * @param mixed $value The value to check.
- * @param array $types The list of possible types.
+ * @param mixed $value The value to check.
+ * @param string[] $types The list of possible types.
* @return string The best matching type, an empty string if no types match.
*/
function rest_get_best_type_for_value( $value, $types ) {
@@ -1580,8 +1631,10 @@
'null' => 'is_null',
);
- // Both arrays and objects allow empty strings to be converted to their types.
- // But the best answer for this type is a string.
+ /*
+ * Both arrays and objects allow empty strings to be converted to their types.
+ * But the best answer for this type is a string.
+ */
if ( '' === $value && in_array( 'string', $types, true ) ) {
return 'string';
}
@@ -1640,13 +1693,13 @@
*
* @since 5.5.0
*
- * @param array $array The array to check.
+ * @param array $input_array The array to check.
* @return bool True if the array contains unique items, false otherwise.
*/
-function rest_validate_array_contains_unique_items( $array ) {
+function rest_validate_array_contains_unique_items( $input_array ) {
$seen = array();
- foreach ( $array as $item ) {
+ foreach ( $input_array as $item ) {
$stabilized = rest_stabilize_value( $item );
$key = serialize( $stabilized );
@@ -2162,8 +2215,10 @@
}
}
- // The "format" keyword should only be applied to strings. However, for backward compatibility,
- // we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value.
+ /*
+ * The "format" keyword should only be applied to strings. However, for backward compatibility,
+ * we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value.
+ */
if ( isset( $args['format'] )
&& ( ! isset( $args['type'] ) || 'string' === $args['type'] || ! in_array( $args['type'], $allowed_types, true ) )
) {
@@ -2795,7 +2850,7 @@
return sanitize_text_field( $value );
case 'uri':
- return esc_url_raw( $value );
+ return sanitize_url( $value );
case 'ip':
return sanitize_text_field( $value );
@@ -2829,8 +2884,10 @@
* @return array Modified reduce accumulator.
*/
function rest_preload_api_request( $memo, $path ) {
- // array_reduce() doesn't support passing an array in PHP 5.2,
- // so we need to make sure we start with one.
+ /*
+ * array_reduce() doesn't support passing an array in PHP 5.2,
+ * so we need to make sure we start with one.
+ */
if ( ! is_array( $memo ) ) {
$memo = array();
}
@@ -2870,8 +2927,8 @@
$server = rest_get_server();
/** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */
$response = apply_filters( 'rest_post_dispatch', rest_ensure_response( $response ), $server, $request );
- $embed = $request->has_param( '_embed' ) ? rest_parse_embed_param( $request['_embed'] ) : false;
- $data = (array) $server->response_to_data( $response, $embed );
+ $embed = $request->has_param( '_embed' ) ? rest_parse_embed_param( $request['_embed'] ) : false;
+ $data = (array) $server->response_to_data( $response, $embed );
if ( 'OPTIONS' === $method ) {
$memo[ $method ][ $path ] = array(
@@ -2918,36 +2975,36 @@
* @since 5.6.0 Support the "patternProperties" keyword for objects.
* Support the "anyOf" and "oneOf" keywords.
*
- * @param array|object $data The response data to modify.
- * @param array $schema The schema for the endpoint used to filter the response.
- * @param string $context The requested context.
+ * @param array|object $response_data The response data to modify.
+ * @param array $schema The schema for the endpoint used to filter the response.
+ * @param string $context The requested context.
* @return array|object The filtered response data.
*/
-function rest_filter_response_by_context( $data, $schema, $context ) {
+function rest_filter_response_by_context( $response_data, $schema, $context ) {
if ( isset( $schema['anyOf'] ) ) {
- $matching_schema = rest_find_any_matching_schema( $data, $schema, '' );
+ $matching_schema = rest_find_any_matching_schema( $response_data, $schema, '' );
if ( ! is_wp_error( $matching_schema ) ) {
if ( ! isset( $schema['type'] ) ) {
$schema['type'] = $matching_schema['type'];
}
- $data = rest_filter_response_by_context( $data, $matching_schema, $context );
+ $response_data = rest_filter_response_by_context( $response_data, $matching_schema, $context );
}
}
if ( isset( $schema['oneOf'] ) ) {
- $matching_schema = rest_find_one_matching_schema( $data, $schema, '', true );
+ $matching_schema = rest_find_one_matching_schema( $response_data, $schema, '', true );
if ( ! is_wp_error( $matching_schema ) ) {
if ( ! isset( $schema['type'] ) ) {
$schema['type'] = $matching_schema['type'];
}
- $data = rest_filter_response_by_context( $data, $matching_schema, $context );
+ $response_data = rest_filter_response_by_context( $response_data, $matching_schema, $context );
}
}
- if ( ! is_array( $data ) && ! is_object( $data ) ) {
- return $data;
+ if ( ! is_array( $response_data ) && ! is_object( $response_data ) ) {
+ return $response_data;
}
if ( isset( $schema['type'] ) ) {
@@ -2955,14 +3012,14 @@
} elseif ( isset( $schema['properties'] ) ) {
$type = 'object'; // Back compat if a developer accidentally omitted the type.
} else {
- return $data;
+ return $response_data;
}
$is_array_type = 'array' === $type || ( is_array( $type ) && in_array( 'array', $type, true ) );
$is_object_type = 'object' === $type || ( is_array( $type ) && in_array( 'object', $type, true ) );
if ( $is_array_type && $is_object_type ) {
- if ( rest_is_array( $data ) ) {
+ if ( rest_is_array( $response_data ) ) {
$is_object_type = false;
} else {
$is_array_type = false;
@@ -2971,7 +3028,7 @@
$has_additional_properties = $is_object_type && isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] );
- foreach ( $data as $key => $value ) {
+ foreach ( $response_data as $key => $value ) {
$check = array();
if ( $is_array_type ) {
@@ -2996,27 +3053,27 @@
if ( ! in_array( $context, $check['context'], true ) ) {
if ( $is_array_type ) {
// All array items share schema, so there's no need to check each one.
- $data = array();
+ $response_data = array();
break;
}
- if ( is_object( $data ) ) {
- unset( $data->$key );
+ if ( is_object( $response_data ) ) {
+ unset( $response_data->$key );
} else {
- unset( $data[ $key ] );
+ unset( $response_data[ $key ] );
}
} elseif ( is_array( $value ) || is_object( $value ) ) {
$new_value = rest_filter_response_by_context( $value, $check, $context );
- if ( is_object( $data ) ) {
- $data->$key = $new_value;
+ if ( is_object( $response_data ) ) {
+ $response_data->$key = $new_value;
} else {
- $data[ $key ] = $new_value;
+ $response_data[ $key ] = $new_value;
}
}
}
- return $data;
+ return $response_data;
}
/**
@@ -3291,7 +3348,7 @@
* Converts an error to a response object.
*
* This iterates over all error codes and messages to change it into a flat
- * array. This enables simpler client behaviour, as it is represented as a
+ * array. This enables simpler client behavior, as it is represented as a
* list in JSON rather than an object/map.
*
* @since 5.7.0
@@ -3339,3 +3396,38 @@
return new WP_REST_Response( $data, $status );
}
+
+/**
+ * Checks whether a REST API endpoint request is currently being handled.
+ *
+ * This may be a standalone REST API request, or an internal request dispatched from within a regular page load.
+ *
+ * @since 6.5.0
+ *
+ * @global WP_REST_Server $wp_rest_server REST server instance.
+ *
+ * @return bool True if a REST endpoint request is currently being handled, false otherwise.
+ */
+function wp_is_rest_endpoint() {
+ /* @var WP_REST_Server $wp_rest_server */
+ global $wp_rest_server;
+
+ // Check whether this is a standalone REST request.
+ $is_rest_endpoint = wp_is_serving_rest_request();
+ if ( ! $is_rest_endpoint ) {
+ // Otherwise, check whether an internal REST request is currently being handled.
+ $is_rest_endpoint = isset( $wp_rest_server )
+ && $wp_rest_server->is_dispatching();
+ }
+
+ /**
+ * Filters whether a REST endpoint request is currently being handled.
+ *
+ * This may be a standalone REST API request, or an internal request dispatched from within a regular page load.
+ *
+ * @since 6.5.0
+ *
+ * @param bool $is_request_endpoint Whether a REST endpoint request is currently being handled.
+ */
+ return (bool) apply_filters( 'wp_is_rest_endpoint', $is_rest_endpoint );
+}