wp-graphql

GraphQL API for WordPress

GPL-3.0 License

Downloads
304.7K
Stars
3.6K
Committers
154

Bot releases are visible (Hide)

wp-graphql - v0.8.1

Published by jasonbahl over 4 years ago

Release Notes

Breaking Changes

n/a

New Features

  • Pass the Connection class to edges in the AbstractConnectionResolver #1212
  • #1192 Cleanup of docblocs to remove @access tag. Thanks @izzygld!
  • Updates to misc docs links
wp-graphql - v0.8.0

Published by jasonbahl over 4 years ago

Release Notes

TL;DR

This release focuses on adjusting how Nodes are resolved to prevent errors in cases where the nodes are determined to be considered private and non-viewable by the requesting user. (#1138)

More details below:

Schema Breaking Changes

Schema Breaking changes are changes to the shape of the Schema that would require clients interacting with WPGraphQL to update to remain compatible.

  • n/a: The shape of the Schema remains unchanged in this release. Clients shouldn't need to adjust their queries/mutations to remain compatible with this release.

  • ancestors field removed from Post Type Objects. Possibly will add back in the future as a formal connection.

Internal Breaking Changes

Internal Breaking Changes are changes to internals that might require plugins that extend WPGraphQL to change in order to remain compatible.

  • BREAKING: There are changes to the AbstractConnectionResolver class that affect how connections are resolved. If you are a plugin author extending this class, you will need to update your classes that extend this. Read More
  • BREAKING: Refactored ContentTypeConnectionResolver, TaxonomyConnectionResolver and UserRoleConnectionResolver to not extend the AbstractConnectionResolver class, but instead make use of the Relay::connectionFromArray() method
  • BREAKING: - Update Loaders (CommentLoader, MenuItemLoader, PostObjectLoader, TermObjectLoader, UserLoader) to return an array of resolved nodes (Models) instead of an array of Deferreds.
    • If your plugin extends or calls these classes, you may need to update your code. The loaders now return an array of Nodes (Models) instead of an array of Deferreds.

New Features

Release Summary

WPGraphQL makes use of a concept called (Deferred Resolution)[https://github.com/wp-graphql/wp-graphql/pull/722#issue-261315185], to ensure that database queries are executed as efficiently as possible.

WPGraphQL was deferring the resolution of nodes too late, causing errors when Nodes were determined to be private after being loaded.

Take the following query for example :

{
  posts {
     nodes {
         id
         databaseId
         title
     }
  }
}

This query might return a payload like so:

{
  "data": {
    "posts": {
      "nodes": [
        {
          "id": "cG9zdDoyNDI=",
          "databaseId": 242,
          "title": "Test Post"
        },
        {
          "id": "cG9zdDox",
          "databaseId": 1,
          "title": "Hello world!"
        }
      ]
    }
  },
}

Looks great! Just what we'd expect (assuming the site had only 2 posts).

Well, let's say we had a membership plugin installed (or something similar) that used meta to determine whether a Post should be considered private or not. And let's say that Post 242 was set to private and should not be returned to a public user.

Because of how the Deferred resolution was working (before this release), the Post would have been resolved too late to be stripped out of the results, and would return a null within the list of Post nodes, and would include an error like so:

{
  "errors": [
    {
      "debugMessage": "Cannot return null for non-nullable field Post.id",
      ...
    }
  ],
  "data": {
    "posts": {
      "nodes": [
        null,
        {
          "id": "cG9zdDox",
          "databaseId": 1,
          "title": "Hello world!"
        }
      ]
    }
  },
}

This behavior is problematic.

First, it throws errors, when there really isn't an error. Nothing has actually gone wrong. The user is asking for Posts, and GraphQL should be able to return posts without error.

If a Post is private, it shouldn't be exposed at all. It should be as if it doesn't even exist in the system. Be returning a null value, we are exposing that something is there behind the scenes.

The correct behavior should be to return a list of Posts, and no errors returned. If a Post is private, it should simply not be included in the list at all.

This release fixes this issue by changing how the Deferred resolution of nodes happens.

Given the query above, resolution used to work like so:

  • Posts: Use WP_Query to get a list of Post IDs. Pass those IDs to the next level of the Resolve Tree
    • Nodes: Use the ID of each node to load the Post using a Batch resolver, pass the Post through the Model Layer to determine if it's public or private, then either return the Post or return a null value

Because of the late resolution of the Node, this was causing the Cannot return null for non-nullable field Post.id error. There's no way to strip a private node out of the list of returned nodes if we're resolving nodes at the last possible tree in the Graph.

This pull request changes the behavior to resolve the nodes earlier.

Given the query above, resolution now works like so:

  • Posts: Use WP_Query to get a list of Post IDs. Pass those IDs to a Deferred Resolver. The Deferred Resolver will make a batch request and load all Nodes, passed through the Model Layer. Nodes that are null will be filtered out now. A list of resolved nodes will be passed to the next level of the Resolve Tree:
    • Nodes: Return the nodes that are passed down. Private nodes will not be passed to this level, so no errors about Cannot return null for non-nullable field Post.id will be returned.

To accomplish this, some changes to the ConnectionResolver classes were made.

Now, Nodes are resolved a step earlier, and the resolved nodes are now passed from the Connection down to Edges/Nodes.

Edges/Nodes now have the full nodes as context in their resolvers, instead of just an ID.

This can be HUGE when needing to add edge data to connections, where before an entity ID was the only context provided, and that can be too little information to be useful.

You can read more about a concrete case where the functionality was problematic, and how this release fixes it here: https://github.com/wp-graphql/wp-graphql/issues/1138#issuecomment-580269285

Changes to the Abstract Connection Resolver

Below is a list of changes the AbstractConnectionResolver Class. If your Plugin extends this class, the below information should help with upgrading.

wp-graphql - v0.7.1

Published by jasonbahl over 4 years ago

Release Notes

New Features

  • Move tests from Travis to Github Actions. Thanks @kidunot89!
  • Updates to docs for accessibility improvments. Thanks @jacobarriola!
  • Added Firecamp link to the GraphQL IDE Tools. Thanks @Nishchit14!

Bugfixes

  • Fix spelling of the GRAPHQL_MIN_PHP_VERSION constant. Thanks @curtisbelt!
  • Updated capability checks for CommentDelete and CommentUpdate mutations
  • Fixed bug in NodeResolver where it was using improper arguments. Thanks @curtisbelt!
  • Re-arrange how arguments are defined in PostObjectConnectionResolver so that default arguments for search queries are set before accounting for input arguments on the connection. This way input arguments will be used instead of defaulting to the standard search arguments. #1191
wp-graphql - v0.7.0

Published by jasonbahl over 4 years ago

Release Notes

This feature focused primarily on #1045, exposing PostTypes and Taxonomies at the root of the graph.

Breaking Changes

  • BREAKING: (#1148) change name of connections to revisions to include revisions in the name. Thanks @hsimah!
    • ex: PageToPageConnection for revisions is now named PageToRevisionConnection in the Schema
  • BREAKING: replace PostTypeEnum with ContentTypeEnum (and update all references)
  • BREAKING: remove postTypeInfo field from connections to PostTypeObjects. Each PostTypeObject node now has a contentType field to access the ContentType node it's associated with
  • BREAKING: remove taxonomyInfo from taxonomy connections. Each TermNode now has a taxonomy field to access the Taxonomy node it's associated with. The shape of the taxonomy field is now different as well.
  • BREAKING: Change the global ID for ContentType to use contentType instead of postType

New Features

  • Register connections from RootQuery->ContentType and a oneToOne connection from each PostTypeObject to it's ContentType
  • Register connections from RootQuery->Taxonomy and a oneToOne connection from each TermNode to it's Taxonomy
  • Add ContentTypeConnectionResolver for resolving connections to ContentType nodes
  • Add TaxonomyConnectionResolver for resolving connections to Taxonomy nodes
  • Add initial work for registering oneToOne connections. Used by TermNode->Taxonomy and PostObject->ContentType connections. Will be flushed out more in a PR for #347
  • Add ContentTypeIdEnum and TaxonomyIdTypeEnum
  • Add RootQuery.contentType and RootQuery.taxonomy fields to query ContentType nodes and Taxonomy nodes by ID, and supports the idType argument to use multiple types of identifiers (ID and Name, currently)
  • Update tests to reflect changes to queries for the category.taxonomy and tag.taxonomy field
  • Update tests to reflect changes to access ContentType and Taxonomy info on connections

Examples of behavior before/after

Query TaxonomyInfo (Before)

{
  tags {
    taxonomyInfo { #This returns a Taxonomy node, similar to calling get_taxonomy( 'post_tag' )
       id
       name
    }
    nodes {
       id
       name
       taxonomy { #This returns a Taxonomy type, similar to calling get_taxonomy( 'post_tag' )
         name
       }
    }
  }
}

Screen Shot 2020-01-29 at 9 27 03 AM

Query TaxonomyInfo (After)

{
  tags {
      nodes {
         id
         name
         taxonomy { # This now returns a oneToOne connection to a Taxonomy node
            
            # Note this edge space between taxonomy and node. 
            # Contextual info about the connection between the Tag node and the Taxonomy 
            # it belongs to (should there ever be any) can be added here.
            
            node { #This returns a Taxonomy node, similar to calling get_taxonomy( 'post_tag' )
               id
               name
            }
         }
      }
   }
}

Screen Shot 2020-01-29 at 9 19 10 AM

Query PostTypeInfo (before)

{
  posts {
     postTypeInfo { # This returned a PostType type, similar to calling get_post_type_object( 'post' );
        name
     }
     nodes {
         id
         title
         # Note: there is no field to query for postType or contentType from a Post object node
      }
  }
}

Screen Shot 2020-01-29 at 9 27 33 AM

Query PostTypeInfo (after)

{
  posts {
     nodes {
         id
         title
         contentType {

            # Note this edge space between contentType and node. 
            # Contextual info about the connection between the Post node and the ContentType node 
            # it belongs to (should there ever be any) can be added here.
            
            node { # This returns a ContentType node, similar to calling get_post_type_object( 'post' );
                name
            }
         }
      }
  }
}

Screen Shot 2020-01-29 at 9 18 36 AM

Query All ContentTypes (Post Types)

This RootQuery->ContentType connection allows for Content Types (post types) to be queried from the root. All properties of the ContentType can be asked for, such as labels, etc.

{
  contentTypes {
     nodes {
        id
        name
        graphqlSingleName
        graphqlPluralName
     }
  }
}

Screen Shot 2020-01-29 at 9 16 57 AM

Query Single Taxonomy Node by ID

{
  taxonomy(id: "dGF4b25vbXk6cG9zdF90YWc=") {
    id
    name
    graphqlSingleName
    graphqlPluralName
  }
}

Screen Shot 2020-01-29 at 9 22 39 AM

Query Single Taxonomy Node by Name

{
  taxonomy(id: "post_tag" idType: NAME ) {
    id
    name
    graphqlSingleName
    graphqlPluralName
  }
}

Screen Shot 2020-01-29 at 9 22 16 AM

Query Single ContentType (Post Type) by ID

{
  contentType(id: "Y29udGVudFR5cGU6cG9zdA==") {
    id
    name
    graphqlSingleName
    graphqlPluralName
  }
}

Screen Shot 2020-01-29 at 9 24 30 AM

Query Single ContentType (Post Type) by Name

{
  contentType( id: "post", idType: NAME ) {
    id
    name
    graphqlSingleName
    graphqlPluralName
  }
}

Screen Shot 2020-01-29 at 9 24 01 AM

wp-graphql - v0.6.3

Published by jasonbahl over 4 years ago

Release Notes

Bugfix

  • This updates the NodeResolver class to better resolve Posts by their path. (#1142)

Before

Screen Shot 2020-02-21 at 1 13 39 AM

After

Screen Shot 2020-02-21 at 1 25 24 AM

wp-graphql - v0.6.2

Published by jasonbahl over 4 years ago

Release Notes

Bugfix

This fixes #1144, a bug in the Model Layer that was causing cached values of a Model to attempt to execute if the string name was a function. For example, if a field's value was the string count the Model would attempt to execute the count() method instead of returning the string count.

wp-graphql - v0.6.1

Published by jasonbahl over 4 years ago

Release Notes

This is a minor release that should have no breaking changes.

Bugfixes

  • #1129: There was a regression where the menuOrder field wasn't being registered to post types that support page attributes. This was fixed by #1131. Thanks for reporting @moonmeister!

New Features

  • #1130: Added support for Github Updater. Thanks @manojhl!
wp-graphql - v0.6.0

Published by jasonbahl over 4 years ago

Release Notes

Summary

This release focused primarily on adding Interfaces for Post and Term objects.

Interfaces in GraphQL allow for common fields to be registered and shared across Types. Similar to Unions, they allow for multiple types to be queried from the same field.

By having Post Objects (posts, pages, etc) and Terms (Tags, Categories, etc) implement common interfaces, various Types can be queried for from the same entry point. So, instead of having to query only Posts or only Pages, interfaces make it possible to query for Post Objects of any type and have predictable results.

See below for examples of such queries.

Breaking Changes

  • updated formatting of URI resolvers across types to be consistent. May be a breaking change depending on your current use of uri fields when querying nodes
  • placed many fields of PostObject mutations behind conditionals to only allow inputs on Post Types that support said fields. For example, a Post Type that doesn't support author won't have an author input on its mutation anymore. Or a non-hierarchical Post Type doesn't have a parent input field by default in its mutation anymore. Might be a breaking change depending on your use of mutations and fields that a Post Type doesn't support
  • fixed a bug with settings with dashes not properly being mapped to the schema. This fix in behavior could cause a breaking change depending on what types of settings you had registered and were querying from the schema.
  • Made many fields of Post Object types (Post, Page, etc) part of Interfaces instead of the PostObject type itself, and the Types now implement the interfaces if the Post Type supports said feature. This might cause breaking changes if you were querying for fields on a Post Object Type that the Post Type doesn't actually support. For example, if you registered a post type without support for author, you could have queried for the author on that node, and got null. Now the author field will not exist on that Type and your query would not work.
  • remove __get methods from WPObjectType, WPUnionType, etc in favor of making the type_registry a public property (@kidunot89 this will affect WPGraphQL for WooCommerce)
  • Deprecate Types.php static methods
  • changed parent field to revisionOf field for Types that support revisions. If the node is a revision, the revisionOf field will return the node that it is a revision of. This is applied only to post types that support revisions via the NodeWithRevisions Interface
  • added abstract public function is_valid_offset( $offset ); to AbstractConnectionResolver. If you extend the AbstractConnectionResolver in your code, you will need to have your extending class implement this method. It is used for pagination to respect the Relay spec.

New Features

  • add support for the post format taxonomy - thanks @aberkow!
  • update testing matrix for Travis CI to cover PHP 7.1 - 7.4
  • misc updates to documentation - Thanks @aberkow, @jacobarriola, @craigfay
  • better support for respecting the Relay spec for pagination. (#1111) Thanks @let00!
  • RootQuery.contentNodes connection added, allowing for lists of Posts of any Post Type to be queried from a single Root entry point
  • All Post Object Types (Post, Page, etc) implement the ContentNode interface
  • Most fields defined in PostObjects.php have been moved into interfaces to be defined
  • Add new RootQuery.terms connection to query terms of any Taxonomy type from the root of the graph
  • Add new NodeResolver class that resolves any node (Post, Term, User) from a URI. This allows for users to pass a URI (path of the resource) to fetch nodes by
  • Update UserMutation.php to use string definition of types, instead of the Types static definitions
  • added pageTemplate field to the Post model layer
  • added uri field to the User model
  • Added the following Interfaces:
    • ContentNode
    • ContentTemplate
    • HierarchicalContentNode
    • NodeWithAuthor
    • NodeWithComments
    • NodeWithContentEditor
    • NodeWithExcerpt
    • NodeWithFeaturedImage
    • NodeWithRevisions
    • NodeWithTitle
    • NodeWithTrackbacks
    • TermNode
    • UniformResourceIdentifiable
  • Added the following Enums
    • ContentNodeIdTypeEnum
    • TermNodeIdTypeEnum
    • UserNodeIdTypeEnum
  • added ContentTemplateUnion, allowing for templates to be queried for on Post objects
  • added description to various fields missing descriptions
  • deprecated the $postType.by fields. They will still work, but they won't show in Schema docs and may be removed from the codebase in the future. This means that you can no longer query like so: postBy( slug: "slug" ) { ...postFields }, but are encouraged to query by the single entry point with the newly added idType input instead, like so: post( id: "slug" idType: SLUG ) { ...postFields }
  • added RootQuery.contentNode field for querying an individual content node from the root of the graph
  • added RootQuery.nodeByUri field for querying any node by it's resource path.
  • added RootQuery.termNode field for querying any type of term node from the root of the graph
  • updated single resource entry points by adding idType inputs. Now single resources can be queried for using various types of unique identifiers such as database id, slug, name, uri. The type of ID available depends on the type of node.

Bugfixes

  • Fixed a bug causing use of the graphql() function in PHP to break the admin bar
  • throw an exception if WPGraphQL is being used on a server with a PHP version below what WPGraphQL supports (#1099)

Issues Closed

  • #405, #263, #278, #1086, #1066, #899, #1088, #944, #1101, #1100, #1096, #1083, #1063, #1059

Examples of new functionality

Posts

We're deprecating the $postType.'By' entry points, and have added a new idType field and enum for single entry points.

This means queries such as the following will still work, but will not show in the Schema documentation, and may be formally removed from the codebase at a later date:

Deprecated Queries

{
  postBy( slug: "some-slug" ) {
    id
    title
  }
}
{
  pageBy( uri: "some-uri" ) {
    id
    title
  }
}

These are deprecated in favor of existing single entry points for each post type, and the newly added idType field on those entry points.

New Singular Post Object Queries

With the added idType field on the singular post object entry points, below is a series of example queries now made possible:

Query Single Post By Database ID

{
  post(id: 1739, idType: DATABASE_ID) {
    id
    title
    uri
    slug
    postId
  }
}

Screen Shot 2019-12-31 at 3 34 28 PM

Query Single Post by URI

{
  post(id: "/test-5/", idType: URI) {
    id
    title
    uri
    slug
    postId
  }
}

Screen Shot 2019-12-31 at 3 35 31 PM

Query Single Post by Global Hashed ID

{
  post(id: "cG9zdDoxNzM5", idType: ID) {
    id
    title
    uri
    slug
    postId
  }
}

Screen Shot 2019-12-31 at 3 34 06 PM

or without specifying idType as the default is the hashed ID

{
  post(id: "cG9zdDoxNzM5") {
    id
    title
    uri
    slug
  }
}

Screen Shot 2019-12-31 at 3 33 53 PM

Query Post (non-hierarchical post type) by Slug

{
  post(id: "test-5", idType: SLUG) {
    id
    title
    uri
    slug
  }
}

Screen Shot 2019-12-31 at 3 36 46 PM

ContentNodeInterface

This release also introduces the ContentNode Interface that is implemented by all Post Object types (posts, pages, custom post types).

This Interface allows for new types of queries to be executed that span many post types.

Content Nodes Connection

Here's an example of a new query:

{
  contentNodes {
    nodes {
      __typename
      id
      title
      link
      uri
      isRevision
      ... on Page {
        isFrontPage
      }
    }
  }
}

Screen Shot 2019-12-31 at 3 49 33 PM

In the results above, we can see that a mix of Posts and Pages have been returned.

We can also pass arguments to do things like search across multiple post types:

{
  contentNodes(where: {search: "test"}) {
    nodes {
      __typename
      id
      title
      link
      uri
      isRevision
      ... on Page {
        isFrontPage
      }
    }
  }
}

Screen Shot 2019-12-31 at 3 53 04 PM

ContentNode single entry point

We can now also fetch single Content (post) nodes like so:

{
  contentNode(id: "cG9zdDoxNzM5") {
    __typename
    id
    title
    link
    uri
    isRevision
    ... on Page {
      isFrontPage
    }
  }
}

Screen Shot 2019-12-31 at 3 59 15 PM

But, we can fetch single nodes of any Post type by other unique identifiers as well, such as the URI:

{
  contentNode(id: "/2019/12/05/test-5/", idType: URI) {
    __typename
    id
    title
    link
    uri
    isRevision
    ... on Page {
      isFrontPage
    }
  }
}

Screen Shot 2019-12-31 at 4 02 25 PM

or

{
  contentNode(id: "/test/", idType: URI) {
    __typename
    id
    title
    link
    uri
    isRevision
    ... on Page {
      isFrontPage
    }
  }
}

Screen Shot 2019-12-31 at 4 02 38 PM

This is a SUPER powerful feature as it allows for fragments to be more easily shared and re-used across queries and components.

Terms

Prior to this release, there wasn't really great ways of fetching singular term objects. You could do a query for a connection of terms and limit it to the first: 1, and in some cases that worked fine, but it wasn't always ideal.

This release adds better support for fetching individual Term Nodes.

Example Term Node Queries

Instead of only fetching by the hashed global ID, we can now fetch by other unique identifiers using the idType field.

Query Tag by Hashed Global ID

{
  tag(id: "cG9zdF90YWc6Mw==") {
    id
    name
    slug
    tagId
  }
}

Screen Shot 2019-12-31 at 4 09 37 PM

Query Tag by Database ID

{
  tag(id: 3, idType: DATABASE_ID) {
    id
    name
    slug
    tagId
  }
}

Screen Shot 2019-12-31 at 4 12 14 PM

Query Tag by Name

{
  tag(id: "Another Test", idType: NAME) {
    id
    name
    slug
    tagId
  }
}

Screen Shot 2019-12-31 at 4 12 47 PM

Query Tag by Slug

{
  tag(id: "another-test", idType: SLUG) {
    id
    name
    slug
    tagId
  }
}

Screen Shot 2019-12-31 at 4 14 06 PM

Query Tag by URI

{
  tag(id: "tag/another-test/", idType: URI) {
    id
    name
    slug
    tagId
    uri
  }
}

Screen Shot 2019-12-31 at 4 14 46 PM

TermNode Interface

This release also introduces the TermNode interface, which allows for querying terms across Taxonomy types.

For example:

Query TermNodes Connection

{
  terms {
    nodes {
      id
      __typename
      name
      uri
    }
  }
}

Screen Shot 2019-12-31 at 4 22 31 PM

This enables us to do things, like search terms across multiple taxonomies and get both Categories and Tags (and custom taxonomies) back in the same query:

{
  terms(where: {search: "test"}) {
    nodes {
      id
      __typename
      name
      uri
      ... on Tag {
        tagId
      }
      ... on Category {
        categoryId
      }
    }
  }
}

Screen Shot 2019-12-31 at 4 24 38 PM

Query Single Terms by Unique Identifiers

We can also query single term nodes by various identifiers, such as Database ID, ID, Name, Slug or URI:

Query Single Term Node by (hashed) ID

{
  termNode(id: "cG9zdF90YWc6Mw==") {
    __typename
    id
    name
    link
    slug
    uri
  }
}

Screen Shot 2019-12-31 at 4 28 01 PM

Query Single Term Node by Database ID

{
  termNode(id: 3, idType: DATABASE_ID) {
    __typename
    id
    name
    link
    slug
    uri
    databaseId
  }
}

Query Single Term Node by Name

{
  termNode(id: "Another Test", idType: NAME, taxonomy: TAG) {
    __typename
    id
    name
    link
    slug
    uri
    databaseId
  }
}

Query Single Term Node by Slug

{
  termNode(id: "another-test", idType: SLUG, taxonomy: TAG) {
    __typename
    id
    name
    link
    slug
    uri
    databaseId
  }
}

Query Single Term Node by URI

{
  termNode(id: "tag/another-test/", idType: URI) {
    __typename
    id
    name
    link
    slug
    uri
    databaseId
  }
}

Node By URI

Another thing this release provides is a way to get any node by URI, across types. This comes in handy because in many cases when a URI is provided, the type of content it is isn't always known ahead of time. By having an entry point for all Types that implement the 1UniformResourceIdentifiable` Interface, we can create a main entry point for entire applications.

Below is an example. This is showing many queries at once, but this could easily be one query with fragments for each Type, controlled by their appropriate component for rendering said type of content:

{
  page: nodeByUri(uri: "about/") {
    ...URI
  }
  post: nodeByUri(uri: "2019/12/05/test-5/") {
    ...URI
  }
  tag: nodeByUri(uri: "tag/8bit/") {
    ...URI
  }
  category: nodeByUri(uri: "category/alignment/") {
    ...URI
  }
  user: nodeByUri(uri: "author/jasonbahl/") {
    ...URI
  }
}

fragment URI on UniformResourceIdentifiable {
  __typename
  ... on Page {
    pageId
  }
  ... on Post {
    postId
  }
  ... on Category {
    categoryId
  }
  ... on Tag {
    tagId
  }
  ... on User {
    userId
  }
}
wp-graphql - v0.5.1

Published by jasonbahl almost 5 years ago

Release Notes

TL;DR

  • WPGraphQL is now officially supporting PHP 7.0+ (used to be PHP 5.6+)
  • Fixed a regression in the GraphiQL component in the Docs that was causing example queries to not execute in the documentation site

Breaking Changes

Apology: This was intended to be a non-breaking minor release, but I moved too quickly and it was brought to my attention that there actually were some regressions not on my radar. I'll try to be more careful and communicate breaking changes better in the future, namely by not releasing them as minor point releases

Regression with endpoint url

  • Previously the /graphql endpoint worked for both site_url() and home_url(), but in a Headless WordPress world we live in, many people are changing their WordPress Address and Site Address to be different things.

For example, I might have my WordPress dashboard at data.site.com/wp-admin and my headless site at site.com, so my settings in general settings might look like:

Screen Shot 2019-12-20 at 1 39 31 PM

Previously, WPGraphQL would resolve under the the site address /graphql, but if the site is actually not WordPress at all, say a Gatsby site, this doesn't make sense.

This release changed so that WPGraphQL endpoint is active at site_url(). /graphql, so in the example above that would be data.site.com/graphql

We didn't fully think through the weight of this change, largely because many of the environments I test on aren't set up with these URLs being different, so it wasn't top of mind.

I apologize for releasing this without fully thinking through the implications for users that are already in environments where their WordPress URL and Site Address are configured to be different.

Thanks @aberkow and @mlbrgl for bringing this to my attention!

Regression in Filter in PostObjectConnectionResolver

There was one breaking change introduced in this release in the way PostObjectConnectionResolver behaves. Previously this resolver class allowed only a single post_type to be passed to the class for resolutions, so $this->post_type was always a string.

Now, it is usually cast as an array, with the exception being attachment and revision as these are validated differently because of their inherit post_type nature.

If you were using the graphql_map_input_fields_to_wp_query filter, the 7th argument passed through will likely have different behavior for you now.

New Features

  • Update PHP minimum version to 7.0
  • Update GraphiQL component in Docs to v0.17.5
  • Add support for the PostObjectConnectionResolver to resolve many Post Types instead of a single Post Type (#944)
  • Don't throw error if postBy() query doesn't return a node (#1059)

Bugfixes

  • Update GraphiQL Component in Docs to not error if extensions are not passed in the response (#1071)
  • Update GraphiQL Component in Docs to not overlap the search bar in the docs (#1063)
  • Update is_graphql_http_request to use site_url() instead of home_url (thanks @kidunot89!)
  • Allow graphql() function to be used on page templates without breaking the admin header bar (#964)
  • enhance is_graphql_http_request() and add tests (Thanks @esamattis!)
wp-graphql - v0.5.0

Published by jasonbahl almost 5 years ago

Release Notes

Breaking Changes

This release is a breaking change release.

The focus of this release is on how Revisions are handled.

Prior to this release, Revisions are addd to the WPGraphQL Schema as their own Revision Type. This largely mimics WordPress implementation, in that revisions are a different Post Type. However, this doesn't lend itself well to actual use.

Revisions of a Post, declaratively speaking, are still Posts. If I paint my house, it's still a house, just with different properties. If I change the title of a Post, it's still a Post, it should be considered as much in the Graph.

The intent of revisions is to show a thing (Post, Page, etc) as it exists over time.

The Revision Type declares that the thing is in fact, a different thing, and the utility of Revisions is compromised.

By changing Revisions in the WPGraphQL Schema to be of the same Type of the object being revised, clients can actually represent their objects as they've been revised over time.

Upgrading

The Revision Type no longer exists. If you were querying for Revisions your queries will need to be updated as the Type being returned will no longer be a Revision.

Querying Root Revisions

When querying revisions from the Root, the Type returned to the connection is a ContentRevisionUnion, which is comprised of any Types that support revisions (for example, Post and Page, or any Post Type that has registered support for revisions)

You can now query revisions from the Root like so:

{
  revisions {
    nodes {
      __typename
      ... on Post {
        id
        title
        postId
      }
      ... on Page {
        id
        title
        pageId
      }
    }
  }
}

and you would get results similar to the following (dependent on your data set):

{
  "data": {
    "revisions": {
      "nodes": [
        {
          "__typename": "Post",
          "id": "cmV2aXNpb246MTcxNQ==",
          "title": "Another Test"
          "postId":1715
        },
       {
          "__typename": "Page",
          "id": "cmV2aXNpb246MTY0Mg==",
          "title": "Test Page Revision",
          "pageId": 1642,
        }
        {
          "__typename": "Post",
          "id": "cmV2aXNpb246MTcxNA==",
          "title": "Test revision",
          "postId": 1543
        }
      ]
    }
  },
}

Extending Revision Types

If you were extending the Revision Type, you will need to consider alternatives for extending the Schema for your use case.

Querying revisions of a Post will return a connection to Posts. The WordPress database will still fetch posts of the "revision" post type, but the GraphQL Schema will represent the revisions of a Post as a Post.

Querying revisions of a Page will return a connection to Pages. The WordPress database will still fetch posts of the "revision" post type, but the GraphQL Schema will represent the revisions of Pages as a Page.

Same goes for Custom Post Types.

Since revisions of a Post are always a Post, the connection is not a Union as it is when querying Revisions from the RootQuery, so we can query like so (of course this will vary based on your data set):

{
  post(id: "cG9zdDoxNzEz") {
    __typename
    id
    title
    date
    revisions {
      nodes {
        __typename
        id
        title
        date
      }
    }
  }
}

and you might get results like so:

{
  "data": {
    "post": {
      "__typename": "Post",
      "id": "cG9zdDoxNzEz",
      "title": "Test",
      "date": "2019-11-30T17:32:39",
      "revisions": {
        "nodes": [
          {
            "__typename": "Post",
            "id": "cmV2aXNpb246MTcxNQ==",
            "title": "Test",
            "date": "2019-11-30T17:33:10"
          },
          {
            "__typename": "Post",
            "id": "cmV2aXNpb246MTcxNA==",
            "title": "Test",
            "date": "2019-11-30T17:32:20"
          }
        ]
      }
    }
  }

Because Revisions of a Post are now represented as a Post, we can make use of some great GraphQL features, such as Query Fragments. We could refactor the above query like below, using the same fragment for the primary Post and the revisions of it, allowing for the same components to be used to render a Post and a revision of a Post. Powerful stuff!:

{
  post(id: "cG9zdDoxNzEz") {
    __typename
    ...PostFields
    revisions {
      nodes {
        __typename
        ...PostFields
      }
    }
  }
}

fragment PostFields on Post {
  id
  title
  date
}

Does this close any currently open issues?

closes #1017

wp-graphql - v0.4.3

Published by jasonbahl almost 5 years ago

Release Notes

Bugfixes

  • #1042 adds is_graphql_request and is_graphql_http_request Thanks @esamattis @kidunot89!
  • #1043 Don't call for allowed post types at the init hook
  • #1052 TypeRegistry->getTypes() not available to graphql_register_types action

New Features

  • #1050 add displayName to UserRole type
wp-graphql - v0.4.2

Published by jasonbahl almost 5 years ago

Release Notes

Bugfixes

wp-graphql - v0.4.1

Published by jasonbahl almost 5 years ago

Release Notes

  • Update composer dependencies
  • Update filter on WPGraphQL::get_allowed_taxonomies()
  • Update to Docs for WPGraphQL for ACF - Thanks @henrikwirth!
  • Update to Install and Activate Docs - Thanks @jacobarriola!
  • Update to Docs sidebar styles - Thanks @TylerBarnes!
  • Add Router::is_graphql_request() method - Thanks @esamattis!
  • Fix issue with PostObjectMutation not respecting term inputs if graphql_plural_name was capitalized in the registration
  • Prevent execution of connections if the source Post is null
  • Fix PostObjectCursor issue with meta_value_num compares - Thanks @kidunot89!
  • Fix UserLoader for orphaned users - Kellen
  • Adjustments to Comment Model - Ryan
  • Add Interface inheritance for Types implementing Interfaces - Thanks @kidunot89!
  • Fix PHP warning in InstrumentSchema.php
  • Add tests for Interfaces
  • add Page.isFrontPage field to the Schema - Thanks @zgordon!
wp-graphql - v0.4.0

Published by jasonbahl almost 5 years ago

Release Summary

This release is centered around Issue #846. Plugins that extend the WPGraphQL Schema are very difficult to test because once the Schema is created, it can't be cleared or modified. This is because of the heavy use of Statics, which make testing very difficult.

This Release changes many of the Static classes to classic objects that are instantiated and passed down using Dependency Injection.

This makes it much easier to create instances of the Schema on the fly, which is essential for extension plugins to do when testing their extensions. It also helps the core plugin properly test API methods like register_graphql_field, register_graphql_mutation, etc.

These changes make it easier for extensions to write and execute tests.

Because of the statics, the WPGraphQL Schema could be generated just once for the entire test suite, which means to test things like registering custom fields in ACF will add fields to the WPGraphQL Schema would mean that all fields would need to be added in the Bootstrap of the test suite, and not within the individual test that's testing the fields.

This is problematic to scaling tests. Ideally, we want to follow the AAA method of testing:

  • Arrange: setup what we need to test
  • Act: execute what we want to test
  • Assert: assert that the execution behaved as expected

What this means is that if we wanted to test something like adding an ACF Text field (doesn't have to be ACF, just an example) we would want a test that:

  • registers an ACF field group
  • registers an ACF Field to that group
  • creates a post
  • updates meta to the ACF field of that post
  • execute a GraphQL Query for the post and the field
  • assert that the field registered in ACF added a field to the Schema and resolves as expected

We cannot do that today, but with this release, we can! Now, each test can "own" everything needed to test its behavior.


Breaking Changes

The primary breaking change here is making the TypeRegistry class no longer a singleton, so the methods are not statically accessible anymore. Instead, the TypeRegistry is an object that is passed down in the context of the graphql_register_types action.

If your code was previously making use of any static methods from the TypeRegistry class, such as TypeRegistry::get_type( 'TypeName' ) you will need to refactor a bit.

Upgrading

Below is an example from the WPGraphQL for Gravity Forms plugin that needs to change:

@kellenmace pointed out:

I am using TypeRegistry::get_type(), here: https://github.com/harness-software/wp-graphql-gravity-forms/blob/master/src/Types/Union/ObjectFieldUnion.php#L45
src/Types/Union/ObjectFieldUnion.php:45

To upgrade to v0.4.0, this code should be changed from:

public function register_type() {
        $field_mappings = $this->get_field_type_mappings();
        register_graphql_union_type( self::TYPE, [
            'typeNames'   => array_values( $field_mappings ),
            'resolveType' => function( GF_Field $field ) use ( $field_mappings ) {
                if ( isset( $field_mappings[ $field['type'] ] ) ) {
                    return TypeRegistry::get_type( $field_mappings[ $field['type'] ] );
                }
                return null;
            },
        ] );
    }

to:

public function register_type( $type_registry ) {
        $field_mappings = $this->get_field_type_mappings();
        register_graphql_union_type( self::TYPE, [
            'typeNames'   => array_values( $field_mappings ),
            'resolveType' => function( GF_Field $field ) use ( $field_mappings, $type_registry ) {
                if ( isset( $field_mappings[ $field['type'] ] ) ) {
                    return $type_registry->get_type( $field_mappings[ $field['type'] ] );
                }
                return null;
            },
        ] );
    }

Here we can see that the callback is passed the $type_registry as it's a callback of the graphql_register_types action. The $type_registry is the instance of the TypeRegistry, and now the get_type method can be used. We changed TypeRegistry::get_type() to $type_registry->get_type().

NOTE:, we are using a closure for the resolveType so we have to pass $typeRegistry through with the use statement.


Todo before release:

  • Write Release Summary (@jasonbahl)
  • Ensure Docs reflect current changes (@TylerBarnes)
  • Test/upgrade WPGraphQL Insights for compatibility (@jasonbahl)
  • Test/upgrade WPGraphQL for ACF for compatibility (@jasonbahl)
  • Test/upgrade WPGraphQL Tax Query for compatibility (@jasonbahl)
  • Test/upgrade WPGraphQL Meta Query for compatibility (@jasonbahl)
  • Test/upgrade WPGraphQL JWT Authentication for compatibility (@jasonbahl)
  • Test/upgrade WPGraphQL Dad Jokes for compatibility (@jasonbahl)
  • Test/upgrade WPGraphQL Custom Post Type UI for compatibility (@jasonbahl)
  • Test/upgrade WPGraphQL for WooCommerce for compatibility (@kidunot89)
  • Summarize breaking changes and upgrade path (@jasonbahl, with feedback from @kidunot89 and @TylerBarnes)
wp-graphql - v0.3.8

Published by jasonbahl almost 5 years ago

Release Notes

Breaking changes

none

Bugfix

  • Removes error that is thrown in the PostObjectLoader when a Post cannot be loaded from the IDs passed to it. (#982)

New Features

none

wp-graphql - v0.3.7

Published by jasonbahl about 5 years ago

Release Summary

Breaking Changes

Shouldn't be any. Please report if you come across any issues.

New features

  • add mediaItemUrl field to MediaItem Type. Thanks @jydmnd!
  • add public getters to AbstractConnectionResolver class
  • update WordPress, MySQL and Docker versions for test environment. Thanks @mngi-arogers!
  • Add husky to lint the codebase when pull requests are opened. Thanks @TylerBarnes!
wp-graphql - v0.3.6

Published by jasonbahl about 5 years ago

🚀 Release Notes

Breaking Changes

  • Shouldn't be any 🎉

New Features

  • Add proper support for cursor pagination for users. Thanks @let00!!
  • Update docs to show added info for debugging
  • Add check for auth errors to allow execution to be stopped if authentication is attempted and fails
wp-graphql - v0.3.5

Published by jasonbahl about 5 years ago

🚀 Release Notes

Potential Breaking Changes:

If you were making use of filtering users by role, the behavior has changed due to #890 to respect access control properly.

Bugfixes

  • Fixes #869: Fixes bugs when registering multi-word option_group name with underscores in WordPress. Thanks @sbarry50!
  • Fixes #871: PostObject fields "srcSet" and "sizes" no longer resolved at the model layer. Thanks @kidunot89!
  • Fix incorrect enum for contentType field in Comments Schema. Thanks @let00!
  • Fix include/exclude schema descriptions. Thanks @BDMayhem!
  • #909: Fixes issue with docker mysql/mariadb. Thanks @epeli!
  • #890: Prevent filtering users by role if requestor doesn't have proper caps.
  • #897: Fixes cursor pagination not preserving order with the "search" where arg

Enhancements

  • #885: Creates WPSchema config variable. Thanks @mjacobsen4DFM!
  • #894: Updates docker config. Thanks @mngi-arogers!
  • #919: Code standards formatting updates. Thanks @dingo-d!
wp-graphql - v0.3.4

Published by jasonbahl over 5 years ago

🚀 Release Notes

Implemented enhancements:

  • Added a CHANGELOG.md!!
  • #796 - Add srcSet field to media items #858 (jasonbahl)
  • #802 - Throw exception for invalid list_of / non_null Types #856 (jasonbahl)

Fixed bugs:

  • Cannot define list of non null strings as return type #849
  • Cursor pagination not working with custom ordering #818
  • v0.3.x menuItems connectedObject issue #810
  • Bug/#810 menu items connected object term issue #855 (jasonbahl)
  • #839 - Fix typo with cssClasses #853 (jasonbahl)
  • #849 - This ensures that list_of and non_null can be used with each other #850 (jasonbahl)
  • Make the post date field to conform to RFC3339 #821 (manzoorwanijk)

Closed issues:

  • Pagination not working for pageBy and taxQuery queries #861
  • Docker tests are failing #859
  • wp-graphql-jwt-authentication plugin doesn't work after upgrading from 0.2.3 -> 0.3.3? #854
  • Page where "in" query not returning any results #844
  • Pass $source to edge resolver #840
  • menuItem cssClasses is always null #839
  • Hooking WooCommerce Categories to GraphQL #835
  • Query pages results in server error #833
  • Error when creating comments on latest dev branch #827
  • The post date field does not conform to RFC3339 #822
  • Bug/Enhancement: Report references to missing types in debug mode #802
  • Add src-set to attachments #796
  • 0.3.0 bug: Queries on 'posts' with category value return internal server error #788
  • Tests for preflight OPTIONS requests #260
  • Fieldname Audit #221
  • Unit Tests for PostObjectsConnection Resolver #86

Merged pull requests:

wp-graphql - v0.3.3

Published by jasonbahl over 5 years ago

🚀 Release Notes

(Potential) Breaking Changes

If you were using WPGraphQL::$allowed_post_types or WP_GraphQL::$allowed_taxonomies in your custom code, we recommend updating to use WPGraphQL::get_allowed_post_types() and WPGraphQL::get_allowed_taxonomies() instead, as some changes in this PR could potentially cause you issues.

Bugfixes

This release fixes several regressions that snuck by in the v0.3.0 release cycle.

  • #812 Addresses #811, where the $where args for querying menus was not properly being respected post v0.3.0. Thanks for reporting and your patience as we resolved, @josephCarrington!
  • #814 Fixed a regression with Custom Post Type id fields not working properly. Thanks @benallfree!
  • #816 addressed #815, where static definitions of WPGraphQL::$allowed_post_types were causing funkiness.
  • #824 addresses #823, where Custom Taxonomy terms were loading funky in some cases. Thanks for reporting and working through this, @paulisloud, @seagyn!
  • Fix to hideEmpty description on Term connection args. Thanks @epeli!

New!!

  • Updates to Docker testing environment. Thanks @mngi-arogers!
  • #831 New "success" field returned for createComment payload so the mutation can respond with something indicating the createComment succeeded, even if the user doesn't have access to get an unapproved comment returned as a result of the mutation. Thanks for working through this with me @paulisloud!
Package Rankings
Top 0.97% on Packagist.org
Top 6.68% on Proxy.golang.org
Badges
Extracted from project README
Total Downloads Monthly Downloads Daily Downloads Latest Stable Version License Actions Status Actions Status Coverage Status Backers on Open Collective Sponsors on Open Collective
Related Projects