1. Wpgraphql No Schema Available
  2. Wp Graphql Woocommerce
  3. Wp Graphql Acf
  4. Graphql Api Github
  5. Wp Graphql Gutenberg
  1. WPGraphQL has been, until now, a synonym with GraphQL in WordPress. During the 4 years plus that it has been developed (starting in November, 2016), it gathered over 2.8k stars on the repo, a community of over 4600 followers, and almost 100 contributors to the project.
  2. CMS-agnostic GraphQL server in PHP. What are these packages? From owner 'getpop', only packages 'getpop/graphql' and 'getpop/engine-wp-bootloader' are mandatory. The other ones are required to load data from posts, pages, users, comments, taxonomies and media, and to set-up the API endpoint permalink.

WPGraphQL has been, until now, a synonym with GraphQL in WordPress. During the 4 years plus that it has been developed (starting in November, 2016), it gathered over 2.8k stars on the repo, a community of over 4600 followers, and almost 100 contributors to the project. The WP GraphQL plugin does not ship with WordPress Core, but does add a GraphQL endpoint to WordPress. GraphQL is the preferred method for getting data mostly due to its ease of use and ability to get with one query what would take multiple queries with a REST API. Screenshot of a GraphQL Query for Menu Items, filtered by Menu Location Hierarchical Data. One thing you may have noticed is that Menu Items will be returned in a flat-list by default, meaning that hierarchical relationships such as parent, children, grand-child Menu Items, will all be returned together in a flat list.

Class Types - Acts as a registry and factory for Types.

Each 'type' is static ensuring that it will only be instantiated once and can be re-usedthroughout the system. The types that are 'dynamic' (such as post_types, taxonomies, etc)are added as a sub-property to the Types class based on their unique identifier, and aretherefore only instantiated once as well.

Namespace:WPGraphQL
Package: WPGraphQL
Since: 0.0.5
Located atTypes.php
public static WPGraphQLTypeAvatarAvatarType
#avatar( )

This returns the definition for the AvatarType

Returns

Since

0.0.5
public static WPGraphQLTypeCommentCommentType
#comment( )

This returns the definition for the CommentType

Returns

Since

0.0.5
public static WPGraphQLTypeCommentAuthorCommentAuthorType
#comment_author( )

This returns the definition for the CommentAuthorType

This returns the definition for the CommentAuthorType

Returns

WPGraphQLTypeCommentAuthorCommentAuthorType
object

Since

public static WPGraphQLTypeUnionCommentAuthorUnionType
#comment_author_union( )

This returns the definition for the PostObjectUnionType

This returns the definition for the PostObjectUnionType

Returns

WPGraphQLTypeUnionCommentAuthorUnionType
object

Since

public static WPGraphQLTypeEditLockEditLockType
#edit_lock( )

This returns the definition for the EditLock type

Returns

public static WPGraphQLTypeEnumMimeTypeEnumType
#mime_type_enum( )

This returns the definition for the MimeTypeEnumType

This returns the definition for the MimeTypeEnumType

Returns

Since

0.0.5
public static WPGraphQLTypeSettingSettingType
#setting( $setting_type )

This returns the definition for the SettingType

Returns

public static WPGraphQLTypePluginPluginType
#plugin( )

This returns the definition for the PluginType

Returns

Since

0.0.5
public static WPGraphQLTypePostObjectPostObjectType
#post_object( string $post_type )

This returns the definition for the PostObjectType

This returns the definition for the PostObjectType

Parameters

$post_type
Name of the post type you want to retrieve the PostObjectType for

Returns

Since

0.0.5
public static WPGraphQLTypeUnionPostObjectUnionType
#post_object_union( )

This returns the definition for the PostObjectUnionType

This returns the definition for the PostObjectUnionType

Returns

Since

0.0.5
public static WPGraphQLTypeEnumPostObjectFieldFormatEnumType
#post_object_field_format_enum( )

This returns the definition for the PostObjectFieldFormatEnumType

This returns the definition for the PostObjectFieldFormatEnumType

Returns

WPGraphQLTypeEnumPostObjectFieldFormatEnumType
object

Since

public static WPGraphQLTypeEnumPostStatusEnumType
#post_status_enum( )

This returns the definition for the PostStatusEnumType

This returns the definition for the PostStatusEnumType

Returns

Since

0.0.5
public static WPGraphQLTypeEnumMediaItemStatusEnumType
#media_item_status_enum( )

This returns the definition for the MediaItemStatusEnumType

This returns the definition for the MediaItemStatusEnumType

Returns

WPGraphQLTypeEnumMediaItemStatusEnumType
object
public static WPGraphQLTypeEnumPostTypeEnumType
#post_type_enum( )

This returns the definition for the PostStatusEnumType

This returns the definition for the PostStatusEnumType

Returns

Since

0.0.5
public static WPGraphQLTypePostObjectConnectionPostObjectConnectionArgs
#post_object_query_args( )

This returns the definition for the PostObjectConnectionArgs

This returns the definition for the PostObjectConnectionArgs

Returns

WPGraphQLTypePostObjectConnectionPostObjectConnectionArgs
object

Since

public static WPGraphQLTypePostTypePostTypeType
#post_type( )

This returns the definition for the PostTypeType

Returns

Since

0.0.5
public static WPGraphQLTypeEnumRelationEnumType
#relation_enum( )

This returns the definition for the RelationEnum

Returns

Since

0.0.5
public static WPGraphQLTypeRootMutationType
#root_mutation( )

This returns the definition for the RootMutationType

This returns the definition for the RootMutationType

Returns

Since

0.0.8
public static WPGraphQLTypeRootQueryType
#root_query( )

This returns the definition for the RootQueryType

Returns

Since

0.0.5
public static WPGraphQLTypeTaxonomyTaxonomyType
#taxonomy( )

This returns the definition for the TaxonomyType

Returns

Since

0.0.5
public static WPGraphQLTypeEnumTaxonomyEnumType
#taxonomy_enum( )

This returns the definition for the TaxonomyEnumType

This returns the definition for the TaxonomyEnumType

Returns

Since

0.0.5
public static WPGraphQLTypeTermObjectTermObjectType
#term_object( string $taxonomy )

This returns the definition for the TermObjectType

This returns the definition for the TermObjectType

Parameters

$taxonomy
Name of the taxonomy you want to get the TermObjectType for

Returns

Since

0.0.5
public static WPGraphQLTypeTermObjectConnectionTermObjectConnectionArgs
#term_object_query_args( )

This returns the definition for the TermObjectConnectionArgs

This returns the definition for the TermObjectConnectionArgs

Returns

WPGraphQLTypeTermObjectConnectionTermObjectConnectionArgs
object

Since

public static WPGraphQLTypeUnionTermObjectUnionType
#term_object_union( )

This returns the definition for the termObjectUnionType

This returns the definition for the termObjectUnionType

Returns

public static WPGraphQLTypeThemeThemeType
#theme( )

This returns the definition for the ThemeType

Returns

Since

0.0.5
public static WPGraphQLTypeUserUserType
#user( )

This returns the definition for the UserType

Returns

Since

0.0.5
public static WPGraphQLTypeUserConnectionUserConnectionArgs
#user_connection_query_args( )

This returns the definition for the UserConnectionArgs

This returns the definition for the UserConnectionArgs

Returns

WPGraphQLTypeUserConnectionUserConnectionArgs
object

Since

public static GraphQLTypeDefinitionBooleanType
#boolean( )

This is a wrapper for the GraphQL type to give a consistent experience

This is a wrapper for the GraphQL type to give a consistent experience

Returns

Since

0.0.5
public static GraphQLTypeDefinitionFloatType
#float( )

This is a wrapper for the GraphQL type to give a consistent experience

This is a wrapper for the GraphQL type to give a consistent experience

Returns

Since

0.0.5
public static GraphQLTypeDefinitionidType
#id( )

This is a wrapper for the GraphQL type to give a consistent experience

This is a wrapper for the GraphQL type to give a consistent experience

Returns

Since

0.0.5
public static GraphQLTypeDefinitionIntType
#int( )

This is a wrapper for the GraphQL type to give a consistent experience

This is a wrapper for the GraphQL type to give a consistent experience

Returns

Since

0.0.5
public static GraphQLTypeDefinitionStringType
#string( )

This is a wrapper for the GraphQL type to give a consistent experience

This is a wrapper for the GraphQL type to give a consistent experience

Returns

Since

0.0.5
public static GraphQLTypeDefinitionListOfType
#list_of( callable $type )

This is a wrapper for the GraphQL type to give a consistent experience

This is a wrapper for the GraphQL type to give a consistent experience

Parameters

$type

instance of GraphQLTypeDefinitionType or callable returning instance of that class

Returns

Since

0.0.5
public static GraphQLTypeDefinitionNonNull
#non_null( callable $type )

This is a wrapper for the GraphQL type to give a consistent experience

This is a wrapper for the GraphQL type to give a consistent experience

Parameters

$type

instance of GraphQLTypeDefinitionType or callable returning instance of that class

Returns

Since

0.0.5
public static GraphQLTypeDefinitionBooleanType|GraphQLTypeDefinitionFloatType|GraphQLTypeDefinitionIntType|GraphQLTypeDefinitionStringType
#get_type( $type )

Resolve the type on the individual setting fieldfor the settingsType

Resolve the type on the individual setting fieldfor the settingsType

Parameters

Returns

GraphQLTypeDefinitionBooleanType|GraphQLTypeDefinitionFloatType|GraphQLTypeDefinitionIntType|GraphQLTypeDefinitionStringType
public static array
#map_input( array $args, array $map )

Maps new input query args and sanitizes the input

Parameters

$args
The raw query args from the GraphQL query
$map
The mapping of where each of the args should go

Returns

Since

0.5.0

WordPress is a legacy CMS: having been invented over 17 years ago, it's filled with PHP code that, given a new chance, it would be coded in a different way.

GraphQL is a modern interface to access data. Please notice the word 'interface': it doesn't care how the underlying data system is implemented, but only how to expose the data.

What happens when we put these two together? How should we design the GraphQL interface to access data from WordPress?

There are a couple of obvious strategies that we can put in place:

  1. Respect tradition, and provide a mapping that keeps the WordPress data model as is, including the technical debt it accumulated during the years

  2. Fix the technical debt, providing an interface exposing data in an abstract, not-necessarily-fixed-to-WordPress way

Both approaches have benefits and drawbacks, and there is no right or wrong. It's just opinionatedness, prioritizing some behavior over another.

For plugin GraphQL API for WordPress I have chosen the latter approach, attempting to create a GraphQL schema that, even though it is based on WordPress and works for WordPress, it is not tied to WordPress (for instance, by removing inconsistent names and relationships).

The result is that GraphQL rejuvenates WordPress: while we still have WordPress as our underlying CMS, with its legacy PHP code, its data layer can be created anew, based on common sense, not tradition. The data layer goes back from being an adolescent, to become a toddler again.

The result is this GraphQL schema, representing the WordPress data model, and also supporting nested mutations.

Let's check out it was carried out.

The WordPress data model permalink

WordPress has the following entities:

  • posts
  • pages
  • custom posts
  • media elements
  • users
  • user roles
  • tags
  • categories
  • comments
  • blocks
  • meta properties
  • others (options, plugins, themes, etc)

These entities can have a hierarchy. For instance, post, page and media elements are both custom post types, and tags and categories are both taxonomies.

This is the WordPress database diagram, showing how data for all entities is stored:

Is the mapping an exact replica of the DB diagram? permalink

When mapping the WordPress database into a GraphQL schema, is the same diagrame above respected 1 to 1?

No, it is not. While the database diagram is an actual implementation, GraphQL is an interface to access the data from the client. These two are related, but they can be different. GraphQL doesn't care about the database: it doesn't think in SQL commands, or know there are database tables called wp_posts and wp_users.

So we don't need to worry too much about the database diagram when creating the GraphQL schema for WordPress. That means that we can produce a GraphQL schema that fixes some of the technical debt from the WordPress data model.

Mapping the WordPress data model as a GraphQL schema permalink

Let's do the mapping. First, we map the original entities as types, as much as possible. From the list of entities in the WordPress data model, we produce the following types for the GraphQL schema:

  • Post
  • Page
  • Media
  • User
  • UserRole
  • PostTag
  • PostCategory
  • Comment

Then, we add all the expected fields to every type. To represent the schema, we can use the SDL, or Schema Definition Language. (This is used for documentation purposes only; the plugin itself does not use SDL to codify the schema: it's all PHP code).

These are the fields (among many others) for a Post:

These are the fields (among many others) for a User:

We also create the corresponding connections, which are fields that return another entity (instead of a scalar, such as a number or a string). For instance, we represent a post having an author, and a user owning posts:

Fields and connections can also accept arguments. For instance, we enable Post.date to be formatted, and User.posts to search entries and limit their number:

We keep doing this for all entities in the WordPress data model. Once we are done, we'll arrive at the GraphQL schema for WordPress, as visible using the Voyager client (available as 'Interactive Schema' on the plugin's menu):

This schema has similarities to the WordPress database diagram, but also many differences. Let's analyse them.

Operations without entity are mapped as Root fields permalink

Woocommerce github

In the WordPress database diagram represents how data is stored, so there is no 'beginning'. GraphQL, though, is an interface to retrieve data, hence there must be an initial stage from which to execute the query.

This initial stage is the Root type, or, to be more precise, the QueryRoot and MutationRoot types (to deal with queries and mutations, respectively).

In these two types, we map all operations that do not depend on an entity, such as when executing get_posts(), get_users() or wp_signon():

The fields do not need to have the same name or signature as the operation they represent. For instance, calling field logUserIn can be considered more suitable than signOn.

All mutations go under MutationRoot permalink

There are operations which do depend on an entity, such as wp_update_post(), which is applied on some post. The corresponding mutation on the GraphQL schema must be added to the MutationRoot type, because that's how GraphQL works.

Then, this operation is mapped like this:

This plugin also supports nested mutations, which are offered as an opt-in feature (because this is not standad GraphQL behavior). Then, mutations can also be added under any type, not just MutationRoot. In this case, we obtain:

Dealing with custom posts permalink

There is no type inheritance in GraphQL. Hence, we can't have a type CustomPost, and declare that Post and Page extend it.

GraphQL offers two resources to compensate for this lack: interfaces and union types.

For the first one, we create an interface IsCustomPost for the schema, declaring all the fields expected from a custom post, and we define types Post and Page to implement the interface:

For the second one, we create a CustomPostUnion type for the schema returning all the custom post types:

And have fields return this type whenever appropriate:

As it can be observed, in the GraphQL schema we need to explicitly assert when we are dealing with posts, and when with custom posts, since they are not the same! Calling these two interchangeably is technical debt from WordPress, which we can fix.

For this reason, a custom post is always called CustomPost and not Post, a field dealing with custom posts is always called customPosts and not posts, and a field argument receiving the ID for a custom post is called customPostID and not postID (even though that's how it's called in the mapped WordPress function).

Then, the expectation is always clear:

Wp Graphql
  • field User.customPosts can return a list of any custom post, including posts and pages, and User.posts only returns posts
  • field Root.setFeaturedImageOnCustomPost can add a featured image to any custom post, that's why it's not called setFeaturedImageOnPost

Not grouping tags (and categories) under a single type permalink

Why is type PostTag (and same for PostCategory) called like that, instead of just Tag?

Because, when executing this query (where a product is a CPT), the results from field tags for posts and products will always be different, non-overlapping:

Wpgraphql No Schema Available

Tags added to posts will not show up when retrieving tags for products, and the other way around (unless a product also uses the post_tag taxonomy, but then it can also be represented with the PostTag type). This does not represent a big deal in WordPress, since these items can be considered different rows from the same database table. But it does matter for GraphQL, which is strongly typed.

Then, it's a good design decision to keep these entities separate, under their own types, and have tags for posts returned under the PostTag type and, if a custom plugin implements its own product CPT, it must use the ProductTag type for its tags.

Giving media items their own identity permalink

Graphql

Media entities in WordPress are custom post types, only because it was convenient from an implementation point of view. However, the GraphQL schema can avoid this technical debt, and model media elements as a distinct entity, not as custom posts.

This implies the following decisions for the GraphQL schema:

  • When querying field customPosts, it will not fetch media elements
  • The Media type does not implement the IsCustomPost interface, and won't be part of the CustomPostUnion type
  • The Media type doesn't have many fields expected from a custom post type, such as excerpt, date and status. Instead, it only has those fields expected from a media element:

Wp Graphql Woocommerce

Identifying and mapping enums permalink

In some situations, WordPress uses fixed values from a given set. For instance, the status of a post can only be 'publish', 'draft', 'pending' or 'trash'.

In GraphQL, we can treat these as enums (instead of strings), and create a corresponding enumeration type. Following the GraphQL standard, enums should be written in uppercase, like this:

However, then the query can't be directly used to interact with WordPress, since executing get_posts( [ 'post_status' => 'PUBLISH' ] ) doesn't work.

Wp Graphql Acf

So, as a compromise, we keep these enum values in lowercase:

Mapping additional types permalink

Graphql Api Github

Blocks are not directly visible in the WordPress database diagram, since they are stored in wp_posts (there is no table wp_blocks), but nevertheless thay are a distinct entity.

Wp Graphql Gutenberg

Hence, we introduce the type Block to map them: