diff --git a/wp-includes/class-wp-query.php b/wp-includes/class-wp-query.php index e6a3e6b743..f683a52bd1 100644 --- a/wp-includes/class-wp-query.php +++ b/wp-includes/class-wp-query.php @@ -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; } diff --git a/wp-includes/deprecated.php b/wp-includes/deprecated.php index e63708f91b..ec7b33f360 100644 --- a/wp-includes/deprecated.php +++ b/wp-includes/deprecated.php @@ -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. diff --git a/wp-includes/functions.php b/wp-includes/functions.php index a3a5e56bfa..ff55251d7d 100644 --- a/wp-includes/functions.php +++ b/wp-includes/functions.php @@ -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. diff --git a/wp-includes/load.php b/wp-includes/load.php index 520902cdd6..0dbbc187cf 100644 --- a/wp-includes/load.php +++ b/wp-includes/load.php @@ -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() diff --git a/wp-includes/rest-api.php b/wp-includes/rest-api.php index 61e324e801..2631a6663f 100644 --- a/wp-includes/rest-api.php +++ b/wp-includes/rest-api.php @@ -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 ); +} diff --git a/wp-includes/rest-api/class-wp-rest-server.php b/wp-includes/rest-api/class-wp-rest-server.php index 6838579ce8..861f5115e6 100644 --- a/wp-includes/rest-api/class-wp-rest-server.php +++ b/wp-includes/rest-api/class-wp-rest-server.php @@ -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; } /** diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php index 7367c0fc57..c7da6d068b 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php @@ -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. diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php index c9ac6675d0..7dcc4d7923 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php @@ -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 ) { diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php index 8886cb587b..6425afe874 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -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; } diff --git a/wp-includes/user.php b/wp-includes/user.php index 5dbff2b929..5d8cd9f57c 100644 --- a/wp-includes/user.php +++ b/wp-includes/user.php @@ -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 ) ); /** diff --git a/wp-includes/version.php b/wp-includes/version.php index 9e43c965d3..205deb7271 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -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.