Bootstrap/Load: Introduce functions to check whether WordPress is serving a REST API request.

This changeset introduces two functions:
* `wp_is_serving_rest_request()` returns a boolean for whether WordPress is serving an actual REST API request.
* `wp_is_rest_endpoint()` returns a boolean for whether a WordPress REST API endpoint is currently being used. While this is always the case if `wp_is_serving_rest_request()` returns `true`, the function additionally covers the scenario of internal REST API requests, i.e. where WordPress calls a REST API endpoint within the same request.

Both functions should only be used after the `parse_request` action.

All relevant manual checks have been adjusted to use one of the new functions, depending on the use-case. They were all using the same constant check so far, while in fact some of them were intending to check for an actual REST API request while others were intending to check for REST endpoint usage.

A new filter `wp_is_rest_endpoint` can be used to alter the return value of the `wp_is_rest_endpoint()` function.

Props lots.0.logs, TimothyBlynJacobs, flixos90, joehoyle, peterwilsoncc, swissspidy, SergeyBiryukov, pento, mikejolley, iandunn, hellofromTonya, Cybr, petitphp.
Fixes #42061.

Built from https://develop.svn.wordpress.org/trunk@57312


git-svn-id: http://core.svn.wordpress.org/trunk@56818 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Felix Arntz 2024-01-19 17:40:09 +00:00
parent 9d8b474654
commit e19c18cba9
11 changed files with 97 additions and 12 deletions

View File

@ -1027,7 +1027,7 @@ class WP_Query {
}
if ( ! ( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed
|| ( defined( 'REST_REQUEST' ) && REST_REQUEST && $this->is_main_query() )
|| ( wp_is_serving_rest_request() && $this->is_main_query() )
|| $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots || $this->is_favicon ) ) {
$this->is_home = true;
}

View File

@ -5436,7 +5436,7 @@ function _wp_theme_json_webfonts_handler() {
$settings = WP_Theme_JSON_Resolver::get_merged_data()->get_settings();
// If in the editor, add webfonts defined in variations.
if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
if ( is_admin() || wp_is_rest_endpoint() ) {
$variations = WP_Theme_JSON_Resolver::get_style_variations();
foreach ( $variations as $variation ) {
// Skip if fontFamilies are not defined in the variation.

View File

@ -3718,7 +3718,7 @@ function wp_die( $message = '', $title = '', $args = array() ) {
* @param callable $callback Callback function name.
*/
$callback = apply_filters( 'wp_die_json_handler', '_json_wp_die_handler' );
} elseif ( defined( 'REST_REQUEST' ) && REST_REQUEST && wp_is_jsonp_request() ) {
} elseif ( wp_is_serving_rest_request() && wp_is_jsonp_request() ) {
/**
* Filters the callback for killing WordPress execution for JSONP REST requests.
*
@ -4441,7 +4441,7 @@ function _wp_json_prepare_data( $value ) {
* @param int $flags Optional. Options to be passed to json_encode(). Default 0.
*/
function wp_send_json( $response, $status_code = null, $flags = 0 ) {
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
if ( wp_is_serving_rest_request() ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
@ -4697,6 +4697,23 @@ function _mce_set_direction( $mce_init ) {
return $mce_init;
}
/**
* Determines whether WordPress is currently serving a REST API request.
*
* The function relies on the 'REST_REQUEST' global. As such, it only returns true when an actual REST _request_ is
* being made. It does not return true when a REST endpoint is hit as part of another request, e.g. for preloading a
* REST response. See {@see wp_is_rest_endpoint()} for that purpose.
*
* This function should not be called until the {@see 'parse_request'} action, as the constant is only defined then,
* even for an actual REST request.
*
* @since 6.5.0
*
* @return bool True if it's a WordPress REST API request, false otherwise.
*/
function wp_is_serving_rest_request() {
return defined( 'REST_REQUEST' ) && REST_REQUEST;
}
/**
* Converts smiley code to the icon graphic file equivalent.

View File

@ -598,6 +598,10 @@ function wp_debug_mode() {
error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
}
/*
* The 'REST_REQUEST' check here is optimistic as the constant is most
* likely not set at this point even if it is in fact a REST request.
*/
if ( defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) || defined( 'MS_FILES_REQUEST' )
|| ( defined( 'WP_INSTALLING' ) && WP_INSTALLING )
|| wp_doing_ajax() || wp_is_json_request()

View File

@ -209,7 +209,7 @@ function rest_api_register_rewrites() {
* @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' );
@ -3389,3 +3389,38 @@ function rest_convert_error_to_response( $error ) {
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 );
}

View File

@ -87,6 +87,14 @@ class WP_REST_Server {
*/
protected $embed_cache = array();
/**
* Stores request objects that are currently being handled.
*
* @since 6.5.0
* @var array
*/
protected $dispatching_requests = array();
/**
* Instantiates the REST server.
*
@ -983,6 +991,8 @@ class WP_REST_Server {
* @return WP_REST_Response Response returned by the callback.
*/
public function dispatch( $request ) {
$this->dispatching_requests[] = $request;
/**
* Filters the pre-calculated result of a REST API dispatch request.
*
@ -1008,6 +1018,7 @@ class WP_REST_Server {
$result = $this->error_to_response( $result );
}
array_pop( $this->dispatching_requests );
return $result;
}
@ -1015,7 +1026,9 @@ class WP_REST_Server {
$matched = $this->match_request_to_handler( $request );
if ( is_wp_error( $matched ) ) {
return $this->error_to_response( $matched );
$response = $this->error_to_response( $matched );
array_pop( $this->dispatching_requests );
return $response;
}
list( $route, $handler ) = $matched;
@ -1040,7 +1053,22 @@ class WP_REST_Server {
}
}
return $this->respond_to_request( $request, $route, $handler, $error );
$response = $this->respond_to_request( $request, $route, $handler, $error );
array_pop( $this->dispatching_requests );
return $response;
}
/**
* Returns whether the REST server is currently dispatching / responding to a request.
*
* This may be a standalone REST API request, or an internal request dispatched from within a regular page load.
*
* @since 6.5.0
*
* @return bool Whether the REST server is currently handling a request.
*/
public function is_dispatching() {
return (bool) $this->dispatching_requests;
}
/**

View File

@ -201,7 +201,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
wp_after_insert_post( $attachment, false, null );
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
if ( wp_is_serving_rest_request() ) {
/*
* Set a custom header with the attachment_id.
* Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
@ -630,7 +630,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
update_post_meta( $new_attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
}
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
if ( wp_is_serving_rest_request() ) {
/*
* Set a custom header with the attachment_id.
* Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.

View File

@ -128,7 +128,7 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
*
* @since 5.9.0
*
* @param WP_REST_REQUEST $request Full details about the request.
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Response|WP_Error The parsed details as a response object. WP_Error if there are errors.
*/
public function parse_url_details( $request ) {

View File

@ -2586,7 +2586,7 @@ function wp_should_load_block_editor_scripts_and_styles() {
* @return bool Whether separate assets will be loaded.
*/
function wp_should_load_separate_core_block_assets() {
if ( is_admin() || is_feed() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
if ( is_admin() || is_feed() || wp_is_rest_endpoint() ) {
return false;
}

View File

@ -333,6 +333,7 @@ function wp_authenticate_application_password( $input_user, $username, $password
return $input_user;
}
// The 'REST_REQUEST' check here may happen too early for the constant to be available.
$is_api_request = ( ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) );
/**

View File

@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.5-alpha-57311';
$wp_version = '6.5-alpha-57312';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.