Commit b4acb10706 for wordpress.org

commit b4acb1070651ebed42349bd05d66179dd58301e6
Author: TimothyBlynJacobs <TimothyBlynJacobs@git.wordpress.org>
Date:   Tue Sep 17 21:52:20 2024 +0000

    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

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.