New and modified REST API endpoints in WordPress 5.5

In WordPress 5.5, a handful of entirely new REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/. endpoints have been introduced and several others will see new features or enhancements. Let’s look at a breakdown of these changes.

BlockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. Types

In [48173] REST API endpoints were introduced to return all of the block types registered on the server.

  • GET /wp/v2/block-types will return all registered block types.
  • GET /wp/v2/block-types/core will return all blocks within the core namespace.
  • GET /wp/v2/block-types/core/quote will return the definition specifically for the coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. quote block.

This endpoint is accessible to users that have edit permission for any post type that is included in the REST API. In other words, if the user can edit posts in the Block Editor, they can access the block types endpoint.

Response Format

The response format for this endpoint closely follows the Block Type Registration RFC. The JSON Schema documents the full response type. The following is an example of that in practice for the core/quote block.

{
  "attributes": {
    "value": {
      "type": "string",
      "source": "html",
      "selector": "blockquote",
      "multiline": "p",
      "default": ""
    },
    "citation": {
      "type": "string",
      "source": "html",
      "selector": "cite",
      "default": ""
    },
    "align": {
      "type": "string"
    }
  },
  "is_dynamic": false,
  "name": "core/quote",
  "title": "",
  "description": "",
  "icon": null,
  "category": "text",
  "keywords": [],
  "parent": null,
  "provides_context": [],
  "uses_context": [],
  "supports": {
    "anchor": true
  },
  "styles": [],
  "textdomain": null,
  "example": null,
  "editor_script": null,
  "script": null,
  "editor_style": null,
  "style": null
}

For more information, refer to the relevant ticketticket Created for both bug reports and feature development on the bug tracker. on TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. (#48173).

Plugins

In [48242] REST API endpoints were introduced for managing plugins. These endpoints facilitate the Block Directory Inserter feature in the block editor.

  • GET /wp/v2/plugins will return a list of all plugins installed on a site.
  • GET /wp/v2/plugins/akismet/akismet will return information about the installed Akismet pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party. The first akismet refers to the plugin’s folder, the second akismet is the main plugin file without the .php file extension.
  • POST /wp/v2/plugins { slug: "akismet" } installs the plugin with the slug aksimet from the WordPress.orgWordPress.org The community site where WordPress code is created and shared by the users. This is where you can download the source code for WordPress core, plugins and themes as well as the central location for community conversations and organization. https://wordpress.org/ plugin directory. The endpoint does not support uploading a plugin zip.
  • PUT /wp/v2/plugins/akismet/akismet { status: "active" } activates the selected plugin. The status can be set to network-active to networknetwork (versus site, blog) activate the plugin on Multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site. To deactivate the plugin set the status to inactive. There is not a separate network-inactive status, inactive will perform a network deactivation if the plugin was network activated.
  • DELETE /wp/v2/plugins/akismet/akismet uninstalls the selected plugin. The plugin must be inactive before deleting it.

The endpoint is accessible to authenticated users with the activate_plugins capability. Specific actions have their own additional permission checks. For instance, the install_plugins capability is required to install new plugins.

Response Format

The JSON Schema for the endpoint documents the full response type. The following is an example for the Akismet plugin.

{
  "plugin": "akismet/akismet",
  "status": "inactive",
  "name": "Akismet Anti-Spam",
  "plugin_uri": "https://akismet.com/",
  "author": "Automattic",
  "author_uri": "https://automattic.com/wordpress-plugins/",
  "description": {
    "raw": "Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. It keeps your site protected even while you sleep. To get started: activate the Akismet plugin and then go to your Akismet Settings page to set up your API key.",
    "rendered": "Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. It keeps your site protected even while you sleep. To get started: activate the Akismet plugin and then go to your Akismet Settings page to set up your API key. <cite>By <a href=\"https://automattic.com/wordpress-plugins/\">Automattic</a>.</cite>"
  },
  "version": "4.1.6",
  "network_only": false,
  "requires_wp": "",
  "requires_php": "",
  "text_domain": "akismet"
}

For more information, refer to the relevant ticket on Trac (#50321).

Block Directory

The [48242] changeset also introduced an endpoint for searching the WordPress.org block directory.

GET /wp/v2/block-directory/search?term=starscape searches for blocks that match the term starscape.

This endpoint requires both the activate_plugins and install_plugins capabilities.

Response Format

The JSON Schema for the endpoint documents the full response type. The following is an example for the Starscape block.

{
  "name": "a8c/starscape",
  "title": "Starscape Block",
  "description": "Everything was made of collapsing stars, we are all made of star stuff. Now we also can create content in WordPress with stars in motion. Requirements As this is part...",
  "id": "starscape",
  "rating": 0,
  "rating_count": 0,
  "active_installs": 10,
  "author_block_rating": 0,
  "author_block_count": 1,
  "author": "Automattic",
  "icon": "https://ps.w.org/starscape/assets/icon.svg?rev=2232475",
  "assets": [
    "https://ps.w.org/starscape/tags/1.0.2/index.js?v=1591313160",
    "https://ps.w.org/starscape/tags/1.0.2/editor.css?v=1591313160",
    "https://ps.w.org/starscape/tags/1.0.2/style.css?v=1591313160"
  ],
  "last_updated": "2020-06-04T23:26:00",
  "humanized_updated": "1 month ago",
  "_links": {
    "wp:install-plugin": [
      {
        "href": "http://trunk.test/wp-json/wp/v2/plugins?slug=starscape"
      }
    ]
  }
}

For more information, refer to the relevant ticket on Trac (#50321).

Image Editing

In [48291] an endpoint was introduced for editing image attachments in the media library. This facilitates the inline image editing feature in the block editor.

POST /wp/v2/media/5/edit edits the image with id 5. This rotates the image 90 degrees, and then zooms the image to 80% of its original height and width into the top-left corner.

{
  "x": 0,
  "y": 0,
  "width": 80,
  "height": 80,
  "rotate": 90
}

Notes: width and height only supports percentage values. x & y specify the crop starting point.

This endpoint requires permission to edit the original attachment as well as the upload_files capability. The endpoint returns the newly created attachment.

For more information, refer to the relevant ticket on Trac (#44405).

Block Renderer

Every block has a different set of attributes. These attributes are specified as a JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. Schema object. Previously, every block registered its own block renderer route using its attributes for the schema. This allowed for the attributes to be validated using the built in endpoint validation rules.

However, this approach had the unfortunate side effect of creating a large number of nearly identical REST API routes (one for each dynamic block). Each registered route has a performance impact. As the number of server side blocks goes up, this becomes more and more of an issue.

In [48069], the block renderer route was changed to register a single block renderer route and dynamically validate the attributes based on the selected block. This is an internal only change, consumers of the block renderer endpoint shouldn’t notice any changes. The same request format continues to work.

However, this means the attributes schema for a block can no longer be fetched by making an OPTIONS request to the block renderer endpoint. The new block types endpoint should be used instead.

In [47756] support for the POST request method was added to the block renderer. This allows a block to be rendered that has attributes larger than would be allowed in the URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org.

For more information, refer to the tickets on Trac (#49680 and #48079).

Themes

In [47921], support for returning the majority of a theme’s headerHeader The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitor’s opinion about your content and you/ your organization’s brand. It may also look different on different screen sizes. information from its public style.css file was added to the /wp/v2/themes endpoint. Previously, only the theme’s supported features were returned.

For example, Twenty Twenty now produces the following response:

{
  "stylesheet": "twentytwenty",
  "template": "twentytwenty",
  "requires_php": "5.2.4",
  "requires_wp": "4.7",
  "textdomain": "twentytwenty",
  "version": "1.4",
  "screenshot": "http://trunk.test/wp-content/themes/twentytwenty/screenshot.png",
  "author": {
    "raw": "the WordPress team",
    "rendered": "<a href=\"https://wordpress.org/\">the WordPress team</a>"
  },
  "author_uri": {
    "raw": "https://wordpress.org/",
    "rendered": "https://wordpress.org/"
  },
  "description": {
    "raw": "Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor. ",
    "rendered": "Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor."
  },
  "name": {
    "raw": "Twenty Twenty",
    "rendered": "Twenty Twenty"
  },
  "tags": {
    "raw": [
      "blog",
      "one-column",
      "custom-background",
      "custom-colors",
      "custom-logo",
      "custom-menu"
    ],
    "rendered": "blog, one-column, custom-background, custom-colors, custom-logo, custom-menu"
  },
  "theme_uri": {
    "raw": "https://wordpress.org/themes/twentytwenty/",
    "rendered": "https://wordpress.org/themes/twentytwenty/"
  },
  "theme_supports": {}
}

Currently, themes can declare support for a given feature by using add_theme_support(). In [48171], the register_theme_feature APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. was introduced that allows WordPress Core and plugins to declare a list of available features that themes can support.

The REST API uses this to expose a theme’s supported features if the feature has been registered with show_in_rest set to true.

As a reminder, the themes endpoint is available to any users who can edit a post type that is visible in the REST API. In other words, if a user can use the Block Editor, they can access this information.

For more information, refer to the relevant tickets on Trac (#49906 and #49406).

Props @desrosj and @justinahinon for reviewing.

#5-5, #dev-notes, #rest-api

REST API Parameter & JSON Schema changes in WordPress 5.5

WordPress 5.5 introduces a number of new features and changes to how request and response parameters are handled, particularly around JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. Schema features.

General

Support more JSON Schemas when filtering a response by context

The REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/. uses context to remove fields from a response if the user does not have adequate permissions or for performance reasons. For example, in the following schema, if the user requested the resource with context=view, only the name properties would be returned.

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "context": [ "view", "edit" ]
    },
    "role": {
      "type": "string",
      "context": [ "edit" ]
    }
  }
}

In [47758], support was added for removing more properties from a response if additional features were in use. The array type, multi-types, and the additionalProperties keyword are now supported. Additionally, the filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. recurses to an infinite depth.

So for the following schema, if the resource was requested with context=view the following fields would be returned.

{
  "type": "object",
  "properties": {
    "notes": {
      "context": [ "view", "edit" ],
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "note": {
            "context": [ "view", "edit" ],
            "type": "string"
          },
          "ip": {
            "context": [ "edit" ],
            "type": "string"
          }
        }
      }
    }
  }
}

Note that the ip field has been omitted.

{
  "notes": [
    {
      "note": "My Note"
    }
  ]
}

For more information, see #48819 on TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress..

Inconsistent parameter type handling in WP_REST_Request::set_param()

Previously, when parameters were manually added to a WP_REST_Request object using set_param(), the parameter was added into the first available parameter slot. This could be unexpected if a parameter was already in another parameter slot and you were trying to overwrite the value.

In [47559], this changed to first look for an existing parameter, and then falls back to the first parameter in the order if none was found.

For more information, refer to the relevant Trac ticketticket Created for both bug reports and feature development on the bug tracker. (#40838).

WP_REST_Controller::get_endpoint_args_for_item_schema drops some keywords

The primary mechanism for developers to declare the parameters an endpoint accepts is by writing a JSON Schema in WP_REST_Controller::get_item_schema(). The schema is then transformed into the args format by using WP_REST_Controller::get_endpoint_args_for_item_schema() during route registration. This transformation process dropped the minimum, maximum, exclusiveMinimum, and exclusiveMaximum JSON Schema keywords. This list of allowed keywords was updated in [47911] to ensure this doesn’t happen.

For more information, check out #50301 on Trac.

Check required properties are provided when validating an object

Previously, the REST API would validate that all parameters with the required attribute were provided in WP_REST_Request::has_valid_params. This meant that if an object was defined with its own set of required parameters, it was not checked by the default parameter validator.

So, for instance, given the following schema, the request would be accepted despite the missing version field.

{
  "type": "object",
  "properties": {
    "fixed_in": {
      "required": true,
      "type": "object",
      "properties": {
        "revision": {
          "required": true,
          "type": "integer"
        },
        "version": {
          "required": true,
          "type": "string"
        }
      }
    }
  }
}
{
  "fixed_in": {
    "revision": 47809
  }
}

In [47809] this was fixed to now generate a rest_property_required error.

Version 4 syntax

This change also adds support for JSON Schema Version 4 required-property syntax where the list of required properties for an object is defined as an array of property names. This can be particularly helpful when specifying that a metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. value has a list of required properties.

Given the following meta field.

register_post_meta( 'post', 'fixed_in', array(
	'type'         => 'object',
	'show_in_rest' => array(
		'single' => true,
		'schema' => array(
			'required'   => array( 'revision', 'version' ),
			'type'       => 'object',
			'properties' => array(
				'revision' => array(
					'type' => 'integer',
				),
				'version'  => array(
					'type' => 'string',
				),
			),
		),
	),
) );

And the following request object.

{
	"title": "Check required properties",
	"content": "We should check that required properties are provided",
	"meta": {
		"fixed_in": {
			"revision": 47089
		}
	}
}

The following error will be returned.

{
  "code": "rest_property_required",
  "message": "version is a required property of meta.fixed_in.",
  "data": {
    "status": 400
  }
}

If the fixed_in meta field was omitted entirely, no error would be generated. An object that defines a list of required properties does not indicate that the object itself is required to be submitted. Just that if the object is included, that the listed properties must also be included as well.

Specifying the required properties in the top-level schema for an endpoint using a required array is not supported. Given the following schema, a user could successfully submit a request without the title or content properties. This is because, as discussed earlier, the schema document is not itself used for validation, but instead transformed to a list of parameter definitions.

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "my-endpoint",
  "type": "object",
  "required": [ "title", "content" ],
  "properties": {
    "title": {
      "type": "string"
    },
    "content": {
      "type": "string"
    }
  }
}

For more information, refer to #48818 on Trac.

Make multi-typed schemas more robust

A multi-type schema is a schema where the type keyword is an array of possible types instead of a single type. For instance, [ 'object', 'string' ] would allow objects or string values.

In [46249] basic support for these schemas was introduced. The validator would loopLoop The Loop is PHP code used by WordPress to display posts. Using The Loop, WordPress processes each post to be displayed on the current page, and formats it according to how it matches specified criteria within The Loop tags. Any HTML or PHP code in the Loop will be processed on each post. https://codex.wordpress.org/The_Loop. over each schema type trying to find a version that matched. This worked for valid values, but for invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid. values it provided unhelpful error messages. The sanitizer also had its utility restricted.

In [48306], the validators and sanitizers will now first determine the best type of the passed value and then apply the schema with that set type. In the case that a value could match multiple types, the schema of the first matching type will be used.

So, for instance, given the following schema, if the value 40 was submitted for the parameter, the user would receive param must be between 10 (inclusive) and 20 (inclusive) as an error message instead of param is not of type null,integer.

{
  "type": [ "null", "integer" ],
  "minimum": 10,
  "maximum": 20
}

Correct rest_sanitize_value_from_schema return type

The return type of rest_sanitize_value_from_schema has been corrected in [48307] to be mixed|WP_Error. Previously, the function had been documented as returning true|WP_Error.

Though WP_Error was a documented return type, it would not have been returned before WordPress 5.5. The function now returns a WP_Error if the value cannot be safely sanitized. For instance when checking the uniqueItems keyword.

New Keywords

WordPress 5.5 adds support for a number of JSON Schema keywords.

Pattern

The JSON Schema keyword pattern can be used to validate that a string field matches a regular expression.

For instance, given the following schema, #123 would be valid, but #abc would not.

{
  "type": "string",
  "pattern": "#[0-9]+"
}

The regex is not automatically anchored. Regex flags, for instance /i to make the match case insensitive are not supported. Developers are advised to use a constrained set of regex features so the schema can be interoperable between JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/. and PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher. The pattern should be valid according to the ECMA 262 regex dialect.

Relevant changeset: [47810].

Min and max string length

The minLength and maxLength keywords can be used to constrain the acceptable length of a string. Importantly multi-byte characters are counted as a single character and bounds are inclusive.

For instance, given the following schema, ab, abc, and abcd are valid, while a, and abcde are invalid.

{
  "type": "string",
  "minLength": 2,
  "maxLength": 4
}

The exclusiveMinimum and exclusiveMaximum keywords do not apply, they are only valid for numbers.

Relevant changeset: [47627].

Min and max array items

The minItems and maxItems keywords can be used to constrain the acceptable number of items included in an array.

For instance, given the following schema, [ 'a' ] and [ 'a', 'b' ] are valid, while [] and [ 'a', 'b', 'c' ] are invalid.

{
  "type": "array",
  "minItems": 1,
  "maxItems": 2,
  "items": {
    "type": "string"
  }
}

Again, the exclusiveMinimum and exclusiveMaximum keywords do not apply.

Relevante changeset: [47923].

Unique items

The uniqueItems keyword can be used to require that all items in an array are unique.

For instance, given the following schema, [ 'a', 'b' ] is valid, while [ 'a', 'a' ] is not.

{
  "type": "array",
  "uniqueItems": true,
  "items": {
    "type": "string"
  }
}

Uniqueness

Items of different types are considered unique, for instance, '1', 1 and 1.0 are different values.

When arrays are compared, the order of items matters. So the given array is considered to have all unique items.

[
  [ "a", "b" ],
  [ "b", "a" ]
]

When objects are compared, the order the members appear in does not matter. So the given array is considered to have duplicate items since the values are the same, they just appear in a different order.

[
  { 
    "a": 1,
    "b": 2
  },
  {
    "b": 2,
    "a": 1
  }
]

Uniqueness is checked in both rest_validate_value_from_schema and rest_sanitize_value_from_schema. This is to prevent instances where items would be considered unique before sanitization is applied, but after sanitization the items would converge to identical values.

Take for instance the following schema:

{
  "type": "array",
  "uniqueItems": true,
  "items": {
    "type": "string",
    "format": "uri"
  }
}

A request with [ "https://example.org/hello world", "https://example.org/hello%20world" ] would pass validation because the each string value is different. However, after esc_url_raw converted the space in the first url to %20 the values would be identical.

In this case rest_sanitize_value_from_schema would return an error. As such, developers are advised to always validate and sanitize parameters.

For more information, see #48821 on Trac.

Format Changes

A couple of changes have been made to handling of the format keyword.

Only validate the format keyword if the type is a string

Previously, implementing multi-type fields that had a format keyword required disabling the default validate & sanitize callbacks. After [48300] this can now be expressed entirely in JSON Schema.

For instance, given the following schema, a user can now submit both https://example.org/hello world and { "link": "https://example.org/hello world" } and validation & sanitization will be properly applied in both cases.

{
  "type": [ "string", "object" ],
  "properties": {
    "link": {
      "type": "string",
      "format": "uri"
    },
    "label": {
      "type": "string"
    }
  },
  "format": "uri"
}

For backward compatibility with invalid schemas the format validation will still apply if the type is not specified, or it is invalid.

Miscellaneous changes

  • The hex-color format has been introduced. This enforces a 3 or 6 hex digit color with a leading (see #49270).
  • The uuid format has been introduced. This enforces a uuid of any version using the wp_is_uuid function (see #50053).
  • The rest_validate_value_from_schema and rest_sanitize_value_from_schema functions will now issue _doing_it_wrong notices if the type keyword is missing or contains invalid values. The following types are valid: object, array, string, number, integer, boolean, and null (see #48821).
  • The following functions have been introduced to encapsulate type validation & sanitization: rest_is_integer, rest_is_array, rest_sanitize_array, rest_is_object and rest_sanitize_object (see #48821).

Props @desrosj, @davidbaumwald, and @justinahinon for reviewing.

#5-5, #dev-notes, #rest-api

Register theme feature API

Themes use the add_theme_support APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. to declare support for a particular theme feature. For instance, add_theme_support( 'align-wide' ) declares that a theme supports the wide alignment feature.

When the Themes REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/. controller was introduced in WordPress 5.0 , a minimal set of theme features were exposed (see #45016). In WordPress 5.4, this was expanded to all WordPress CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. theme features (see #49037). Support for custom theme features was not included because there was not a safe way to validate their shape and ensure the associated data was not private.

In [48171] the new register_theme_feature() API was introduced to declare the format of a theme feature. This does not indicate that the current theme supports that feature, merely that it is available to be supported.

Features that are registered with show_in_rest enabled will have the add_theme_support() value exposed in the REST API themes endpoint. This allows for pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party developers to access the theme support values over the REST API. Currently, the REST API is the only consumer of the registered theme features.

WordPress Core registers the list of built-in theme features in the create_initial_theme_features() function.

The API

The register_theme_feature() function takes two arguments. The first, $feature, is the name uniquely identifying the feature. The second, $args, is a list of arguments detailing the feature. If the feature is successfully registered, the function will return true. Otherwise, a WP_Error instance is returned.

Type

The type argument specifies the JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. Schema type of the value that should be passed to add_theme_support(). The acceptable values are string, boolean, integer, number, object and array.

The object type refers to a PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher associative array (an array of key, value pairs). The array type refers to a PHP numerical array, in other words a list of values without specific keys.

Variadic

The variadic argument specifies whether the feature utilizes the variadic argument support of add_theme_support(), or if the feature is entirely described by the first argument. Theme features in Core aren’t variadic.

add_theme_support( 'html5', array(
	'search-form',
	'comment-form',
) );

If the html5 feature was variadic, add_theme_support() would be used like this.

add_theme_support( 'html5', 'search-form', 'comment-form' );

Description

The description argument is meant to be a short description of the feature intended for developers. The REST API surfaces this description in the schema for the Themes API.

Show in REST

By default, theme features are not included in the REST API. To opt-in to this behavior, the show_in_rest flag can be set to true or an array with additional arguments to describe the feature.

Schema

The show_in_rest.schema argument specifies the JSON schema describing the format of the feature. If the feature type is an object or array specifying a schema is mandatory.

For an array type, the schema should contain an items definition that describes the format of each entry in the array. For example, the html5 theme feature is described with the following schema.

array(
	'items' => array(
		'type' => 'string',
		'enum' => array(
			'search-form',
			'comment-form',
			'comment-list',
			'gallery',
			'caption',
			'script',
			'style',
		),
	),
)

For an object type, the schema should define each of the properties of the object that should appear in the REST API. This isn’t always every field that can be registered. For instance, the custom-header omits the various callback flags because they aren’t safe to include in the REST API.

array(
	'properties' => array(
		'default-image'      => array(
			'type'   => 'string',
			'format' => 'uri',
		),
		'random-default'     => array(
			'type' => 'boolean',
		),
		'width'              => array(
			'type' => 'integer',
		),
		'height'             => array(
			'type' => 'integer',
		),
		'flex-height'        => array(
			'type' => 'boolean',
		),
		'flex-width'         => array(
			'type' => 'boolean',
		),
		'default-text-color' => array(
			'type' => 'string',
		),
		'header-text'        => array(
			'type' => 'boolean',
		),
		'uploads'            => array(
			'type' => 'boolean',
		),
		'video'              => array(
			'type' => 'boolean',
		),
	),
)
Default

The show_in_rest.schema.default argument can be used to specify an alternate default value to be shown in the REST API if the current theme does not support the registered feature. By default, the feature will have a value of false. The post-formats feature declares a default of [ 'standard' ].

Name

The show_in_rest.name argument can be used to specify an alternate property name for the feature when it is displayed in the REST API. For example, the post-formats feature declares a name of formats.

Prepare callback

The show_in_rest.prepare_callback argument can be used to customize how the feature is formatted in the REST API. By default, the REST API sanitizes the raw value from get_theme_support according to the specified schema.

The post-formats feature uses a custom prepare_callback to ensure that standard is always included as a supported post format.

function ( $formats ) {
	$formats = is_array( $formats ) ? array_values( $formats[0] ) : array();
	$formats = array_merge( array( 'standard' ), $formats );

	return $formats;
}

The prepare_callback function receives the following parameters.

  1. The raw feature value from add_theme_support().
  2. The args describing the feature from register_theme_feature().
  3. The feature name.
  4. The WP_REST_Request object being responded to by the REST API.

Example

This example registers the editor-color-palette theme feature. Theme features should be registered on the setup_theme action.

function myplugin_setup_theme() {
	register_theme_feature( 'editor-color-palette', array(
		'type'         => 'array',
		'description'  => __( 'Custom color palette if defined by the theme.' ),
		'show_in_rest' => array(
			'schema' => array(
				'items' => array(
					'type'       => 'object',
					'properties' => array(
						'name'  => array(
							'type' => 'string',
						),
						'slug'  => array(
							'type' => 'string',
						),
						'color' => array(
							'type' => 'string',
						),
					),
				),
			),
		),
	) );
}
add_action( 'setup_theme', 'myplugin_setup_theme' );

For more information, refer to the related ticketticket Created for both bug reports and feature development on the bug tracker. on TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. (#49406).

Props @desrosj and @justinahinon for reviewing.

#5-5, #dev-notes, #rest-api, #themes

REST API Changes in 5.4

TaxonomyTaxonomy A taxonomy is a way to group things together. In WordPress, some common taxonomies are category, link, tag, or post format. https://codex.wordpress.org/Taxonomies#Default_Taxonomies. “OR” Relation Now Supported in Posts Controller

Querying for /wp/v2/posts?tags=1&categories=2 returns all posts assigned the tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.) with ID 1, AND assigned the categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging. with ID 2. This AND relationship, where multiple taxonomies’ term relationships must all be satisfied, has been the only supported behavior in these collection endpoints since WordPress 4.7.

The REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/. /wp/v2/posts endpoint, as well as custom post typeCustom Post Type WordPress can hold and display many different types of content. A single item of such a content is generally called a post, although post is also a specific post type. Custom Post Types gives your site the ability to have templated posts, to simplify the concept. endpoints extending from WP_REST_Posts_Controller (including custom post types specifying "show_in_rest" => true), now supports a new tax_relation parameter which can be used to return posts matching either taxonomy filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output., rather than both.

As an example, in WordPress 5.4, the posts endpoint query

/wp/v2/posts?tags=1&categories=2&tax_relation=OR

will now return posts in either the tag ID 1 or the category with ID 2.

Selective Link Embedding

The REST API now supports returning a limited set of embedded objects using the _embed parameter. As an example, in WordPress 5.4, the following query only embeds the author information instead of including all the comments, media, etc…

/wp/v2/posts/?_embed=author

All embeds will be returned if a value for the _embed parameter is omitted, or set to true or 1.

WP_REST_Server method changes

WordPress 5.4 changes the signature of two methods in the WP_REST_Server class. Developers who are extending WP_REST_Server and overriding these methods should update their code to match the new signatures to avoid PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher warnings.

  1. The signature of WP_REST_Server::embed_links() is now embed_links( $data, $embed = true ). The new $embed paramter accepts an array of link relations (such as array( 'author', 'wp:term' )) and limits the embedded links in the response to those relations. The default of true maintains the previous behavior of embedding all links in the response. For more details, see #39696.
  2. The signature of WP_REST_Server::get_routes() is now get_routes( $namespace = '' ). The new $namespace parameter accepts a string and limits the returned routes to those whose namespace matches the string. Internally, WP_REST_Server uses this new parameter to improve the performance of WP_REST_Server::dispatch() by reducing the number of regex checks necessary to match a request to a registered route. For more details, see #48530.

For performance reasons, WP_REST_Server::embed_links() also now caches response data in memory. This cache is managed by WP_REST_Server::response_to_data(). Code calling the protected embed_links method being called directly may need to be updated to ensure stale data is not returned.

(Thank you to @dlh for authoring this section)

See the full list of REST API changes on TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress..

#5-4, #dev-notes, #rest-api

The REST API in WordPress 5.3

WordPress 5.3 contains a number of REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/. improvements designed to make it easier and faster to work with APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. data from the blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. editor or other client applications.

Register Array & Object Metadata

As covered previously in this developer note on array & object metadata, it is now possible to use register_post_meta & register_term_meta (as well as the underlying method register_meta) to interact with complex metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. values as schema-validated JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. arrays or objects using the REST API. See the linked post for more details.

Nested response filtering with _fields query parameter

This developer note on the changes to the REST API’s _fields= query parameter shows how you may now filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. your REST API response objects to include only specific nested properties within the response body.

Ticketticket Created for both bug reports and feature development on the bug tracker. #42094

Set drafts back to “floating date” status

Once a date has been set for a draft, it was previously impossible to set the post back to showing “publish immediately” (also referred to as a “floating date,” where the post will be dated whenever it is published). As of 5.3, passing null for a date value will unset the draft date and restore this floating state.

Ticket #39953

Faster Responses

We have introduced a caching wrapper around the generation of REST resource schema objects, which initial testing has shown to yield up to a 30-40% performance increase in large API responses. If you work with expensive or large REST API queries, things should be quite a bit faster now. (Ticket #47871)

The REST API has also been improved to avoid unnecessary controller object instantiation (#45677) and to skip generation of sample permalinks when that data is not requested (#45605).

Please Note: if your team has existing performance benchmarking tooling for the REST API, please contact the component maintainers in the #core-restapi SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/. channel; we very much desire to expand our metrics in this area.

Additional Changes of Note

In addition to these key enhancements, there are a number of smaller improvements to the REST API which may be of interest to developers.

  • It is no longer possible to DELETE a Revision resource using the REST API, as this behavior could break a post’s audit trail. Ticket #43709
  • The /search endpoint will now correctly embed the full original body of each matched resource when passing the _embed query parameter. Ticket #47684
  • rest_do_request and rest_ensure_request now accept a string API path, so it is possible to instantiate a request in PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher using nothing more than the desired endpoint string, e.g.
    rest_do_request( '/wp/v2/posts' );
    Ticket #40614
  • Creating or updating a Terms resource via the REST API now returns the updated object using the “edit” context. Ticket #41411
  • It is now possible to edit a posted comment through the REST API when authenticating the request as a user with the moderate_comments capability. Previously a full editor- or adminadmin (and super admin)-level role was needed. Ticket #47024
  • rest_get_avatar_urls now receives the entire User or Comment object, not just the object’s email address. Ticket #40030

Welcoming Timothy Jacobs as a REST API component maintainer

Last but not least, many of you have no doubt seen @timothyblynjacobs active in tracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress., slack, and community events. Timothy has driven much of the momentum that resulted in the above improvements, and I’m excited to (belatedly) announce that he has joined the REST API team as an official component maintainer. Thank you very much for your energy and dedication!

Thank you also to every other person who contributed to API changes this cycle; it’s the best version of the REST API yet, and we couldn’t have done it without the dozens of contributors who helped create, review and land these patches.

We’ve got some ambitious ideas about how we can make the REST API even better in 5.4. Interested in helping out, with code, docs, or triagetriage The act of evaluating and sorting bug reports, in order to decide priority, severity, and other factors.? Join us for weekly office hours, every week on Thursdays at 1800 UTC!

#5-3, #dev-notes, #rest-api

Filtering nested REST response _fields in WP 5.3

WordPress 4.9.8 introduced the ability to limit the fields included in the JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. objects returned from the REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/., for example specifying

/wp/v2/posts?_fields=id,title,author

to return a list of posts with only id, title & author fields in situations where we don’t need all of the data contained in other fields like content or media (see #38131). Since 4.9.8 we’ve made further improvements to skip computing fields we did not explicitly request when _fields is present, saving time on the server in addition to slimming down the JSON response object.

In WordPress 5.3 we are adding the ability to filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. by nested fields. Previously we could only request top-level properties like content or meta, which would return the full content object (with raw and rendered properties when using an edit context) or the object containing all metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. values. We can now specify a nested path such as content.raw and the REST API will skip computing the rendered content, a useful performance boost for applications like GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ which only require that underlying raw post content.

Now that we can register complex array or object meta, we may similarly ask for only a few of many registered meta fields, or certain properties within a complex object, using a query such as this:

?_fields=meta.meta-key-1,meta.meta-key-2,meta.meta-key-3.nested-prop

(Note that this specific meta example depends on bugfix #48266, which will ship as part of RC1.)

Thank you @timothyblynjacobs, @dlh, @danielbachhuber, and @rmccue for assisting with the development of this useful feature!

#5-3, #dev-notes, #rest-api

WP 5.3 Supports Object and Array Meta Types in the REST API

With WordPress 5.3, the register_meta functions (including register_post_meta) now support the 'object' and 'array' data types. Previously, the recommended solution to create complex metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress.-based GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ blocks was to JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. encode the blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience.’s complex attribute value, and pass that string to the APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways.. The REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/. now natively supports those complex metadata types. This allows leveraging the REST API to perform schema-based validation, and should additionally simplify client code which interacts with these complex values through the REST API.

Importantly, these data types follow the JSON specification, not the PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher definition. For comparison, that means a JSON object type is equivalent to an associative array in PHP. The JSON array type is a numerically indexed array.

When registering a complex meta field, it is almost always required to also specify a JSON schema describing the expected structure. This can be done by switching show_in_rest from a simple true value, to an array that specifies the desired schema under the schema array key.

Object Example

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

{
  "meta": {
    "release": {
      "version": "5.2",
      "artist": "Jaco"
    }
  }
}
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',
                     ),
                 ),
             ),
         ),
     )
 );

By default, only properties that are explicitly specified in the schema will be allowed. The additionalProperties keyword can be used to to change this behavior. additionalProperties should be another JSON schema that is used to validate any unknown object members. For instance, to enforce that any additional properties are numbers, the following code can be used.

{
   "meta": {
     "release": {
       "version": "5.2",
       "artist": "Jaco",
       "unknown_field": 5.3
     }
   }
 }
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',
                 ),
             ),
         ),
     )
 );

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

Array Example

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

{
   "meta": {
     "projects": [
       "WordPress",
       "BuddyPress"
     ]
   }
 }
register_post_meta(
     'post',
     'projects',
     array(
         'single'       => true,
         'type'         => 'array',
         'show_in_rest' => array(
             'schema' => array(
                 'type'  => 'array',
                 'items' => array(
                     'type' => 'string',
                 ),
             ),
         ),
     )
 );

The “items” keyword is used to define the JSON schema to validate each array member against. It can be a simple type like “string” or a complex type like “object”.

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

{
   "meta": {
     "projects": [
       {
         "name": "WordPress",
         "website": "https://wordpress.org"
       },
       {
         "name": "BuddyPress",
         "website": "https://buddypress.org"
       }
     ]
   }
 }
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',
                         ),
                     ),
                 ),
             ),
         ),
     )
 );

Non-Single Metadata

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

The array and object data 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.

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

This would result in two postmeta 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.

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

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

Invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally 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. This is a change in 5.3, where previously only the meta type was validated.

#5-3, #dev-notes, #rest-api

New REST API Notice in 5.1

Edit: On January 14, 2019, the Good and Bad Practices section was added to show both correct and incorrect code examples.

Starting in WordPress 5.1, if register_rest_route() is not called on the rest_api_init action hook, a “doing it wrong” notice will be triggered. This notice is being added in an effort to encourage best practices when registering REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/. endpoints.

First, let’s look at what happens when WordPress loads to set up the REST API and explore a few reasons why this pattern is beneficial.

REST API Bootstrap Process

WordPress does its best to ensure that the REST API is only loaded when a REST request is being performed. To do this, the rest_api_loaded() function is run on the parse_request action and checks for a value in the rest_route query argument. This argument is populated with a value when the Rewrite APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. matches a WordPress REST API URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org. When a value is present, the rest_get_server() function is called to instantiate the WP_REST_Server class, store it for use across WordPress, and to run the rest_api_init action hook.

Performance

When register_rest_route() is called, it invokes rest_get_server() to retrieve the global WP_REST_Server instance created in the bootstrap process. But, if the instance has not been set up yet, it is instantiated then and the rest_api_init action hook is run. This means that every function added to the rest_api_init hook will fire at that time. This could result in a large performance hit.

For example, say register_rest_route() is called on the init action, or, just called in a theme’s functions.php file. The REST API server would be set up for every WordPress request, even those that are not actually aimed at the REST API.

Missing Endpoints

If register_rest_route() is called too early, it’s also possible that endpoints will go missing and never be registered. This happens when other plugins are not given the chance to register their rest_api_init hooksHooks In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same..

For example, say register_rest_route() is called directly in an mu-plugin file. This will cause the REST API to be set up before regular plugins are run, so their rest_api_init hooks will not be registered.

Good and Bad Practices

Let’s look at a few code examples and detail why they are good or bad.

Bad Practice

register_rest_route(
	'hello-world/v1',
	'/phrase',
	array(
		'method'   => 'GET',
		'callback' => 'myplugin_get_endpoint_phrase',
	)
);

In this example, register_rest_route() is called directly in a file without being attached to an action hook. This means the function will be called as soon as the file is loaded by WordPress. All of the potential issues detailed above are possible, and a _doing_it_wrong() notice will be triggered.

Good Practice

function myplugin_register_endpoints() {
	register_rest_route(
		'hello-world/v1',
		'/phrase',
		array(
			'method'   => 'GET',
			'callback' => 'myplugin_get_endpoint_phrase',
		)
	);
}
add_action( 'rest_api_init', `myplugin_register_endpoints` );

In this example, register_rest_route() is correctly placed inside of a function that is added to the rest_api_init action hook. It will only execute when the rest_api_init action hook is executed. The potential issues detailed above are avoided, and no _doing_it_wrong() notice is triggered.

Changes Required

Plugins and Themes

All plugins and themes should double check that their REST API endpoints are being registered correctly using the rest_api_init action hook. This best practice is also mentioned in the Routes and Endpoints section of the REST API Handbook. If this was a resource used when developing, chances are you won’t have to change anything!

Unit Tests

Because some unit tests require custom endpoints to exist, it is not uncommon for a test method to call register_rest_route() directly. If a test method calls the function before rest_api_init, a previously passing test method may now fail. This can be fixed in two ways.

The first way is to use rest_get_server() to create the WP_Rest_Server instance for your tests. Since rest_api_init is run within that function, this will prevent the notice. This approach can be seen in the Tests_REST_Server class. The wp_rest_server_class filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. still allows you to replace the default WP_Rest_Server class with your own for testing purposes with this method.

The second way is to call do_action( 'rest_api_init' ); directly in your test method or setUp() method. This method is for scenarios where complete control is needed over the REST server setup process. This can approach can be seen in the Tests_REST_API class.

You can read more information about this change in the ticket on Trac.

#5-1, #dev-notes, #rest-api

Improvements in REST API request parameter regular expressions

With WordPress 4.9, a bugbug A bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority. has been fixed which would cause unexpected numeric results to be included in the parsed URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org parameters for a REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/. request. Prior to this change, calling WP_REST_Request::get_params() for a request like /wp/v2/users/(?P<id>[\d]+) with an ID of 10 would return array( 'id' => 10, 1 => '10' ), where the latter numeric key is unnecessary and a result of PCRE matching against a named subpattern (see preg_match() documentation). The fix ensures that the above request now only returns array( 'id' => 10 ) instead. This helps for example to verify that a request does not include more than a few specific parameters.

The WP REST API docs have always been using named URL parameters, using regular (numeric) matches was never recommended. With this bug fix in place, using named parameters is now effectively required, for example /my-namespace/my-endpoint/(?P<numeric_param>[\d]+) must be used instead of /my-namespace/my-endpoint/(\d+). For background discussion on these changes, see #40704.

#4-9, #dev-notes, #rest-api

Enhancing register_meta() in 4.6

Note: The direction of register_meta() has changed since this was published. Please see the most recent developer note explaining these changes.

In 4.6, register_meta() expands to support the registration of meta keys and what to expect from those keys. See #35658 for the discussion around this change.

The behavior of register_meta() is similar to register_post_type() in that the registration of this data is stored in the global scope. This makes an object’s meta data more accessible to parts of core and extending code.

Why make this change

In 4.5 and earlier, WordPress provided no method to explicitly register a meta key’s public state. Instead, register_meta() provided “protected” and “authenticated” meta. This can be used effectively for some things, particularly to determine what meta appears in the Custom Fields metabox when editing a post. It can not be used as a basis for arbitrarily showing meta keys and values to unauthenticated visitors.

What does this change involve

A global variable, $wp_meta_keys, contains all registered meta keys.

The function signature of register_meta() has changed to support 3 arguments, the last being an array. That array should contain data about the meta with these key/values:

  • sanitize_callback, a callable method to provide sanitization. This is the new version of the current 3rd parameter in register_meta().
  • auth_callback, a callable method to provide authorization. This is the new version of the current 4th parameter in register_meta().
  • object_subtype, a string containing an object subtype slug. If there is no object subtype, meta will not be registered and a WP_Error will be returned instead.
  • type, a string indicating what type of data the meta value will be. This is intentionally not restricted to a specific list of data types, however full names should be used when possible. (e.g. boolean, integer)
  • description, a string containing a basic description of the meta value.
  • single, whether code retrieving meta for this key should expect a single or multiple values when using something like get_post_meta().
  • show_in_rest, whether this should be shown as part of a post’s meta endpoint in the WordPress REST API. Note that this should be treated as experimental until the WordPress REST API provides support for meta.

The register_meta_args filter is available to add support for additional arguments. This need to explicitly whitelist further arguments is to reserve the right for core to add further arguments in the future; should you choose to use this filter, you should be prepared to follow along with further development. Your testing with trunk or betas is greatly appreciated!

By default, only WordPress core object types (post, user, term, comment) can be registered. To add support for custom object types, use the wp_object_types filter. This whitelisting is similar to the above.

Object sub types provide specific registration of meta keys to a type of data.

  • A standard WordPress post has an object type of “post” and an object subtype of “post”.
  • A custom post type registered with a slug of “my_cpt” has an object type of “post” and an object subtype of “my_cpt”.
  • A WordPress user has an object type of “user” and an object subtype of “user”.
  • A standard WordPress comment has an object type of “comment” and an object subtype of “comment”.
  • A standard WordPress category term has an object type of “term” and an object subtype of “category”.
  • A custom taxonomy registered with a slug of “my_tax” has an object type of “term” and an object subtype of “my_tax”.

Meta keys must be explicitly registered for each object type and subtype combination.

Additional helper functions get_registered_metadata(), get_registered_meta_keys(), unregister_meta(), and registered_meta_key_exists() have been added to make the innards of the global data more accessible.

The $wp_meta_keys variable should not be altered directly. It is possible that its structure will change in the future.

Any code currently using register_meta() and expecting pre-4.6 behavior will continue to work as is. Please report any breaks in compatibility that might be found.

Example

Here’s what registering meta looked like in 4.5. This meta key has sanitization and authorization callbacks.

register_meta( 'post', 'my_meta_key', 'sanitize_my_meta_key', 'authorize_my_meta_key' );

The above code will continue to work in 4.6, though will not be considered completely registered. The callbacks will be registered, but the key will not be added to the global registry. A WP_Error object will be returned with this explanation.

Here’s what registering meta looks like in 4.6. This meta key will have sanitization and authorization callbacks, and be registered as public for the WordPress REST API.

$args = array(
    'object_subtype' => 'post',
    'sanitize_callback' => 'sanitize_my_meta_key',
    'auth_callback' => 'authorize_my_meta_key',
    'type' => 'string',
    'description' => 'My registered meta key',
    'single' => true,
    'show_in_rest' => true,
);
register_meta( 'post', 'my_meta_key', $args );

If you are currently using register_meta() and would like to maintain support for older versions of WordPress, the best method will be to check for the registration of the sanitization and authorization callbacks after calling register_meta() and then registering them manually if not present. This manual registration is all that register_meta() was previously doing. Continuing from the example above:

// Pre-WordPress 4.6 compatibility
if ( ! has_filter( 'sanitize_post_meta_my_meta_key' ) ) {
    add_filter( 'sanitize_post_meta_my_meta_key', 'sanitize_my_meta_key', 10, 4 );
}

if ( ! has_filter( 'auth_post_meta_my_meta_key' ) ) {
    add_filter( 'auth_post_meta_my_meta_key', 'authorize_my_meta_key', 10, 6 );
}

What’s next

While the initial work on this is largely driven by the need to move the WordPress REST API forward, its scope is not limited to solving the problem of public access to metadata. By having information about the meta keys used in a code base, it becomes much easier for other pieces of code to make decisions about what can be done with this data.

This data can one day be useful to everything from the Customizer, the editing experience for all object types, the Fields API, and many plugins that rely on metadata. Work will continue on transforming this $wp_meta_keys object and the methods surrounding it to be flexible and explicit. As WordPress core becomes familiar with register_meta() and more confident in the approach, the set of default arguments can and likely will expand to include more data about registered meta keys as required.

Feedback

Please leave any feedback you have on this new iteration of register_meta() in the comments below. Test it out in your plugins and themes to be sure it is working in a backwards compatible way. Try out the new function signature and register meta for objects and their subtypes. This continues to be a work in progress and feedback is important.

#4-6, #dev-notes, #fields-api, #options-meta, #rest-api