diff --git a/wp-includes/rest-api/class-wp-rest-request.php b/wp-includes/rest-api/class-wp-rest-request.php index 6ed6ce6674..3257194e54 100644 --- a/wp-includes/rest-api/class-wp-rest-request.php +++ b/wp-includes/rest-api/class-wp-rest-request.php @@ -161,6 +161,18 @@ class WP_REST_Request implements ArrayAccess { return $this->headers; } + /** + * Determines if the request is the given method. + * + * @since 6.8.0 + * + * @param string $method HTTP method. + * @return bool Whether the request is of the given method. + */ + public function is_method( $method ) { + return $this->get_method() === strtoupper( $method ); + } + /** * Canonicalizes the header name. * diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php index 5545625df4..43fd8d3b29 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php @@ -305,6 +305,10 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller { return $parent; } + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } $response = array(); $parent_id = $parent->ID; $revisions = wp_get_post_revisions( $parent_id, array( 'check_enabled' => false ) ); @@ -448,6 +452,11 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller { // Restores the more descriptive, specific name for use within this method. $post = $item; + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php */ + return apply_filters( 'rest_prepare_autosave', new WP_REST_Response(), $post, $request ); + } $response = $this->revisions_controller->prepare_item_for_response( $post, $request ); $fields = $this->get_fields_for_response( $request ); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php index 5d31891678..86ee4cdc52 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php @@ -81,6 +81,11 @@ class WP_REST_Block_Pattern_Categories_Controller extends WP_REST_Controller { * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } + $response = array(); $categories = WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(); foreach ( $categories as $category ) { diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php index 263f2a8ef2..f167d72255 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php @@ -131,6 +131,11 @@ class WP_REST_Block_Types_Controller extends WP_REST_Controller { * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } + $data = array(); $block_types = $this->block_registry->get_all_registered(); @@ -250,6 +255,12 @@ class WP_REST_Block_Types_Controller extends WP_REST_Controller { // Restores the more descriptive, specific name for use within this method. $block_type = $item; + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php */ + return apply_filters( 'rest_prepare_block_type', new WP_REST_Response(), $block_type, $request ); + } + $fields = $this->get_fields_for_response( $request ); $data = array(); 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 6f44d1e1b2..57214ef62e 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 @@ -262,6 +262,14 @@ class WP_REST_Comments_Controller extends WP_REST_Controller { $prepared_args['offset'] = $prepared_args['number'] * ( absint( $request['page'] ) - 1 ); } + $is_head_request = $request->is_method( 'HEAD' ); + if ( $is_head_request ) { + // Force the 'fields' argument. For HEAD requests, only post IDs are required to calculate pagination. + $prepared_args['fields'] = 'ids'; + // Disable priming comment meta for HEAD requests to improve performance. + $prepared_args['update_comment_meta_cache'] = false; + } + /** * Filters WP_Comment_Query arguments when querying comments via the REST API. * @@ -277,15 +285,17 @@ class WP_REST_Comments_Controller extends WP_REST_Controller { $query = new WP_Comment_Query(); $query_result = $query->query( $prepared_args ); - $comments = array(); + if ( ! $is_head_request ) { + $comments = array(); - foreach ( $query_result as $comment ) { - if ( ! $this->check_read_permission( $comment, $request ) ) { - continue; + foreach ( $query_result as $comment ) { + if ( ! $this->check_read_permission( $comment, $request ) ) { + continue; + } + + $data = $this->prepare_item_for_response( $comment, $request ); + $comments[] = $this->prepare_response_for_collection( $data ); } - - $data = $this->prepare_item_for_response( $comment, $request ); - $comments[] = $this->prepare_response_for_collection( $data ); } $total_comments = (int) $query->found_comments; @@ -303,7 +313,7 @@ class WP_REST_Comments_Controller extends WP_REST_Controller { $max_pages = (int) ceil( $total_comments / $request['per_page'] ); } - $response = rest_ensure_response( $comments ); + $response = $is_head_request ? new WP_REST_Response() : rest_ensure_response( $comments ); $response->header( 'X-WP-Total', $total_comments ); $response->header( 'X-WP-TotalPages', $max_pages ); @@ -1041,6 +1051,12 @@ class WP_REST_Comments_Controller extends WP_REST_Controller { // Restores the more descriptive, specific name for use within this method. $comment = $item; + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php */ + return apply_filters( 'rest_prepare_comment', new WP_REST_Response(), $comment, $request ); + } + $fields = $this->get_fields_for_response( $request ); $data = array(); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php index b409af4fc2..476f1b750f 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php @@ -89,6 +89,8 @@ class WP_REST_Font_Collections_Controller extends WP_REST_Controller { $collections_page = array_slice( $collections_all, ( $page - 1 ) * $per_page, $per_page ); + $is_head_request = $request->is_method( 'HEAD' ); + $items = array(); foreach ( $collections_page as $collection ) { $item = $this->prepare_item_for_response( $collection, $request ); @@ -97,11 +99,21 @@ class WP_REST_Font_Collections_Controller extends WP_REST_Controller { if ( is_wp_error( $item ) ) { continue; } + + /* + * Skip preparing the response body for HEAD requests. + * Cannot exit earlier due to backward compatibility reasons, + * as validation occurs in the prepare_item_for_response method. + */ + if ( $is_head_request ) { + continue; + } + $item = $this->prepare_response_for_collection( $item ); $items[] = $item; } - $response = rest_ensure_response( $items ); + $response = $is_head_request ? new WP_REST_Response() : rest_ensure_response( $items ); $response->header( 'X-WP-Total', (int) $total_items ); $response->header( 'X-WP-TotalPages', $max_pages ); @@ -175,6 +187,15 @@ class WP_REST_Font_Collections_Controller extends WP_REST_Controller { return $collection_data; } + /** + * Don't prepare the response body for HEAD requests. + * Can't exit at the beginning of the method due to the potential need to return a WP_Error object. + */ + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php */ + return apply_filters( 'rest_prepare_font_collection', new WP_REST_Response(), $item, $request ); + } + foreach ( $data_fields as $field ) { if ( rest_is_field_included( $field, $fields ) ) { $data[ $field ] = $collection_data[ $field ]; @@ -182,6 +203,15 @@ class WP_REST_Font_Collections_Controller extends WP_REST_Controller { } } + /** + * Don't prepare the response body for HEAD requests. + * Can't exit at the beginning of the method due to the potential need to return a WP_Error object. + */ + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php */ + return apply_filters( 'rest_prepare_font_collection', new WP_REST_Response(), $item, $request ); + } + $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) ) { diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php index 4108f9711c..e214ab6d39 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php @@ -163,6 +163,8 @@ class WP_REST_Global_Styles_Revisions_Controller extends WP_REST_Revisions_Contr return $global_styles_config; } + $is_head_request = $request->is_method( 'HEAD' ); + if ( wp_revisions_enabled( $parent ) ) { $registered = $this->get_collection_params(); $query_args = array( @@ -186,6 +188,14 @@ class WP_REST_Global_Styles_Revisions_Controller extends WP_REST_Revisions_Contr } } + if ( $is_head_request ) { + // Force the 'fields' argument. For HEAD requests, only post IDs are required to calculate pagination. + $query_args['fields'] = 'ids'; + // Disable priming post meta for HEAD requests to improve performance. + $query_args['update_post_term_cache'] = false; + $query_args['update_post_meta_cache'] = false; + } + $revisions_query = new WP_Query(); $revisions = $revisions_query->query( $query_args ); $offset = isset( $query_args['offset'] ) ? (int) $query_args['offset'] : 0; @@ -228,15 +238,19 @@ class WP_REST_Global_Styles_Revisions_Controller extends WP_REST_Revisions_Contr $page = (int) $request['page']; } - $response = array(); + if ( ! $is_head_request ) { + $response = array(); - foreach ( $revisions as $revision ) { - $data = $this->prepare_item_for_response( $revision, $request ); - $response[] = $this->prepare_response_for_collection( $data ); + foreach ( $revisions as $revision ) { + $data = $this->prepare_item_for_response( $revision, $request ); + $response[] = $this->prepare_response_for_collection( $data ); + } + + $response = rest_ensure_response( $response ); + } else { + $response = new WP_REST_Response(); } - $response = rest_ensure_response( $response ); - $response->header( 'X-WP-Total', (int) $total_revisions ); $response->header( 'X-WP-TotalPages', (int) $max_pages ); @@ -275,6 +289,11 @@ class WP_REST_Global_Styles_Revisions_Controller extends WP_REST_Revisions_Contr * @return WP_REST_Response|WP_Error Response object. */ public function prepare_item_for_response( $post, $request ) { + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + return new WP_REST_Response(); + } + $parent = $this->get_parent( $request['parent'] ); $global_styles_config = $this->get_decoded_global_styles_json( $post->post_content ); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php index e31c47ee61..4dda8b3455 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php @@ -161,6 +161,11 @@ class WP_REST_Pattern_Directory_Controller extends WP_REST_Controller { return $raw_patterns; } + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } + $response = array(); if ( $raw_patterns ) { diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php index d766d5c61d..6ead90af59 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php @@ -109,6 +109,11 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } + $data = array(); $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); @@ -178,6 +183,12 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { // Restores the more descriptive, specific name for use within this method. $post_type = $item; + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php */ + return apply_filters( 'rest_prepare_post_type', new WP_REST_Response(), $post_type, $request ); + } + $taxonomies = wp_list_filter( get_object_taxonomies( $post_type->name, 'objects' ), array( 'show_in_rest' => true ) ); $taxonomies = wp_list_pluck( $taxonomies, 'name' ); $base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name; diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index cb25207fc5..37b7c6305a 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php @@ -411,6 +411,15 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { // Force the post_type argument, since it's not a user input variable. $args['post_type'] = $this->post_type; + $is_head_request = $request->is_method( 'HEAD' ); + if ( $is_head_request ) { + // Force the 'fields' argument. For HEAD requests, only post IDs are required to calculate pagination. + $args['fields'] = 'ids'; + // Disable priming post meta for HEAD requests to improve performance. + $args['update_post_term_cache'] = false; + $args['update_post_meta_cache'] = false; + } + /** * Filters WP_Query arguments when querying posts via the REST API. * @@ -443,22 +452,24 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { add_filter( 'post_password_required', array( $this, 'check_password_required' ), 10, 2 ); } - $posts = array(); + if ( ! $is_head_request ) { + $posts = array(); - update_post_author_caches( $query_result ); - update_post_parent_caches( $query_result ); + update_post_author_caches( $query_result ); + update_post_parent_caches( $query_result ); - if ( post_type_supports( $this->post_type, 'thumbnail' ) ) { - update_post_thumbnail_cache( $posts_query ); - } - - foreach ( $query_result as $post ) { - if ( ! $this->check_read_permission( $post ) ) { - continue; + if ( post_type_supports( $this->post_type, 'thumbnail' ) ) { + update_post_thumbnail_cache( $posts_query ); } - $data = $this->prepare_item_for_response( $post, $request ); - $posts[] = $this->prepare_response_for_collection( $data ); + foreach ( $query_result as $post ) { + if ( ! $this->check_read_permission( $post ) ) { + continue; + } + + $data = $this->prepare_item_for_response( $post, $request ); + $posts[] = $this->prepare_response_for_collection( $data ); + } } // Reset filter. @@ -488,7 +499,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { ); } - $response = rest_ensure_response( $posts ); + $response = $is_head_request ? new WP_REST_Response() : rest_ensure_response( $posts ); $response->header( 'X-WP-Total', (int) $total_posts ); $response->header( 'X-WP-TotalPages', (int) $max_pages ); @@ -1833,6 +1844,12 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { setup_postdata( $post ); + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ + return apply_filters( "rest_prepare_{$this->post_type}", new WP_REST_Response(), $post, $request ); + } + $fields = $this->get_fields_for_response( $request ); // Base fields for every post. diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php index 1dbc611631..2756e3d751 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php @@ -253,6 +253,8 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller { ); } + $is_head_request = $request->is_method( 'HEAD' ); + if ( wp_revisions_enabled( $parent ) ) { $registered = $this->get_collection_params(); $args = array( @@ -287,6 +289,14 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller { $args['orderby'] = 'date ID'; } + if ( $is_head_request ) { + // Force the 'fields' argument. For HEAD requests, only post IDs are required to calculate pagination. + $args['fields'] = 'ids'; + // Disable priming post meta for HEAD requests to improve performance. + $args['update_post_term_cache'] = false; + $args['update_post_meta_cache'] = false; + } + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ $args = apply_filters( 'rest_revision_query', $args, $request ); $query_args = $this->prepare_items_query( $args, $request ); @@ -335,15 +345,19 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller { $page = (int) $request['page']; } - $response = array(); + if ( ! $is_head_request ) { + $response = array(); - foreach ( $revisions as $revision ) { - $data = $this->prepare_item_for_response( $revision, $request ); - $response[] = $this->prepare_response_for_collection( $data ); + foreach ( $revisions as $revision ) { + $data = $this->prepare_item_for_response( $revision, $request ); + $response[] = $this->prepare_response_for_collection( $data ); + } + + $response = rest_ensure_response( $response ); + } else { + $response = new WP_REST_Response(); } - $response = rest_ensure_response( $response ); - $response->header( 'X-WP-Total', (int) $total_revisions ); $response->header( 'X-WP-TotalPages', (int) $max_pages ); @@ -574,6 +588,12 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller { setup_postdata( $post ); + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php */ + return apply_filters( 'rest_prepare_revision', new WP_REST_Response(), $post, $request ); + } + $fields = $this->get_fields_for_response( $request ); $data = array(); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php index 55fe1ad63a..345a200c67 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php @@ -142,11 +142,14 @@ class WP_REST_Search_Controller extends WP_REST_Controller { $ids = $result[ WP_REST_Search_Handler::RESULT_IDS ]; - $results = array(); + $is_head_request = $request->is_method( 'HEAD' ); + if ( ! $is_head_request ) { + $results = array(); - foreach ( $ids as $id ) { - $data = $this->prepare_item_for_response( $id, $request ); - $results[] = $this->prepare_response_for_collection( $data ); + foreach ( $ids as $id ) { + $data = $this->prepare_item_for_response( $id, $request ); + $results[] = $this->prepare_response_for_collection( $data ); + } } $total = (int) $result[ WP_REST_Search_Handler::RESULT_TOTAL ]; @@ -162,7 +165,7 @@ class WP_REST_Search_Controller extends WP_REST_Controller { ); } - $response = rest_ensure_response( $results ); + $response = $is_head_request ? new WP_REST_Response() : rest_ensure_response( $results ); $response->header( 'X-WP-Total', $total ); $response->header( 'X-WP-TotalPages', $max_pages ); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php index 4ff1007237..95a24cf53e 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php @@ -119,6 +119,11 @@ class WP_REST_Sidebars_Controller extends WP_REST_Controller { * @return WP_REST_Response Response object on success. */ public function get_items( $request ) { + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } + $this->retrieve_widgets(); $data = array(); @@ -321,6 +326,12 @@ class WP_REST_Sidebars_Controller extends WP_REST_Controller { // Restores the more descriptive, specific name for use within this method. $raw_sidebar = $item; + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php */ + return apply_filters( 'rest_prepare_sidebar', new WP_REST_Response(), $raw_sidebar, $request ); + } + $id = $raw_sidebar['id']; $sidebar = array( 'id' => $id ); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php index 0b15f3494c..b7492c8150 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php @@ -113,6 +113,10 @@ class WP_REST_Taxonomies_Controller extends WP_REST_Controller { * @return WP_REST_Response Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } // Retrieve the list of registered collection query parameters. $registered = $this->get_collection_params(); @@ -210,6 +214,12 @@ class WP_REST_Taxonomies_Controller extends WP_REST_Controller { // Restores the more descriptive, specific name for use within this method. $taxonomy = $item; + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php */ + return apply_filters( 'rest_prepare_taxonomy', new WP_REST_Response(), $taxonomy, $request ); + } + $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; $fields = $this->get_fields_for_response( $request ); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php index c996894a59..dbdca57508 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php @@ -175,6 +175,11 @@ class WP_REST_Template_Autosaves_Controller extends WP_REST_Autosaves_Controller $template = _build_block_template_result_from_post( $item ); $response = $this->parent_controller->prepare_item_for_response( $template, $request ); + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + return $response; + } + $fields = $this->get_fields_for_response( $request ); $data = $response->get_data(); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php index c0bc7663e1..f88b60372b 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php @@ -200,6 +200,11 @@ class WP_REST_Template_Revisions_Controller extends WP_REST_Revisions_Controller $template = _build_block_template_result_from_post( $item ); $response = $this->parent_controller->prepare_item_for_response( $template, $request ); + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + return $response; + } + $fields = $this->get_fields_for_response( $request ); $data = $response->get_data(); 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 267f40e77f..45e0d59d5b 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 @@ -269,6 +269,11 @@ class WP_REST_Templates_Controller extends WP_REST_Controller { * @return WP_REST_Response */ public function get_items( $request ) { + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } + $query = array(); if ( isset( $request['wp_id'] ) ) { $query['wp_id'] = $request['wp_id']; @@ -668,6 +673,11 @@ class WP_REST_Templates_Controller extends WP_REST_Controller { * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + return new WP_REST_Response(); + } + /* * Resolve pattern blocks so they don't need to be resolved client-side * in the editor, improving performance. diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php index 455c83a68d..d927ba5e04 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php @@ -312,6 +312,14 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { $prepared_args = array_merge( $prepared_args, $taxonomy_obj->args ); } + $is_head_request = $request->is_method( 'HEAD' ); + if ( $is_head_request ) { + // Force the 'fields' argument. For HEAD requests, only term IDs are required. + $prepared_args['fields'] = 'ids'; + // Disable priming term meta for HEAD requests to improve performance. + $prepared_args['update_term_meta_cache'] = false; + } + /** * Filters get_terms() arguments when querying terms via the REST API. * @@ -354,14 +362,15 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { $total_terms = 0; } - $response = array(); - - foreach ( $query_result as $term ) { - $data = $this->prepare_item_for_response( $term, $request ); - $response[] = $this->prepare_response_for_collection( $data ); + if ( ! $is_head_request ) { + $response = array(); + foreach ( $query_result as $term ) { + $data = $this->prepare_item_for_response( $term, $request ); + $response[] = $this->prepare_response_for_collection( $data ); + } } - $response = rest_ensure_response( $response ); + $response = $is_head_request ? new WP_REST_Response() : rest_ensure_response( $response ); // Store pagination values for headers. $per_page = (int) $prepared_args['number']; @@ -887,6 +896,12 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { */ public function prepare_item_for_response( $item, $request ) { + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ + return apply_filters( "rest_prepare_{$this->taxonomy}", new WP_REST_Response(), $item, $request ); + } + $fields = $this->get_fields_for_response( $request ); $data = array(); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php index fd2f061171..3995bd1816 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php @@ -355,6 +355,12 @@ class WP_REST_Users_Controller extends WP_REST_Controller { } $prepared_args['search'] = '*' . $prepared_args['search'] . '*'; } + + $is_head_request = $request->is_method( 'HEAD' ); + if ( $is_head_request ) { + // Force the 'fields' argument. For HEAD requests, only user IDs are required. + $prepared_args['fields'] = 'id'; + } /** * Filters WP_User_Query arguments when querying users via the REST API. * @@ -369,14 +375,16 @@ class WP_REST_Users_Controller extends WP_REST_Controller { $query = new WP_User_Query( $prepared_args ); - $users = array(); + if ( ! $is_head_request ) { + $users = array(); - foreach ( $query->get_results() as $user ) { - $data = $this->prepare_item_for_response( $user, $request ); - $users[] = $this->prepare_response_for_collection( $data ); + foreach ( $query->get_results() as $user ) { + $data = $this->prepare_item_for_response( $user, $request ); + $users[] = $this->prepare_response_for_collection( $data ); + } } - $response = rest_ensure_response( $users ); + $response = $is_head_request ? new WP_REST_Response() : rest_ensure_response( $users ); // Store pagination values for headers then unset for count query. $per_page = (int) $prepared_args['number']; @@ -1021,6 +1029,12 @@ class WP_REST_Users_Controller extends WP_REST_Controller { // Restores the more descriptive, specific name for use within this method. $user = $item; + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php */ + return apply_filters( 'rest_prepare_user', new WP_REST_Response(), $user, $request ); + } + $fields = $this->get_fields_for_response( $request ); $data = array(); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php index d70e524411..cd0aef0c87 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php @@ -145,6 +145,11 @@ class WP_REST_Widget_Types_Controller extends WP_REST_Controller { * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } + $data = array(); foreach ( $this->get_widgets() as $widget ) { $widget_type = $this->prepare_item_for_response( $widget, $request ); @@ -298,6 +303,12 @@ class WP_REST_Widget_Types_Controller extends WP_REST_Controller { // Restores the more descriptive, specific name for use within this method. $widget_type = $item; + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php */ + return apply_filters( 'rest_prepare_widget_type', new WP_REST_Response(), $widget_type, $request ); + } + $fields = $this->get_fields_for_response( $request ); $data = array( 'id' => $widget_type['id'], diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php index f2d17186b6..2a154693a1 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php @@ -136,6 +136,11 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { * @return WP_REST_Response Response object. */ public function get_items( $request ) { + if ( $request->is_method( 'HEAD' ) ) { + // Return early as this handler doesn't add any response headers. + return new WP_REST_Response(); + } + $this->retrieve_widgets(); $prepared = array(); @@ -678,6 +683,12 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { } $widget = $wp_registered_widgets[ $widget_id ]; + // Don't prepare the response body for HEAD requests. + if ( $request->is_method( 'HEAD' ) ) { + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php */ + return apply_filters( 'rest_prepare_widget', new WP_REST_Response(), $widget, $request ); + } + $parsed_id = wp_parse_widget_id( $widget_id ); $fields = $this->get_fields_for_response( $request ); diff --git a/wp-includes/version.php b/wp-includes/version.php index 0eb846c57d..494835a94a 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.8-alpha-59898'; +$wp_version = '6.8-alpha-59899'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.