REST API changes in WordPress 5.5

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/. will see a lot of changes in WordPress 5.5. In an effort to explain each change adequately, a number of these were split out and covered by other dev notesdev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase..

Below are some other noteworthy changes that deserve a call out.

Discoverable REST resource links

To aid automated and human discovery of the REST API, a link was added in the <head> of the document and as a Link 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. to the REST route for the currently queried document in [48273].

For example, in the <head> of this post, the following <link> appears.

<link rel="alternate" type="application/json" href="https://make.wordpress.org/core/wp-json/wp/v2/posts/82428">

Links are added for post, pages, and other custom post types, as well as terms and author pages. Links are not currently output for post archives or search results.

See #49116 for more information.

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.

Three new functions are introduced.

  • rest_get_route_for_post() retrieves the route for the given post. For instance, /wp/v2/posts/1.
  • rest_get_route_for_term() retrieves the route for the given term. For instance, /wp/v2/tags/1.
  • rest_get_queried_resource_route() retrieves the route for the currently queried resource. For instance, /wp/v2/users/1 when on the author page for the user with ID of 1.

All three functions return an empty string if a REST API route cannot be determined. To convert the route to a link, pass the result to the rest_url() function.

For more information, see #49116.

Customization

For custom post types, only routes using the built-in WP_REST_Posts_Controller controller class will work by default. For custom controllers, the rest_route_for_post 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. can be used to supply the correct route.

function my_plugin_rest_route_for_post( $route, $post ) {
	if ( $post->post_type === 'my-cpt' ) {
		$route = '/wp/v2/my-cpt/' . $post->ID;
	}

	return $route;
}
add_filter( 'rest_route_for_post', 'my_plugin_rest_route_for_post', 10, 2 );

Similar logic applies to taxonomies, only the built in WP_REST_Terms_Controller is supported by default. The rest_route_for_term filter can be used for custom controller classes.

function my_plugin_rest_route_for_term( $route, $term ) {
	if ( $term->taxonomy === 'my-tax' ) {
		$route = '/wp/v2/my-tax/' . $term->term_id;
	}

	return $route;
}
add_filter( 'rest_route_for_term', 'my_plugin_rest_route_for_term', 10, 2 );

The rest_get_queried_resource_route() function is filterable to allow for identification of custom resources.

function my_plugin_rest_queried_resource_route( $route ) {
	$id = get_query_var( 'my-route' );
	if ( ! $route && $id ) {
		$route = '/my-ns/v1/items/' . $id;
	}

	return $route;
}
add_filter( 'rest_queried_resource_route', 'my_plugin_rest_queried_resource_route' );

These links are output using the existing rest_output_link_wp_head and rest_output_link_header functions. As such, if API discovery has already been disabled, these links will not be rendered.

For more information, see #49116.

CORS changes

In [48112], the Link header was added to the list of exposed CORS response headers. Previously, only the X-WP-Total and X-WP-TotalPages headers were exposed which means that clients would have to manually construct the URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org to implement pagination instead of using the prev and next Links.

In [48452], the Content-Disposition, Content-MD5 and X-WP-Nonce were added to the list of allowed cors request headers. The Content-Disposition and Content-MD5 headers allow for easier file uploading across domains by using a File/Blob object directly. The X-WP-Nonce header is allowed for making authenticated cross-origin and same-origin requests consistently.

Two filters are introduced, rest_exposed_cors_headers and rest_allowed_cors_headers to simplify the process of plugins modifying the list of cors headers.

For more information, see #50369 and #41696.

Miscellaneous

Warn when omitting a permission_callback

The REST API treats routes without a permission_callback as public. Because this happens without any warning to the user, if the permission callback is unintentionally omitted or misspelled, the endpoint can end up being available to the public. Such a scenario has happened multiple times in the wild, and the results can be catastrophic when it occurs.

In [48526] a _doing_it_wrong notice has been added when a permission callback is omitted. For REST API routes that are intended to be public, it is recommended to set the permission callback to the __return_true built in function.

So for instance, this route registration will cause the following warning to appear.

register_rest_route(
	'my-ns',
	'echo',
	array(
		'methods'  => WP_REST_Server::EDITABLE,
		'callback' => function ( WP_REST_Request $request ) {
			return new WP_REST_Response( $request->get_param( 'echo' ) );
		},
	)
);
The REST API route definition for my-ns/echo is missing the required permission_callback argument. For REST API routes that are intended to be public, use __return_true as the permission callback.

If it was intended for this endpoint to be public, you could fix it like this.

register_rest_route(
	'my-ns',
	'echo',
	array(
		'methods'  => WP_REST_Server::EDITABLE,
		'callback' => function ( WP_REST_Request $request ) {
			return new WP_REST_Response( $request->get_param( 'echo' ) );
		},
		'permission_callback' => '__return_true',
	)
);

If you wanted to check the user’s capabilities, you could do it like this.

register_rest_route(
	'my-ns',
	'echo',
	array(
		'methods'  => WP_REST_Server::EDITABLE,
		'callback' => function ( WP_REST_Request $request ) {
			return new WP_REST_Response( $request->get_param( 'echo' ) );
		},
		'permission_callback' => function( WP_REST_Request $request ) {
			return current_user_can( 'manage_options' );
		},
	)
);

For more information, see #50075.

Using wp_send_json() is doing it wrong

When building a REST API route, it is important for the route callback (and permission_callback) to return data instead of directly sending it to the browser. This ensures that the additional processing that the REST API server does, like handling linking/embedding, sending headers, etc… takes place.

// This is incorrect.
echo wp_json_encode( $data );
die;

// And this.
wp_send_json( $data );

// And this.
wp_send_json_error( 'My Error' );

// Instead do this.
return new WP_REST_Response( $data );

// Or this.
return new WP_Error( 'my_error_code', 'My Error Message' );

After [48361], a _doing_it_wrong notice is now issued when any of the wp_send_json family of functions are used during a REST API request.

For more information, see #36271.

Preloading silenced deprecation errors

When using rest_preload_api_request any deprecation errors encountered when processing the request were silenced because the REST API handling took over as soon as the API server was booted.

After [48150], the REST API handling will only apply for actual REST API requests.

For more information, see #50318.

Props @desrosj and @justinahinon for proofreading.

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