Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 229 additions & 4 deletions extending-the-rest-api/modifying-responses.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The API exposes many fields on API responses, including things you might not nee

You may only need a small amount of data, but it's important to keep in mind that the API is about exposing an interface to all clients, not just the feature you're working on. Changing responses is dangerous.

Adding fields is not dangerous, so if you need to modify data, it's much better to duplicate the field instead with your modified data. Removing fields is never encouraged; if you need to get back a smaller subset of data, work with contexts instead, and consider making your own context.
Adding fields is not dangerous, so if you need to modify data, it's much better to duplicate the field instead with your modified data. Removing fields is never encouraged; if you need to get back a smaller subset of data, use the [`_fields` parameter](https://developer.wordpress.org/rest-api/using-the-rest-api/global-parameters/#_fields) or work with contexts instead.

If you must remove fields from an existing context you should ensure that the behavior is **opt-in**, for example by providing a custom query parameter to trigger the field removal.

Expand All @@ -31,11 +31,10 @@ There are two methods which can be used to add data to WordPress REST API respon
`register_meta` is used to whitelist an existing custom meta value for access through the REST API. By setting a meta field's `show_in_rest` parameter to `true`, that field's value will be exposed on a `.meta` key in the endpoint response, and WordPress will handle setting up the callbacks for reading and writing to that meta key. This is much simpler than `register_rest_field`, with one caveat:

[alert]
Prior WordPress 4.9.8, meta fields set to `show_in_rest` using `register_meta` are registered for all objects of a given type. If one custom post type shows a meta field, all custom post types will show that meta field. As of WordPress 4.9.8 it's possible to use `register_meta` with the `object_subtype` argument that allows one to reduce the usage of the meta key to a particular post type.
Prior to WordPress 4.9.8, meta fields set to `show_in_rest` using `register_meta` are registered for all objects of a given type. If one custom post type shows a meta field, all custom post types will show that meta field. As of WordPress 4.9.8 it's possible to use `register_meta` with the `object_subtype` argument that allows one to reduce the usage of the meta key to a particular post type.
[/alert]

The disadvantage of `register_meta` is that it can only handle scalar values whereas `register_rest_field` can handle other object types as well.

Prior to WordPress 5.3, `register_meta` could only support scalar values (`string`, `integer`, `number` and `boolean`). WordPress 5.3 adds support for the `object` and `array` types.

## Adding Custom Fields to API Responses

Expand Down Expand Up @@ -141,6 +140,232 @@ $meta_args = array(
register_post_meta( 'page', 'my_meta_key', $meta_args );
```

### Object Meta Type
WordPress 5.3 adds support for using the `object` [type](https://tools.ietf.org/html/draft-zyp-json-schema-04#section-3.5) when registering meta. Importantly `object` refers to a JSON object, this is equivalent to an associative array in PHP.

When registering `object` meta, setting the `type` to `object` is not sufficient, you also need to inform WordPress of what properties to allow. This is done by writing a JSON Schema when registering the metadata.

For instance, the following code sample registers a post meta field called “release” that accepts the given JSON data.

```json
{
"meta": {
"release": {
"version": "5.2",
"artist": "Jaco"
}
}
}
```

```php
register_post_meta(
'post',
'release',
array(
'single' => true,
'type' => 'object',
'show_in_rest' => array(
'schema' => array(
'type' => 'object',
'properties' => array(
'version' => array(
'type' => 'string',
),
'artist' => array(
'type' => 'string',
),
),
),
),
)
);
```

Notice that `show_in_rest` becomes an array instead of `true` and a Json Schema is specified for the `schema` key. Each property is then listed in the `properties` array. At a minimum, each property must specify a `type`, but any JSON Schema keyword that `rest_validate_value_from_schema` understands can be used as well.

#### Additional Properties
By default, the list of properties is a strict whitelist. If a property is sent in the request that is not listed, the REST API will return an error: `your_property is not a valid property of Object.`. If you don't know the property names ahead of time the `additionalProperties` keyword can be used. `additionalProperties` accepts a JSON Schema that is used to validate the unknown properties. For instance, to enforce that any additional properties are numbers, the following code can be used.

```php
{
"meta": {
"release": {
"version": "5.2",
"artist": "Jaco",
"unknown_field": 5.3
}
}
}
```

```php
register_post_meta(
'post',
'version',
array(
'single' => true,
'type' => 'object',
'show_in_rest' => array(
'schema' => array(
'type' => 'object',
'properties' => array(
'version' => array(
'type' => 'string',
),
'artist' => array(
'type' => 'string',
),
),
'additionalProperties' => array(
'type' => 'number',
),
),
),
)
);
```

`additionalProperties` can be set to true to allow unknown properties of any format, but this is not recommended.

### Array Meta Type
WordPress 5.3 also adds support for using the `array` [type](https://tools.ietf.org/html/draft-zyp-json-schema-04#section-3.5). Importantly `array` refers to a JSON array, this is equivalent to a numeric array in PHP.

When registering `array` meta, setting the `type` to `array` is not sufficient, you need to inform WordPress of what the expected format is of the items in the array. This is done by writing a JSON Schema entry when registering the metadata.

If you do not provide this value, `register_meta` will return false and issue the following warning: `When registering an "array" meta type to show in the REST API, you must specify the schema for each array item in "show_in_rest.schema.items".`

The following code sample registers a post meta field called “projects” that contains a list of project names. It accepts the given JSON data.

```json
{
"meta": {
"projects": [
"WordPress",
"BuddyPress"
]
}
}
```

```php
register_post_meta(
'post',
'projects',
array(
'single' => true,
'type' => 'array',
'show_in_rest' => array(
'schema' => array(
'type' => 'array',
'items' => array(
'type' => 'string',
),
),
),
)
);
```

Notice that again `show_in_rest` becomes an array instead of `true` and a JSON Schema is specified for the `schema` key.
The `items` keyword is used to define the JSON schema to validate each array member against. It can be a scalar type like `string` or a complex type like `object`.

For instance, to accept the given JSON data, the following meta registration would be used.

```json
{
"meta": {
"projects": [
{
"name": "WordPress",
"website": "https://wordpress.org"
},
{
"name": "BuddyPress",
"website": "https://buddypress.org"
}
]
}
}
```

```php
register_post_meta(
'post',
'projects',
array(
'single' => true,
'type' => 'array',
'show_in_rest' => array(
'schema' => array(
'items' => array(
'type' => 'object',
'properties' => array(
'name' => array(
'type' => 'string',
),
'website' => array(
'type' => 'string',
'format' => 'uri',
),
),
),
),
),
)
);
```

[alert]The `array` type enforces that the array keys are sequential integers starting from 0. The array will be reindexed using `array_values`.[/alert]

### Non-Single Metadata

Non-single meta fields have an array of values per object, instead of one value per object. Each of those values is stored in a separate row in the meta table.

The `array` and `object` types can be used with non-single meta fields as well. For example, if the “release” meta key from earlier had `single` set to `false`, the following JSON data could be accepted.

```json
{
"meta": {
"release": [
{
"version": "5.2",
"artist": "Jaco"
},
{
"version": "5.1",
"artist": "Betty"
}
]
}
}
```

This would result in two meta database rows. The first containing `{ "version": "5.2", "artist": "Jaco" }` and the second containing `{ "version": "5.1", "artist": "Betty" }`.

Similarly, the following data would be accepted for the “projects” example if it had set `single` to `false`.

```json
{
"meta": {
"projects": [
[
"WordPress",
"BuddyPress"
],
[
"bbPress"
]
]
}
}
```

This would result in two meta database rows. The first containing `[ "WordPress", "BuddyPress" ]` and the second containing `[ "bbPress" ]`.

### Invalid Stored Values

If the existing value for a meta field does not validate against the registered type and schema, the value for that meta field will be returned as null. If that null value is passed back to the API when doing an update request, you'll receive a `rest_invalid_stored_value` error: `The %s property has an invalid stored value, and cannot be updated to null.`. To fix this, either update the meta key with a valid value or omit that property from your request.

## Adding Links to the API Response
WordPress generates a list of links associated with the queried resource to make it easier to navigate to related resources.
Expand Down