Defining “context” in the WP REST API

Authored by

I got a question from a colleague last week regarding the context parameter in the WP REST API:

In which cases would the request be a GET request but the context be edit? I was thinking that perhaps if an object is edited and a child is embedded, then maybe getting that child would be with edit context param, but probably that would be embed instead? Are there cases when context is edit but it’s a GET request?

When I started learning and contributing to the REST API, I was also unclear about what the context parameter was all about. I never saw a clear explanation for what context was for. The REST API Handbook‘s Glossary entry on “Schema” mentions it briefly:

A “schema” is a representation of the format for WP-API’s response data. For instance, the Post schema communicates that a request to get a Post will return idtitlecontentauthor, and other fields. Our schemas also indicate the type each field is, provide a human-readable description, and show which contexts the field will be returned in.

Likewise, the Controller Classes handbook page notes that a controller’s filter_response_by_context() method “filters the response shape based on the provided context parameter.” But what exactly is context and how is it used?

When defining fields in the REST API, you may often throw into the schema that a field belongs to the contexts of view, edit, and embed. On the surface, I can easily see why there would be confusion between a view context being an alias for GET requests, and an edit context being an alias for POST (and PUT) requests. Is including context=edit in a GET request just another way to make a POST request to update a resource? Not quite.

There is actually a close relationship between POST/PUT requests and the edit context. In fact, whenever you create or update a post, the posts controller will override whatever context was supplied in the request to return the resource in the edit context in the response. This leads to the purpose of the context param: it defines a visibility scope for a given field. The edit context is used to make the response include the fields which are needed in order to be able to edit the resource. So the edit context is always used when doing GET requests when you want to obtain the data for editing. It’s not an alias for doing a POST/PUT request to edit a resource.

For example, the content field includes two properties: rendered and raw. The rendered field belongs to both the view and edit contexts, whereas the raw field only belongs to the edit context. The raw content will have unprocessed shortcodes, non-wptexturize‘d text, and line breaks untouched by wpautop. In contrast, the rendered field is the content after all the_content filters have been applied, just as it appears when viewed on the frontend. If you’re only showing posts in your app, all you need is the rendered field. But when you edit a post, you need the raw content to do so without losing data (like underlying shortcodes used). So when you request a post with the edit context you get any fields that are defined in the schema with this context included. In the case of the edit context, the ability to request a resource with this context is restricted to users who can actually edit the post in the first place (as there also may be sensitive information in unprocessed shortcodes).

So if the rendered property of the content field belongs to the view and edit contexts, why doesn’t it belong to the embed context? What is the embed context? Note that it is not related in any way to oEmbed. The REST API allows you to define links from one resource to other resources. In the response, these links appear as the _links object property. When you make a request to the REST API and you include ?_embed it will dispatch internal subrequests for all of the linked resources and include them in the response via an _embedded object property. The internal subrequests will be made for the linked resources with a context parameter of embed. So the reason content doesn’t belong to the embed context is so that it is excluded from the _embedded property, reducing the size of the overall response. You will note that excerpt does belong to all three contexts, and so post excerpts will be included in _embedded resources while content is excluded from the embed context, which makes sense if wanting to limit the overall size of the response when requesting with _embed.

I’ll share another situation though which embed context really clicked for me. In preparing for a LoopConf 2.1 workshop, I was working on a Customize Featured Content Demo plugin. A featured item had a related field in the REST API that contained a post ID. When requesting a given featured item with _embed I wanted to get the featured item along with its related post in _embedded so that I could eliminate doing a second request to obtain the related post and its properties, like featured_media. Nevertheless, I was baffled when I looked at the post in _embedded  and it omitted featured_media. It turns out that when the content endpoints where added, the featured_media property was only defined as belonging to the view and edit contexts. Because of this, the field was filtered out of the response. This was fixed in WordPress 4.8 via #39805, and this eliminated the need for an unsightly workaround to force a view context on linked resources to get the field to be embedded.

All of this to say, the context is a way to omit a predefined set of fields from being shown in a response, whether that be because they are unnecessary or unauthorized for a given application (showing posts to unauthenticated users), or they are assumed to be too verbose to warrant inclusion when a linked resource is embedded in a response.

The WordPress REST API doesn’t currently support a way to make a request that includes only individually requested fields in the response. For example to limit the response to only include the title and content, you cannot make a request like:

/wp-json/wp/v2/posts/1?fields[]=title&fields[]=content

There is a ticket open to add support for such a fields parameter (see #38131). Nevertheless, the context field can be used for this purpose in custom endpoints. In the REST API Handbook there is an Important Note about Changing Responses which includes an interesting paragraph:

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.

So view, edit, and embed are not the only three possible contexts a field can belong to; you can make up your own. So as long as you can define a set of fields in your custom endpoints which you’ll need for a given application, you can create a new context identifier to add to each of them; any fields that do not belong to this context as included in the request will then be omitted in the response.

I hope this clears up what context is in the WP REST API. I’ll probably try to incorporate some of this post into the REST API Handbook, either as a new page under Using the REST API, or perhaps as a section on the Global Parameters page.

4 thoughts on “Defining “context” in the WP REST API”

  1. Thanks for putting all that into a post, Weston! Definitely clearer now what the context param is for, especially with GET request + edit.

  2. Very nice write up. Thanks.

    I’m just getting started with the api and the dearth of documentation and practical examples is challenging. I came here searching for some clues on how to create a page with a featured media (image) that is inline with the text of the content. In my theme, when I add a new page with a featured image, it appears in the header and it’s not clear how to control its placement in the text of the content.

    In the instant case, I am accessing the GovTrack website and trying to create a single page for each legislator there, using the photo and description as content. The first item of content should be the photo and then the description. Sounds pretty simple but if, for example, my JSON requestbody contains

    jsonDict.Add key:=”content”, Item:=pageContent
    jsonDict.Add key:=”featured_media”, Item:=mediaID

    where pageContent is a string that comes from GovTrack and mediaID is the WordPress ID number for the media (the code above is from VBA and modifies a dictionary object that is later encoded to JSON), then the new page shows the media in the header and not in the body of the content.

  3. /wp-json/wp/v2/posts/1?fields[]=title&fields[]=content is now implemented in core, with a small twist -> the filter is underscored:
    … _fields[]=id&_fields[]=title …
    Thank you for this post!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.