Skip to content

Commit 21ff64c

Browse files
REST API: Let routes turn off _fields, _embed and response links.
Add a `data_processing` option to REST routes and route handlers, so a route can serve its response data as returned. The option is `false` to turn off every feature, or an array with any of the `fields`, `embed` and `links` keys. Every feature is on by default, the handler setting applies over the route setting feature by feature, and turning off `links` also turns off `embed`. The settings are resolved once, when the request is matched, and stored on the request attributes, the matched handler and the response, where `rest_filter_response_fields()`, `WP_REST_Controller::get_fields_for_response()` and `WP_REST_Server::response_to_data()` read them. They apply to served, enveloped, batched and preloaded requests, and to responses returned by the `rest_pre_dispatch` filter. The index lists the settings of endpoints that turn a feature off. Response data that is not an array is now served as returned even without the option: `_fields` leaves scalars and objects alone and keeps list items that are not arrays, links are not added to them unless the object implements `ArrayAccess`, and `rest_preload_api_request()` no longer casts preloaded data to an array. This lets endpoints that own their output schema, such as the abilities run endpoint, return objects, lists and scalar values unchanged. Props jorgefilipecosta, gziolo. See #66267. Fixes #66372. Built from https://develop.svn.wordpress.org/trunk@64689 git-svn-id: http://core.svn.wordpress.org/trunk@63839 1a063a9b-81f0-0310-95a4-ce76da25c4cd
1 parent c967518 commit 21ff64c

5 files changed

Lines changed: 246 additions & 41 deletions

File tree

‎wp-includes/rest-api.php‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,8 @@ function _rest_array_intersect_key_recursive( $array1, $array2 ) {
950950
* Filters the REST API response to include only an allow-listed set of response object fields.
951951
*
952952
* @since 4.8.0
953+
* @since 7.2.0 The response is left unchanged when the route turns off the `fields` response
954+
* processing or when the response data is not an array.
953955
*
954956
* @param WP_REST_Response $response Current response being served.
955957
* @param WP_REST_Server $server ResponseHandler instance (usually WP_REST_Server).
@@ -961,8 +963,18 @@ function rest_filter_response_fields( $response, $server, $request ) {
961963
return $response;
962964
}
963965

966+
$processing = $response->get_data_processing();
967+
if ( ! $processing['fields'] ) {
968+
return $response;
969+
}
970+
964971
$data = $response->get_data();
965972

973+
// Only arrays have fields to filter.
974+
if ( ! is_array( $data ) ) {
975+
return $response;
976+
}
977+
966978
$fields = wp_parse_list( $request['_fields'] );
967979

968980
if ( 0 === count( $fields ) ) {
@@ -993,7 +1005,7 @@ function rest_filter_response_fields( $response, $server, $request ) {
9931005
if ( wp_is_numeric_array( $data ) ) {
9941006
$new_data = array();
9951007
foreach ( $data as $item ) {
996-
$new_data[] = _rest_array_intersect_key_recursive( $item, $fields_as_keyed );
1008+
$new_data[] = is_array( $item ) ? _rest_array_intersect_key_recursive( $item, $fields_as_keyed ) : $item;
9971009
}
9981010
} else {
9991011
$new_data = _rest_array_intersect_key_recursive( $data, $fields_as_keyed );
@@ -3048,7 +3060,7 @@ function rest_preload_api_request( $memo, $path ) {
30483060
/** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */
30493061
$response = apply_filters( 'rest_post_dispatch', rest_ensure_response( $response ), $server, $request );
30503062
$embed = $request->has_param( '_embed' ) ? rest_parse_embed_param( $request['_embed'] ) : false;
3051-
$data = (array) $server->response_to_data( $response, $embed );
3063+
$data = $server->response_to_data( $response, $embed );
30523064

30533065
if ( 'OPTIONS' === $method ) {
30543066
$memo[ $method ][ $path ] = array(

‎wp-includes/rest-api/class-wp-rest-response.php‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* @see WP_HTTP_Response
1616
*
1717
* @phpstan-import-type Route_Handler from WP_REST_Server
18+
* @phpstan-import-type Data_Processing from WP_REST_Server
1819
*
1920
* @phpstan-type Target_Hints array{
2021
* allow?: list<uppercase-string>,
@@ -69,6 +70,19 @@ class WP_REST_Response extends WP_HTTP_Response {
6970
*/
7071
protected $matched_handler = null;
7172

73+
/**
74+
* Whether each data processing feature is on for the response.
75+
*
76+
* @since 7.2.0
77+
* @var array<string, bool> Whether the `fields`, `embed` and `links` features are on. Every feature is on by default.
78+
* @phpstan-var Data_Processing
79+
*/
80+
protected $data_processing = array(
81+
'fields' => true,
82+
'embed' => true,
83+
'links' => true,
84+
);
85+
7286
/**
7387
* Adds a link to the response.
7488
*
@@ -249,6 +263,50 @@ public function set_matched_handler( $handler ) {
249263
$this->matched_handler = $handler;
250264
}
251265

266+
/**
267+
* Retrieves whether each data processing feature is on for the response.
268+
*
269+
* The server sets the settings of the matched route when it dispatches a request, for responses
270+
* returned by the `rest_pre_dispatch` filter too. Every feature is on until then.
271+
*
272+
* @since 7.2.0
273+
*
274+
* @see WP_REST_Server::resolve_data_processing()
275+
*
276+
* @return array<string, bool> {
277+
* Whether each data processing feature is on.
278+
*
279+
* @type bool $fields Whether the `_fields` parameter filters the response data.
280+
* @type bool $embed Whether the `_embed` parameter embeds linked resources in the response data.
281+
* @type bool $links Whether the response links are added to the response data as `_links`.
282+
* }
283+
*
284+
* @phpstan-return Data_Processing
285+
*/
286+
public function get_data_processing() {
287+
return $this->data_processing;
288+
}
289+
290+
/**
291+
* Sets whether each data processing feature is on for the response.
292+
*
293+
* The setting takes the form of the `data_processing` route option: `false` turns off every
294+
* feature, and an array turns off, or on, the features it names. Embedding needs the links, so
295+
* `embed` is off whenever `links` is off.
296+
*
297+
* @since 7.2.0
298+
*
299+
* @see WP_REST_Server::resolve_data_processing()
300+
*
301+
* @param bool|array<string, bool> $processing Whether every feature is on, or whether the `fields`, `embed`
302+
* and `links` features are on. A feature not named stays on.
303+
*
304+
* @phpstan-param bool|array{fields?: bool, embed?: bool, links?: bool} $processing
305+
*/
306+
public function set_data_processing( $processing ) {
307+
$this->data_processing = WP_REST_Server::resolve_data_processing( array( 'data_processing' => $processing ) );
308+
}
309+
252310
/**
253311
* Checks if the response is an error, i.e. >= 400 response code.
254312
*

0 commit comments

Comments
 (0)