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 withedit
context param, but probably that would beembed
instead? Are there cases when context isedit
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
id
,title
,content
,author
, 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.
Great write-up, Weston. Can’t help but read this post and wish for GraphQL 🙂
Thanks for putting all that into a post, Weston! Definitely clearer now what the context param is for, especially with GET request + edit.
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.
/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!
This post includes so much more info than similar blogs, and it’s incredibly useful to me.
Will be returning to see more writing from you!
can I share this?
wonderful points altogether, you just won a new reader. What might you suggest about your put up that
you just made some days ago? Any certain?