Skip to content
16 changes: 14 additions & 2 deletions src/wp-includes/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,8 @@ function _rest_array_intersect_key_recursive( $array1, $array2 ) {
* Filters the REST API response to include only an allow-listed set of response object fields.
*
* @since 4.8.0
* @since 7.2.0 The response is left unchanged when the route turns off the `fields` response
* processing or when the response data is not an array.
*
* @param WP_REST_Response $response Current response being served.
* @param WP_REST_Server $server ResponseHandler instance (usually WP_REST_Server).
Expand All @@ -961,8 +963,18 @@ function rest_filter_response_fields( $response, $server, $request ) {
return $response;
}

$processing = $response->get_data_processing();
if ( ! $processing['fields'] ) {
return $response;
}

$data = $response->get_data();

// Only arrays have fields to filter.
if ( ! is_array( $data ) ) {
return $response;
}

$fields = wp_parse_list( $request['_fields'] );

if ( 0 === count( $fields ) ) {
Expand Down Expand Up @@ -993,7 +1005,7 @@ function rest_filter_response_fields( $response, $server, $request ) {
if ( wp_is_numeric_array( $data ) ) {
$new_data = array();
foreach ( $data as $item ) {
$new_data[] = _rest_array_intersect_key_recursive( $item, $fields_as_keyed );
$new_data[] = is_array( $item ) ? _rest_array_intersect_key_recursive( $item, $fields_as_keyed ) : $item;
}
} else {
$new_data = _rest_array_intersect_key_recursive( $data, $fields_as_keyed );
Expand Down Expand Up @@ -3048,7 +3060,7 @@ function rest_preload_api_request( $memo, $path ) {
/** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */
$response = apply_filters( 'rest_post_dispatch', rest_ensure_response( $response ), $server, $request );
$embed = $request->has_param( '_embed' ) ? rest_parse_embed_param( $request['_embed'] ) : false;
$data = (array) $server->response_to_data( $response, $embed );
$data = $server->response_to_data( $response, $embed );

if ( 'OPTIONS' === $method ) {
$memo[ $method ][ $path ] = array(
Expand Down
58 changes: 58 additions & 0 deletions src/wp-includes/rest-api/class-wp-rest-response.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* @see WP_HTTP_Response
*
* @phpstan-import-type Route_Handler from WP_REST_Server
* @phpstan-import-type Data_Processing from WP_REST_Server
*
* @phpstan-type Target_Hints array{
* allow?: list<uppercase-string>,
Expand Down Expand Up @@ -69,6 +70,19 @@ class WP_REST_Response extends WP_HTTP_Response {
*/
protected $matched_handler = null;

/**
* Whether each data processing feature is on for the response.
*
* @since 7.2.0
* @var array<string, bool> Whether the `fields`, `embed` and `links` features are on. Every feature is on by default.
* @phpstan-var Data_Processing
*/
protected $data_processing = array(
'fields' => true,
'embed' => true,
'links' => true,
);

/**
* Adds a link to the response.
*
Expand Down Expand Up @@ -249,6 +263,50 @@ public function set_matched_handler( $handler ) {
$this->matched_handler = $handler;
}

/**
* Retrieves whether each data processing feature is on for the response.
*
* The server sets the settings of the matched route when it dispatches a request, for responses
* returned by the `rest_pre_dispatch` filter too. Every feature is on until then.
*
* @since 7.2.0
*
* @see WP_REST_Server::resolve_data_processing()
*
* @return array<string, bool> {
* Whether each data processing feature is on.
*
* @type bool $fields Whether the `_fields` parameter filters the response data.
* @type bool $embed Whether the `_embed` parameter embeds linked resources in the response data.
* @type bool $links Whether the response links are added to the response data as `_links`.
* }
*
* @phpstan-return Data_Processing
*/
public function get_data_processing() {
return $this->data_processing;
}

/**
* Sets whether each data processing feature is on for the response.
*
* The setting takes the form of the `data_processing` route option: `false` turns off every
* feature, and an array turns off, or on, the features it names. Embedding needs the links, so
* `embed` is off whenever `links` is off.
*
* @since 7.2.0
*
* @see WP_REST_Server::resolve_data_processing()
*
* @param bool|array<string, bool> $processing Whether every feature is on, or whether the `fields`, `embed`
* and `links` features are on. A feature not named stays on.
*
* @phpstan-param bool|array{fields?: bool, embed?: bool, links?: bool} $processing
*/
public function set_data_processing( $processing ) {
$this->data_processing = WP_REST_Server::resolve_data_processing( array( 'data_processing' => $processing ) );
}

/**
* Checks if the response is an error, i.e. >= 400 response code.
*
Expand Down
Loading
Loading