REST API and WPGraphQL
5 min read
Two switches in the field group let other systems read your values without any PHP:
Setting (group Settings, Group settings tab) | Default | Result |
|---|---|---|
Show in the REST API ( | off | A |
Show in GraphQL ( | off | With the WPGraphQL plugin: a read-only |
Both only look at active groups, only expose top-level fields that have a column, and never expose Password fields (nor password sub-fields inside groups and repeaters). Both find their post types in the same way: the location rules of the form Post type is equal to X. Rules of other kinds (template, status, taxonomy...) do not add post types.
REST API in short
With Show in the REST API on, every post of a located type gets this in its response:
{
"id": 42,
"wpmcf": {
"book_details": { "subtitle": "A story", "pages": 320, "in_print": true, "chapters": [ { "name": "One" } ] }
}
}POST /wp-json/wp/v2/posts/42 { "wpmcf": { "book_details": { "pages": 350 } } }- Keys: group key, then field key. A field without value is
null. Values are the stored PHP values. - Reading follows the post's own visibility; in the view context a password-protected post returns an empty
wpmcf. - Writing needs permission to edit the post and goes through the field types; unknown groups and fields give
400errors. - Posts only: users, terms and comments have no attribute.
The complete reference (every rule, error code, the schema and examples) is on the page REST API of the Developer API section.
WPGraphQL
WPGraphQL (the free plugin of that name) is not required for anything else. Without it nothing is registered and nothing runs; with it, groups that have Show in GraphQL on appear in the schema.
Requirements
- The WPGraphQL plugin is active.
- The field group is active, has Show in GraphQL on, and has a location rule Post type is equal to X.
- The post type is exposed in WPGraphQL: it has
show_in_graphqlon and agraphql_single_name. Posts and pages are by default. For a custom post type, register it with GraphQL support (the Post Types screen of this plugin has no GraphQL option), for example:
add_filter( 'register_post_type_args', function ( $args, $post_type ) {
if ( 'book' === $post_type ) {
$args['show_in_graphql'] = true;
$args['graphql_single_name'] = 'book';
$args['graphql_plural_name'] = 'books';
}
return $args;
}, 10, 2 );A group that is located on several post types gets the field on each of them. A post type that WPGraphQL does not show is skipped. If no located post type is exposed, the group is not registered at all.
Naming
For a group with the key book_details:
What | Name | Rule |
|---|---|---|
Object type |
|
|
Field on |
|
|
Fields inside |
| The field key in camelCase ( |
The group key counts completely, including a prefix: a group with the key wpmcf_doc_a11_gql becomes WpmcfWpmcfDocA11Gql. Choose short group keys if you want short GraphQL names.
Keys that differ only in underscores (a_b and a__b) map to the same name. The first group keeps it and the other is silently left out of GraphQL. Keep group keys distinct.
Value types
Field type | GraphQL type | Notes |
|---|---|---|
True / False |
| |
Number, Range |
|
|
Image, File and Attachment (stored as attachment IDs) |
| The attachment ID. Query the media item with this ID. |
Fields stored as lists or objects (Checkbox, Group, Repeater, Relationship, Link, Map...) |
| The value JSON-encoded (for example |
Everything else (Text, Text area, Select, Date, Email, URL...) |
|
An empty field is null. A value that is not a number in a numeric field is null.
Not exposed: Password fields, layout fields (tab, accordion...) and sub-fields as fields of their own (they are part of the JSON string of their container).
Example query
query Books {
posts(first: 3) {
nodes {
title
wpmcfBookDetails {
subtitle
pageCount
inStock
format
chapters # JSON string, e.g. "[{\"name\":\"One\"}]"
cover # attachment ID
}
}
}
}Response:
{
"data": {
"posts": {
"nodes": [
{
"title": "A story",
"wpmcfBookDetails": {
"subtitle": "A story",
"pageCount": 320,
"inStock": true,
"format": "pb",
"chapters": "[{\"name\":\"One\"}]",
"cover": 1205
}
}
]
}
}
}To get the image URL for cover, ask for the media item by its database ID (mediaItem( id: 1205, idType: DATABASE_ID ) { sourceUrl }).
Access and visibility
- Read only. There are no mutations. To write values from a client use the REST attribute.
- WPGraphQL decides which posts the user may see (drafts, private posts). The
wpmcffield is attached to the post it resolves for. - A password-protected post returns
nullfor the wholewpmcf{Group}field, unless the viewer can edit that post. - The group's field is
nullfor an object the resolver cannot identify.
Verified how
WPGraphQL is not installed on the documentation site. The registration and the resolver were exercised with stand-in register_graphql_object_type() and register_graphql_field() functions: the registered type names, field names and GraphQL types in the tables above are what the plugin registered, and the resolver returned the values shown (booleans, floats, IDs as integers, containers as JSON strings, null for password-protected posts for visitors). A live schema with the real plugin was not queried.
Troubleshooting
Problem | Check |
|---|---|
The field does not appear in the schema | WPGraphQL active? Show in GraphQL on and the group active? A |
The field is called something unexpected | See Naming: the group key is used in full. |
A repeater is a string | By design: containers are JSON strings. Decode with |
| The post is password protected and the viewer cannot edit it, or the group's location does not match that post. |
Two groups, one is missing | Their keys map to the same GraphQL name (underscores). Rename one key. |
Still stuck? Contact support