Make WordPress Core


Ignore:
Timestamp:
09/17/2024 09:50:38 PM (8 months ago)
Author:
TimothyBlynJacobs
Message:

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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/class-wp-rest-server.php

    r58688 r59032  
    637637                $attributes         = $item['attributes'];
    638638                $attributes['href'] = $item['href'];
    639                 $data[ $rel ][]     = $attributes;
     639
     640                if ( 'self' !== $rel ) {
     641                    $data[ $rel ][] = $attributes;
     642                    continue;
     643                }
     644
     645                $target_hints = self::get_target_hints_for_link( $attributes );
     646                if ( $target_hints ) {
     647                    $attributes['targetHints'] = $target_hints;
     648                }
     649
     650                $data[ $rel ][] = $attributes;
    640651            }
    641652        }
    642653
    643654        return $data;
     655    }
     656
     657    /**
     658     * Gets the target links for a REST API Link.
     659     *
     660     * @since 6.7.0
     661     *
     662     * @param array $link
     663     *
     664     * @return array|null
     665     */
     666    protected static function get_target_hints_for_link( $link ) {
     667        // Prefer targetHints that were specifically designated by the developer.
     668        if ( isset( $link['targetHints']['allow'] ) ) {
     669            return null;
     670        }
     671
     672        $request = WP_REST_Request::from_url( $link['href'] );
     673        if ( ! $request ) {
     674            return null;
     675        }
     676
     677        $server = rest_get_server();
     678        $match  = $server->match_request_to_handler( $request );
     679
     680        if ( is_wp_error( $match ) ) {
     681            return null;
     682        }
     683
     684        if ( is_wp_error( $request->has_valid_params() ) ) {
     685            return null;
     686        }
     687
     688        if ( is_wp_error( $request->sanitize_params() ) ) {
     689            return null;
     690        }
     691
     692        $target_hints = array();
     693
     694        $response = new WP_REST_Response();
     695        $response->set_matched_route( $match[0] );
     696        $response->set_matched_handler( $match[1] );
     697        $headers = rest_send_allow_header( $response, $server, $request )->get_headers();
     698
     699        foreach ( $headers as $name => $value ) {
     700            $name = WP_REST_Request::canonicalize_header_name( $name );
     701
     702            $target_hints[ $name ] = array_map( 'trim', explode( ',', $value ) );
     703        }
     704
     705        return $target_hints;
    644706    }
    645707
Note: See TracChangeset for help on using the changeset viewer.