REST API Team Update (4.7 week 7)

Our two (pt1) part (pt2) (split due to team travel) weekly meeting is now complete, and we have some new updates from the API team!

Team review & commentary is requested on “Open Questions on Settings” and “Open Questions on Meta”, below.

Settings

This Pull Request for adding Settings support to the API, resolving one of the few remaining major content gaps in the API, is almost ready to be merged into the rest-api feature plugin. Settings are exposed as keys on the resource `/wp/v2/settings`, e.g.:

{
    title: 'WordPress Develop',
    description: 'Just another WordPress site',
    url: 'http://src.wordpress-develop.dev',
    email: 'admin@local.dev',
    timezone: '',
    date_format: 'F j, Y',
    time_format: 'g:i a',
    start_of_week: 1,
    language: 'en_US',
    use_smilies: true,
    default_category: 1,
    default_post_format: '0',
    posts_per_page: 10
}

This resource is only accessible or modifiable if you are authenticated as a user with the `manage_options` capability.

Open Questions on Settings

Team feedback is requested on the below, and on the settings proposal in general.

  1. What do we do if a setting value in the database does not match the type used in `register_setting`?
    • This becomes a problem when there is serialized data in the `option` value. Right now we are forcing this to be a `null` value in the rest api responses. The problem with this approach is that sending that response data back to the settings endpoint will cause the deletion of that option value (as `null` in this case is essentially a delete operation).
  2. Having support for `object` recursion and `array` types in the Schema would be very nice, allowing settings that are either objects or arrays.
    • We propose that does not need to be resolved prior to merge, and may be added in a subsequent cycle.
  3. Currently, reading all options at `/wp/v2/settings` is behind a `manage_options` cap check: we need to work out if we want to publicly expose option values for some settings.
    • If we do this, we’d need a way in `register_setting` (or via some kind of `read_setting` meta cap) to work out which settings should be exposed publicly (or at specific permissions checks).
    • Site title and description are still available on the root `/wp-json/` resource index; several other settings here can be inferred from other responses or site content. We propose that this resource be left as requiring `manage_options` caps, and move establishing a mechanism in core to register a setting as public be handled in a subsequent development cycle.

Setting Registration

For your settings to be exposed in the REST API, you need to register them. WordPress includes a register_setting function which is not usually required to get/set options, but is required for API support.

To register your field, simply call register_setting and set the show_in_rest flag to true.

register_setting( 'group', 'option_name', array(
    'show_in_rest' => true,
));

register_setting Arguments

register_setting is part of WordPress core, but isn’t heavily used in most parts of core, so you may not have seen it before. Here are the options relevant to the REST API:

  • show_in_rest – Should the setting be exposed in the API? true for default behaviour, or an array of options to override defaults (see below).
  • type – This is the type of data the setting is. Can be `string`, `number`, or `boolean` (so far).
  • description – Human-readable description of what the field is for. The API exposes this in the schema.
  • sanitize_callback – Callback to sanitize the value before it’s stored in the database. See the "sanitize_{$object_type}_meta_{$meta_key}" filter.

REST API-Specific Arguments

The show_in_rest parameter defaults to false, but can be set to true to enable API support. Out of the box, the API makes some assumptions about your setting, but you can override these by setting show_in_rest to an options array instead:

register_setting( 'group', 'option_name', array(
    'show_in_rest' => array(
        'name' => 'fieldname'
    )
));

The options you can set are:

  • name – The key exposed via the REST API. For example, if your setting starts with an underscore, you may want to remove this for the API.
  • default – The default value for the setting via the REST API if it’s not set in the database.
  • schema – The JSON Schema options for the field. Exposed via OPTIONS requests to the post. This is generated automatically based on other parameters, but can be specified manually if you’d like to override it.

Settings Defaults

We’d also love feedback on ticket #38176, this adds the ability to specify a default value for an option via `register_setting()`. As you can see from the above, we are currently defining the `default` value within
the `show_in_rest` options, as there’s no way to do this in the Settings API. We’d like for there to be a way to do this in core, so `get_option()` could default to the value set in `register_setting( … [ default => ‘myvalue’ ])`
when no default is specific in `get_option`.

Meta

Meta is also ready to be merged into the plugin, and also could use review from the broader WordPress team. Similar to custom post types and taxonomies, and as discussed previously, only meta that opts-in to API support is available through the REST API.

Open Questions on Meta

  1. Right now, all meta registered through the mechanism below is assumed to be visible wherever its parent object appears. Meta values registered to a public post will be visible on that post without authentication.
    • Is it acceptable to expose registered meta fields on objects in this way, where the meta visibility will match the visibility of the parent object?
  2. As described in this comment, when you have multiple of the same value stored in a meta key, it will delete all matching values. For example, if you had a meta value [ 11, 13, 13, 13, 13 ] and attempted to remove one 13, it would result in the value [ 11 ].
  • Should multiple instances of the same value be able to be stored in a `single => false` meta field?

Meta Registration

For your meta fields to be exposed in the REST API, you need to register them. WordPress includes a register_meta function which is not usually required to get/set fields, but is required for API support.

To register your field, simply call register_meta and set the show_in_rest flag to true.

register_meta( 'post', 'field_name', array(
    'show_in_rest' => true,
));

Note: register_meta must be called separately for each meta key.

register_meta Arguments

register_meta is part of WordPress core, but isn’t heavily used in most parts of core, so you may not have seen it before. Here are the options relevant to the REST API:

  • show_in_rest – Should the field be exposed in the API? true for default behaviour, or an array of options to override defaults (see below).
  • description – Human-readable description of what the field is for. The API exposes this in the schema.
  • single – Is this field singular? WordPress allows multiple values per key on a single object, but the API needs to know whether you use this functionality.
  • sanitize_callback – Callback to sanitize the value before it’s stored in the database. See the "sanitize_{$object_type}_meta_{$meta_key}" filter.
  • auth_callback – Callback to determine whether the user can write to the field. See the "auth_post_{$post_type}_meta_{$meta_key}" filter.

REST API-Specific Arguments

The show_in_rest parameter defaults to false, but can be set to true to enable API support. Out of the box, the API makes some assumptions about your meta field, but you can override these by setting show_in_rest to an options array instead:

register_meta( 'post', 'field_name', array(
    'show_in_rest' => array(
        'name' => 'fieldname'
    )
));

The options you can set are:

  • name – The key exposed via the REST API. For example, if your meta key starts with an underscore, you may want to remove this for the API.
  • schema – The JSON Schema options for the field. Exposed via OPTIONS requests to the post. This is generated automatically based on other parameters, but can be specified manually if you’d like to override it.

Using Meta over the API

Meta is added to existing resources as a new meta field. For example, to get the meta for a single post, fetch the post at /wp/v2/posts/{id}, then look in the meta field. This is a key-value map for the registered fields.

To update a field, simply send back a new value for it.

Setting a field to null will cause the value to be removed from the database. If a field has a default value set, this essentially “resets” the value to the default (although no default will be stored in the database).

For meta fields which can hold multiple values, this field will be a JSON list. Adding or removing items from the list will create or remove the corresponding values in the database.

Other Updates

  • Add a {taxonomy}_exclude query parameter to query for resources NOT IN a particular taxonomy term_id
  • Decide against supporting full tax_query functionality via filter[tax_query]
  • Defer supporting auto-draft to a future cycle, as it did not have the expected benefits and the applicability of that state to the API is not generally understood

#4-7, #rest-api