From b4acb1070651ebed42349bd05d66179dd58301e6 Mon Sep 17 00:00:00 2001 From: TimothyBlynJacobs Date: Tue, 17 Sep 2024 21:52:20 +0000 Subject: [PATCH] REST API: Automatically populate targetHints for the Allow header. The REST API uses the "Allow" header to communicate what methods a user is authorized to perform on a resource. This works great when operating on a single item route, but can break down when needing to determine authorization over a collection of items. This commit uses the "targetHints" property of JSON Hyper Schema to provide access to the "allow" header for "self" links. This alleviates needing to make a separate network request for each item in a collection. Props mamaduka, noisysocks, peterwilsoncc, spacedmonkey, swissspidy, timothyblynjacobs, tyxla, youknowriad. Fixes #61739. Built from https://develop.svn.wordpress.org/trunk@59032 git-svn-id: http://core.svn.wordpress.org/trunk@58428 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/rest-api/class-wp-rest-server.php | 64 ++++++++++++++++++- wp-includes/version.php | 2 +- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/wp-includes/rest-api/class-wp-rest-server.php b/wp-includes/rest-api/class-wp-rest-server.php index 0eedb0396b..17d620f6fb 100644 --- a/wp-includes/rest-api/class-wp-rest-server.php +++ b/wp-includes/rest-api/class-wp-rest-server.php @@ -636,13 +636,75 @@ class WP_REST_Server { foreach ( $items as $item ) { $attributes = $item['attributes']; $attributes['href'] = $item['href']; - $data[ $rel ][] = $attributes; + + if ( 'self' !== $rel ) { + $data[ $rel ][] = $attributes; + continue; + } + + $target_hints = self::get_target_hints_for_link( $attributes ); + if ( $target_hints ) { + $attributes['targetHints'] = $target_hints; + } + + $data[ $rel ][] = $attributes; } } return $data; } + /** + * Gets the target links for a REST API Link. + * + * @since 6.7.0 + * + * @param array $link + * + * @return array|null + */ + protected static function get_target_hints_for_link( $link ) { + // Prefer targetHints that were specifically designated by the developer. + if ( isset( $link['targetHints']['allow'] ) ) { + return null; + } + + $request = WP_REST_Request::from_url( $link['href'] ); + if ( ! $request ) { + return null; + } + + $server = rest_get_server(); + $match = $server->match_request_to_handler( $request ); + + if ( is_wp_error( $match ) ) { + return null; + } + + if ( is_wp_error( $request->has_valid_params() ) ) { + return null; + } + + if ( is_wp_error( $request->sanitize_params() ) ) { + return null; + } + + $target_hints = array(); + + $response = new WP_REST_Response(); + $response->set_matched_route( $match[0] ); + $response->set_matched_handler( $match[1] ); + $headers = rest_send_allow_header( $response, $server, $request )->get_headers(); + + foreach ( $headers as $name => $value ) { + $name = WP_REST_Request::canonicalize_header_name( $name ); + + $target_hints[ $name ] = array_map( 'trim', explode( ',', $value ) ); + } + + return $target_hints; + } + /** * Retrieves the CURIEs (compact URIs) used for relations. * diff --git a/wp-includes/version.php b/wp-includes/version.php index d5aa4e8bb6..a7e3a9ed79 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.7-alpha-59031'; +$wp_version = '6.7-alpha-59032'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.