Category: Updates

  • What’s next for WPGraphQL?

    On February 1, I announced that I was no longer employed at Gatsby, and stated a blog post would be coming soon.

    This is that blog post.

    TL;DR

    I’m joining WP Engine as a Principal Software Engineer where I will continue maintaining WPGraphQL and will contribute to other projects and initiatives centered around the goal of making WordPress the best headless CMS.

    Below I will expand a bit more on “Why WP Engine?”, but first, I’d like to take a moment to reflect on my time at Gatsby and acknowledge how important Gatsby is to the future of headless WordPress.

    WPGraphQL and Gatsby

    I am incredibly thankful for the opportunity I had to work at Gatsby to push forward WPGraphQL. Gatsby’s investment in WPGraphQL led to a lot of growth and maturation of the project

    Project Growth and Maturation

    I joined Gatsby in June 2019, and since then, WPGraphQL went from:

    Community Growth

    In addition to the growth and maturation of the core WPGraphQL plugin, the community around it has also grown.

    While I believe WPGraphQL would have seen growth in the community regardless, I believe we can attribute at least some of this growth to Gatsby’s investment in WPGraphQL. Gatsby’s investment in WPGraphQL signaled that it wasn’t just a hobby project, but was solving real problems for real users, and users should have confidence using it in their projects.

    When I joined Gatsby to work on WPGraphQL and collaborate with Tyler Barnes on WPGatsby and Gatsby’s new WordPress Source Plugin, the JavaScript ecosystem paid much more attention to using WordPress as a headless CMS, and the WordPress community got more comfortable using WordPress in ways they hadn’t before.

    Many agencies, developers and site owners now consider WPGraphQL an essential part of their stack.

    WordPress plugin developers have now created more than 30 WPGraphQL extensions, and there are now more than 1,500 people in the WPGraphQL Slack!

    Agencies such as Zeek Interactive, WebDev Studios, 10up and Postlight use and recommend WPGraphQL for headless WordPress projects.

    Websites such as gatsbyjs.com, qz.com, denverpost.com, diem.com, apollographql.com, bluehost.com, rudis.com and many more are using WPGraphQL in production.

    So, why leave Gatsby?

    Gatsby has been incredibly generous in funding open source developers to work on projects related to, but not part of Gatsby. For example, John Otander was working on MDX, Rikki Schulte was working on GraphiQL, and I was working on WPGraphQL.

    I was the last remaining of these engineers working primarily on other projects that tangentially, but not directly benefit Gatsby.

    WordPress is only one part of Gatsby’s story. Gatsby can work well with just about any data source. Some popular non-WordPress choices are Contentful, Sanity, DatoCMS, Shopify, among many others.

    The team I was part of was asking me to start transitioning to work more on other Gatsby integrations, such as Contentful and Shopify, and work less on WordPress and WPGraphQL. This doesn’t mean Gatsby was abandoning WordPress or WPGraphQL, just that I would need to spend less time on it and prioritize other things. There’s nothing wrong with this. There’s a lot of sound decision making to this when it comes to making Gatsby a sustainable business.

    I feel right now is a unique time in history where more investment in WordPress as a headless CMS can change the future of WordPress. I believe WordPress is now more respected as a viable option for a headless CMS and that with the momentum of WPGraphQL, technologies like Gatsby, NextJS, and others, I need to spend more time focusing on WPGraphQL and headless WordPress, and not less time.

    Fortunately for me, WP Engine is investing in the future of headless WordPress, and they see WPGraphQL as an important part of that future.

    As ironic as it may sound, I believe that my departure from Gatsby will actually strengthen the WordPress + Gatsby integration.

    Instead of partially focusing on the Gatsby side of the integration and partially focusing on the WordPress API side of the integration, this move will allow Gatsby to hire a backfill for my position to work specifically on the Gatsby side of integrations, and not have to worry about the WordPress server API side of things. This allows the team to narrow their focus and deliver higher quality code on the Gatsby side of the Gatsby + WP integration.

    I intend to continue working with Tyler Barnes and the Gatsby Integrations and Collaborations team to ensure that users of Gatsby + WPGraphQL feel supported and productive. Gatsby + WPGraphQL will continue to play a big role in the future of Headless WordPress, and I’m here for it.

    Why WP Engine?

    Serendipity, at least to some degree.

    Within a few weeks of having conversations about needing to start focusing less on WPGraphQL at Gatsby, I discovered that WP Engine was building a headless WordPress framework and was hiring engineers to focus on headless WordPress. The job description felt like it was describing me, almost perfectly. Serendipity.

    A few years ago, prior to my time at Gatsby I was interested in a position at WP Engine. But at the time there was a hard requirement for employees to be in Austin, TX. I have so many friends and family members in Denver that I have no plans to move if I don’t absolutely have to. WP Engine no longer requires employees to be in Austin, so I could now work for WP Engine without needing to move. Serendipity.

    Along with the serendipitous aligning of stars, WP Engine is a generally attractive employer.

    WP Engine is a leader in the WordPress space. I’ve trusted WP Engine to host many sites I’ve worked on over the last decade, including WPGraphQL.com and jasonbahl.com.

    While WP Engine’s primary business is managed WordPress hosting, it also invests in a lot of products and projects that make it easier for businesses to run their sites on WordPress.

    Projects such as LocalWP (that I gave a shout out to on Syntax.fm in Jul 2019) and Genesis Blocks are thriving under WP Engine, and I believe that WPGraphQL can continue to mature and thrive with WP Engine’s support.

    WP Engine’s investment in headless WordPress isn’t limited to me joining to continue working on WPGraphQL and other headless WordPress projects. There will be more hires and projects aimed at reducing the friction of using WordPress as a headless CMS, and allowing businesses to get started and move faster within that context.

    I believe that WP Engine’s investment in this space will allow WPGraphQL to grow and mature faster than ever before, as I will be part of a larger team working to make WordPress the best it can be.

    So, does WP Engine own WPGraphQL?

    Before my time at Gatsby, during my time at Gatsby and now as I transition to working at WP Engine, WPGraphQL has and will continue to be operated and maintained as a free, open-source community plugin benefitting anyone using WordPress.

    WP Engine pays my salary, and in exchange I will be maintaining WPGraphQL and helping grow the headless WordPress ecosystem, reducing friction in many different ways.

    What’s next for WPGraphQL?

    I can’t officially commit to any of these things quite yet, but some things I have on my radar to tackle in the near future include, but are not limited to:

    • Significant updates to WPGraphQL for Advanced Custom Fields
    • Updates to the GraphiQL IDE that ships with WPGraphQL (testing as public and authenticated user, for example)
    • Introduce new Custom Scalars (datetime, HTML, among others)
    • Add Support for Image Uploads
    • Update Schema surrounding Media
      • Introduce a MediaItem interface and different GraphQL Types for Image, Video, etc
    • New tooling to help developers move faster
      • Query / error logging
      • Breaking change notifications
      • Persisted Queries
      • Query Complexity configuration and analysis
    • WPGraphQL Subscriptions (real time updates when data changes)
    • Component library(s) using WPGraphQL Fragments
    • More tutorials, videos, blog posts about using WPGraphQL in various contexts

    I’m excited to get started at WP Engine and work on the next chapter of WPGraphQL and headless WordPress! I hope to have a more formal roadmap to discuss with the community in the near future, once I get settled as a WP Engine employee.

    I’m so thankful to the community that has embraced WPGraphQL. I feel so much love and appreciation from thousands of developers that are using, contributing to, and providing feedback for WPGraphQL.

    I’ve made many genuine friends from the WPGraphQL community and I am so thankful that this next chapter of my career allows me to continue working in this community.

  • Announcing WPGraphQL v1.0

    I’m so excited to announce WPGraphQL 1.0!

    If you’ve been using WPGraphQL for your side projects, but are waiting for the “stable” version, then this is it! You can use WPGraphQL in production with the confidence that it is secure, well documented, and supported full time and long term.

    If you’re new to the WPGraphQL community, you may ask yourself, “But WordPress already has the REST API. What’s different about using WPGraphQL?”

    Well, when you use WPGraphQL to turn your WordPress site into a GraphQL server, multiple resources can be fetched at the same time. And by design you get back the exact data you asked for, nothing more, nothing less. In addition to being easier to work with compared to the REST API, data loading with GraphQL is faster and more efficient. (Read more: “WPGraphQL vs. WP REST API“)

    If you are upgrading to 1.0 or another version, see the release notes for information on breaking changes and preparing your site. If you are new, start at the homepage and follow our step-by-step docs.

    In this post I want to talk about the journey to 1.0, why it took so long to get to 1.0, and a look at what’s next for WPGraphQL. But before diving into that, I want to also announce some other fun stuff that has also come to life along with this release.

    • WPGraphQL is now available on the WordPress.org repository
    • New WPGraphQL.com website
    • WPGraphQL Swag available on the Gatsby Swag Store

    WPGraphQL on WordPress.org

    The WordPress.org plugin repository has long been the default distribution mechanism for WordPress plugins. Prior to today, developers had to install WPGraphQL using Composer and installing from packagist, or by downloading from Github.

    Now, users can install WPGraphQL directly from WordPress.org’s plugin directory.

    We believe that distributing WPGraphQL on the WordPress.org plugin repository should make it easier for users to find and install and keep updated.

    New WPGraphQL.com website

    WPGraphQL.com has been re-built from the ground up.

    Before today, WPGraphQL had 2 primary domains:

    • WPGraphQL.com, a “traditional” WordPress site using WordPress as the CMS and the theme layer
    • docs.wpgraphql.com, a Gatsby site using Markdown files in a Github repository for the content.

    Now, instead of splitting some content in Markdown files on Github and some content in WordPress, WPGraphQL.com now uses WordPress as the CMS for all content, and and has a Gatsby front-end powered by the new Gatsby Source WordPress plugin, WPGatsby and of course WPGraphQL.

    We’ll be releasing tutorials and videos in the coming weeks and months walking through how various parts of the site were created to provide inspiration for you to build great things with this stack as well, but for now you can draw inspiration from the repository this site is built from: https://github.com/wp-graphql/wpgraphql.com

    WPGraphQL Swag

    Now, possibly the most exciting thing about this whole announcement, is the fact that you can now get WPGraphQL Swag from the Gatsby swag store.

    The Journey to 1.0

    WPGraphQL was started in November 2016 (with no commit message ???? ) and has come a long way in that time.

    Screenshot of the “Initial Commit” in Github

    By the end of 2017 the codebase was pretty robust and provided a Schema to interact with many parts of WordPress. Posts, Pages, Custom Post Types, Tags, Categories, Custom Taxonomies, Comments and Nav Menus.

    Qz.com was the first site to go to production with WPGraphQL, even before I was using it in production! A few years later and they are still running on WPGraphQL! You can learn more about the early days of their stack from this presentation from December 2017.

    In early 2018, my team took WPGraphQL into production on a network of 54 large WordPress sites. WPGraphQL was used as a syndication engine for our network of newspapers. Unlike most GraphQL users, we didn’t initially have a JavaScript or native mobile UI that was using GraphQL, we had PHP WordPress servers syndicating content and GraphQL solved a lot of pain points we had been facing when using REST.

    By the end of 2018, more than 100 sites were using WPGraphQL in some way.

    Now, WPGraphQL seems to be running all over the place!

    This is a non-comprehensive list of sites using WPGraphQL in production in some way:

    According to Packagist.org as of June 30, 2020 there were nearly 50,000 installs of WPGraphQL in the wild, and as of November 2020 Packagist reports 71,573 installs.

    In 2019 Credit Karma paid for a security audit on the plugin and all reported issues were resolved.

    It’s safe to say, WPGraphQL is production ready!

    So, why the wait for 1.0?

    So, if WPGraphQL has been production ready for such a long time, why is is still not 1.0?

    Breaking Changes & WordPress

    The WordPress ecosystem has a strong commitment to backward compatibility. This means that once functionality is introduced to a WordPress plugin, it often sticks around forever.

    With that in mind, before tagging WPGraphQL 1.0, I wanted so badly to be at a place with the codebase & Schema that I could no longer predict anymore breaking changes.

    I wanted the GraphQL Schema to be “perfect” before tagging it 1.0, because I knew that whatever would be in the WPGraphQL Schema at 1.0 would need to remain in the Schema forever. The WordPress community is used to things working the same way “forever” and I wanted to play along.

    Breaking Changes & WPGraphQL

    The reality is that for software to get better, sometimes it needs to make breaking changes.

    WPGraphQL will never be perfect, and it will need to occasionally break to make things better.

    For example, when the GraphQL Specification updates to include Input Unions or Interfaces that can implement other Interfaces, WPGraphQL will need to break to keep up with the GraphQL Specification.

    There would be no way to keep GraphQL as we know it today and take advantage of tomorrow’s GraphQL Spec without breaking.

    WPGraphQL turning 1.0 isn’t a statement that there will never be breaking changes, instead it’s a statement of stability and long term support.

    So, how will breaking changes be handled in a post-1.0 world?

    Semantic Versioning

    WPGraphQL has been following Semver practices for a few years. We will continue to follow Semver and let version numbers communicate meaning. The summary of Semver versioning is as follows:

    • MAJOR version when you make incompatible API changes,
    • MINOR version when you add functionality in a backwards compatible manner, and
    • PATCH version when you make backwards compatible bug fixes.

    You can read more about the details of Semver at semver.org

    Seamless Upgrade Paths

    When WPGraphQL needs to make breaking changes to the Schema, there are sometimes ways to make the changes and allow for seamless upgrade paths.

    What that means, is that WPGraphQL can introduce a new feature while keeping the old feature. For example, let’s say the following (hypothetical) query were in the Schema and the author field returned the name of the Author:

    {
      book {
        author
      }
    }
    

    Let’s say we realized that the Author should actually be a one-to-one connection to an object with edge space for relational context. We would want to change the schema to allow for the following query instead.

    {
      book {
         author {
             node {
                 name
              }
         }
      }
    }
    

    If WPGraphQL made this change, any consumer application would break.

    So, what we can do is introduce the new feature like so:

    {
       book {
         author
         authoredBy {
            node {
                name
            }
         }
       }
    }
    

    We could introduce the new feature as a new field name authoredBy which returns the data in the shape we want.

    The end goal, however, is to have the author field return the author.node.name shape.

    So, with both fields (author and authoredBy) co-existing on the server, consumer applications could make use of GraphQL Aliases and update their code from:

    {
      book {
         author
      }
    }
    

    to:

    {
       book {
          author: authoredBy { # Consumer uses an alias to prepare for the upcoming change to the author field
              node {
                 name
              }
          }
       }
    }
    

    Once consumers have updated their code, the server could then update once more to flip the old field name to the new shape. So, the next release would have the following possible:

    {
       book {
          author {
             node {
                 name
              }
          }
          authoredBy {
            node {
                name
            }
         }
       }
    }
    

    So now, the old field author no longer returns the name directly, it now returns the new nested node/name shape. The client is using an alias to query the authoredBy field, so now the consumer should update their code from:

    {
       book {
          author: authoredBy { # Consumer uses an alias to prepare for the upcoming change to the author field
              node {
                 name
              }
          }
       }
    }
    

    to:

    {
       book {
          author
              node {
                 name
              }
          }
       }
    }
    

    Now, the consumer application is using the new shape of data and the old author field, and one more release would be able to remove the temporary authoredBy field that was used for seamless upgrades.

  • WPGraphQL v0.8.0

    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.

    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.
    • 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

    • Accessibility improvements for the documentation. (See: #1049, #1150) Thanks @jacobarriola!
    • Remove resolveNode config arg from most connections registered by the core plugin as the new method for resolving connections doesn’t wait until the last second to resolve nodes
    • For example: https://github.com/wp-graphql/wp-graphql/compare/master…release/next?expand=1#diff-a04db7b019ce5a16e141cd35799a0718L19-L21, https://github.com/wp-graphql/wp-graphql/compare/master…release/next?expand=1#diff-0b5f575771fc27faf7455a8fa0a05d93L79-L81

    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.

    • AbstractConnectionResolver adds the following breaking changes:
    • abstract public function get_loader_name()
      • This method was added to tell the connection resolver what Loader to use to load nodes using Deferred resolution. In order to extend the AbstractConnectionResolver, a Loader will also need to be created. You can see the existing Loaders here.
      • see: https://github.com/wp-graphql/wp-graphql/compare/master…release/next?expand=1#diff-015d5cec0dcc9f802dcfa99bc136f478R252-R260
    • abstract public function get_ids()
      • replaces previous get_items() method
      • This method was added as a way to tell the resolver what IDs we’re dealing with. In many cases, the IDs are returned by the query, and this method can extract them from the Query.
      • see: https://github.com/wp-graphql/wp-graphql/compare/master…release/next?expand=1#diff-015d5cec0dcc9f802dcfa99bc136f478R297
    • abstract public function get_node_by_id()
      • This method was added to tell the loader how to resolve the node as a Model, ensuring it gets properly passed through the Model layer
      • see: https://github.com/wp-graphql/wp-graphql/compare/master…release/next?expand=1#diff-015d5cec0dcc9f802dcfa99bc136f478R328-R335
    • Changed access of some methods from public to protected as they’re not intended to be used outside of the class or extending classes
      • get_amount_requested(), get_offset(), get_query_amount(), has_next_page(), has_previous_page(), get_start_cursor(), get_end_cursor(), get_nodes(), get_cursor_for_node(), get_edges(), get_page_info()

  • WPGraphQL v0.7.0

    WPGraphQL v0.7.0 is here!
    https://github.com/wp-graphql/wp-graphql/releases/tag/v0.7.0

    This release focused primarily on exposing Post Type and Taxonomy nodes at the root of the query.

    This release does include some breaking changes, so it’s highly recommended that you read the release notes and test on a staging server before updating.

  • WPGraphQL v0.6.0 Release

    WPGraphQL v0.6.0 is here!

    This release is one of the most significant releases in the history of the WPGraphQL plugin.

    Breaking Changes

    Before getting into the hype of the release, I want to highlight some prominent breaking changes. A full list can be found in the release notes.

    • A change to pagination of connections was introduced and any plugin/theme that has a class extending the AbstractConnectionResolver will need to add a public method is_valid_offset to support pagination properly. Not adding this method to extending classes will cause errors.
    • Many fields of Post Object Types (Post, Page, Custom) are now only exposed on the Type if that post_type supports the feature. For example, the “page” post type doesn’t support excerpts in core WordPress. Prior to this release you could query the field excerpt when querying for pages. You no longer can ask for the field excerpt on Pages because Pages don’t support excerpts. Posts do support excerpts, so you can query that field on Posts. If you were querying fields that a Post Type didn’t support, this release might break some of your queries.
    • We fixed a bug with settings registered 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.

    New Features

    This release focused primarily on Interfaces. A full list of new features can be found on the release notes.

    In GraphQL, an Interface is an abstract type that defines a certain set of fields that a type must include to implement the interface.

    In WPGraphQL, prior to this release, the only Interface that was defined and implemented was the node interface, which defined the ID field. Any Type, such as Post, Page, Category, Tag, Comment or User, that implements the node interface must have an ID field. And thus, any of these types could also be fetched by ID.

    Take the following query for example:

    query GET_NODE {
      node(id:"cG9zdDoyMjE5") {
        __typename
        id
        ...on Post {
          title
        }
        ...on Page {
          title
          date
        }
      }
    }

    In the example query, we pass an ID of a node. If, during execution, the server determines the ID is that of a Post, it will return to us the __typename, id, and title, but if it is determined that the ID is that of a Page, it will return the __typename, id, title and date.

    Interfaces allow us to ask for any Type that implements said interface and in response we can ask for the common fields, and can specify the different fields we want based on the Type that is resolved at execution.

    This allows for applications to be built with a high level of predictability.

    Your application is now able to predict what fields will be returned based on the Type being returned. This type of interaction with an API can eliminate entire classes of bugs.

    New Interfaces

    After this release, we now have many more interfaces to join the Node interface.

    The following are Interfaces introduced in this release:

    • TermNode: Defines fields shared across Terms of any Taxonomy Type
    • ContentNode: Defines common fields shared by Post object nodes. Not all fields of Post Types are common across all Post Types. Each Post Type can register/deregister support for numerous fields. The fields that cannot be different are defined in this interface and all Post types implement this Interface.
    • UniformResourceIdentifiable: Defines a uri field. Implemented by Nodes that can be accessed by URI.
    • NodeWithTitle: Defines a title field. Implemented by post types that support titles.
    • NodeWithContentEditor: Defines the content field. Implemented by post types that support the editor.
    • NodeWithAuthor: Defines the author field, connecting a Node to its author. Implemented by post types that support authors.
    • NodeWithFeaturedImage: Defines the featured image field, connecting a Node to its featured image. Implemented by post types that support thumbnails.
    • NodeWithComments: Defines comment fields. Implemented by post types that support comments.
    • HierarchicalContentNode: Defines hierarchical fields (parent/children). Implemented by hierarchical post types.
    • ContentTemplate: Defines a template field.
    • NodeWithRevisions: Defines revisions fields. Implemented by post types that support revisions.
    • NodeWithExcerpt: Defines the excerpt field. Implemented by post types that support excerpts.
    • NodeWithTrackbacks: Defines fields related to trackbacks and pingbacks. Implemented by post types that support trackbacks.

    I cannot provide examples of using every one of these interfaces, but I will cover some examples that should be valuable to WPGraphQL users.

    Content Node Interface

    The ContentNode interface allows for nodes of different Post Types to be queried in a single connection. Prior to this release, Posts of each type were fetched from their dedicated entry points. For example, you could query for { posts { ...fields } } or { pages { ...fields } }, but now, you can query a single collection spanning many post types.

    Here’s an example:

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

    And we might see results like the following:

    {
      "data": {
        "contentNodes": {
          "nodes": [
            {
              "__typename": "Post",
              "id": "cG9zdDoyMjE5",
              "link": "http://acf.local/2020/01/14/test-revisions/",
              "uri": "2020/01/14/test-revisions/"
            },
            {
              "__typename": "Page",
              "id": "cGFnZToxNjQw",
              "link": "http://acf.local/test-page-revision/",
              "uri": "test-page-revision/",
              "isFrontPage": false
            },
          ]
        }
      }
    }

    In this example, we can see that we are receiving both a Post and a Page in the same connection query, and are able to specify common fields, but also able to specify a specific field we want if the Type is Page.

    This flexibility allows WPGraphQL users to create robust User Interfaces with flexibility, but also predictability.

    URI Interface

    The UniformResourceIdentifiable Interface added in this release allows for any node that can be identified by URI to be queried for from a single entry point.

    This is incredibly powerful for headless WordPress applications.

    When interacting with a WordPress site, it’s incredibly common for a user to have a URI, a path to a resource. Typically that path is entered into a browser, and WordPress is able to return the proper page for that resource. The template and data displayed by WordPress is different based on the type of resource (page, post, user, term) it is.

    WPGraphQL can now interact the same way.

    A user can pass a URI to WPGraphQL, and specify what it wants in return based on the Type that the resource resolves as.

    The following example shows how to query for a nodeByUri for a Post, Page, Tag, Category and User, specifying different fields for each Type.

    {
      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
      uri
      ... on Page {
        pageId
      }
      ... on Post {
        postId
      }
      ... on Category {
        categoryId
      }
      ... on Tag {
        tagId
      }
      ... on User {
        userId
      }
    }

    And the response might look like:

    {
      "data": {
        "page": {
          "__typename": "Page",
          "uri": "about/",
          "pageId": 1086
        },
        "post": {
          "__typename": "Post",
          "uri": "2019/12/05/test-5/",
          "postId": 1739
        },
        "tag": {
          "__typename": "Tag",
          "uri": "tag/8bit/",
          "tagId": 45
        },
        "category": {
          "__typename": "Category",
          "uri": "category/alignment/",
          "categoryId": 4
        },
        "user": {
          "__typename": "User",
          "uri": "author/jasonbahl/",
          "userId": 1
        }
      },
    }

    This is incredibly powerful for headless applications that might only have a URI of a resource to identify the resource by. Now headless applications can resolve resources with a high level of predictability, even without knowing the type of resource up front.

    What’s next

    Now that this monumental release is here, the next release will have a focus on Connections. There are many bugs and new features that we want to address that affect the behavior of connections. Keep an eye out for more details there.

  • WPGraphQL v0.4.1

    Today we released WPGraphQL v0.4.1. This is a non-breaking change release. You can view the release here: https://github.com/wp-graphql/wp-graphql/releases/tag/v0.4.1

    Release Summary

    • 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!

  • WPGraphQL at the Desert GraphQL Meetup

    Last night I had the pleasure of remotely presenting for the Desert GraphQL Meetup in Phoenix, Arizona.

    TL;DR, Here’s the video

    Video recording of the GraphQL for WordPress meetup presentation

    Here’s the slides:

    https://slides.com/jasonbahl-1/desert-graphql-oct-2019#/

    Summary of the presentation

    In the presentation I covered the history of WPGraphQL, why the plugin exists, and why it makes sense to continue building for the wider WordPress community.

    We look at some of the frustrations with the WordPress REST API that lead to the creation of WPGraphQL.

    I quickly reviewed what WordPress looks like, as in what the WordPress Dashboard looks like and what it enables out of the box.

    Next, I show how activating WPGraphQL activates a GraphQL API for your WordPress and the WPGraphiQL Plugin adds the GraphiQL IDE to your WordPress dashboard.

    We then look at what WordPress looks like, visually, as an Application Data Graph and how to use GraphQL Queries to pick trees out of that graph.

    Next we looked at various live examples of GraphQL Queries and explored features of the GraphQL Query Language, such as querying multiple resources in a single request, using variables, arguments, fragments, aliases and directives.

    We then compare how to build the same slice of UI using PHP, REST and GraphQL to show how much lower effort it is to use GraphQL compared to alternatives.

    I finish up talking about some things I’ve learned while building WPGraphQL, and what’s next now that I am part of the GatsbyJS team.

  • Release v0.3.5

    Today we released v0.3.5 of WPGraphQL.

    Full release notes here: https://github.com/wp-graphql/wp-graphql/releases/tag/v0.3.5

  • WPGraphiQL IDE v1.0.0 with GraphQL Explorer

    The GraphiQL IDE is an incredibly helpful tool when using GraphQL. WPGraphiQL has been the go-to GraphiQL IDE for use with WPGraphQL, and today we’ve released v1.0.0 of the WPGraphiQL IDE, now with the AMAZING GraphQL Explorer feature, courtesy of the fine folks at OneGraph.com.

  • Upgrading to v0.3.0

    WPGraphQL v0.3.0 is one of the most substantial releases to date for the plugin. You can read more about what was included in this release here and here.

    Test in Staging Environment

    It’s best practice to test plugin updates in staging environment, but I want to re-iterate that again here. Make sure you thoroughly test things when you update this plugin to v0.3.0, especially if you have any custom code that extends the Schema in any way.

    Break: “roles” field on User type has changed shape

    The User Type in the Schema previously had a roles field that returned a list of role names as strings.

    Pre v0.3.0

    {
      users {
        nodes {
          roles
        }
      }
    }

    Would return something like the following:

    {
      "data": {
        "users": {
          "nodes": [
            {
              "roles": [ 'administrator' ]
            }
          ]
        }
      }
    }

    v0.3.0

    In v0.3.0, the roles field has changed to a Connection of roles. The query would change to something like the following:

    {
      users {
        nodes {
          roles {
            nodes {
              name
            }
          }
        }
      }
    }

    This change was made largely because Roles aren’t _really_ properties of a user. Roles are defined as entities on their own, and Users have a connection to one or more roles.

    Break: Resolvers return models instead of WP_* instances

    If you were extending some of the core Types in the Schema by adding fields, the first argument passed to the resolver used to be an instance of a core WP_* class. For instance, the Post Type would pass an instance of WP_Post down to field resolvers on that Type. Now, it will pass an instance of \WPGraphQL\Model\Post.

    Here’s an example of a Field that may have been registered to the “old” version of the Schema:

    register_graphql_field( 'Post', 'myNewField', [
      'type' => 'String',
      'resolve' => function( \WP_Post $post, $args, $context, $info ) {
        $data = get_post_meta( $post->ID, 'some_data', true );
        return $data ? data : null;  
      }
    ] );

    Here, we see the first argument passed down is a \WP_Post. In v0.3.0, that would be a \WPGraphQL\Model\Post like so:

    register_graphql_field( 'Post', 'myNewField', [
      'type' => 'String',
      'resolve' => function( \WPGraphQL\Model\Post $post, $args, $context, $info ) {
        $data = get_post_meta( $post->ID, 'some_data', true );
        return $data ? data : null;   
      }
    ] );

    The following resolvers changed:

    • \WP_Post is now \WPGraphQL\Model\Post
    • \WP_User is now \WPGraphQL\Model\User
    • \WP_Comment is now \WPGraphQL\Model\Comment
    • \WP_Term is now \WPGraphQL\Model\Term

    The full list of Models now available, that replaced what was there previously, is:

    • \WPGraphQL\Model\Avatar
    • \WPGraphQL\Model\Comment
    • \WPGraphQL\Model\CommentAuthor
    • \WPGraphQL\Model\Menu
    • \WPGraphQL\Model\MenuItem
    • \WPGraphQL\Model\Plugin
    • \WPGraphQL\Model\Post
    • \WPGraphQL\Model\PostType
    • \WPGraphQL\Model\Taxonomy
    • \WPGraphQL\Model\Term
    • \WPGraphQL\Model\Theme
    • \WPGraphQL\Model\User
    • \WPGraphQL\Model\UserRole

    Depending on how you were extending the Schema, this may or may not have any affect on you.

    Break: DataSource methods

    The signature of DataSource methods have changed. If you were calling any DataSource methods in your extensions, you’ll likely need to refactor a bit. We recommend checking out the changes to that file so you understand all the changes for the methods you’re using, but here’s a quick example pointing out the difference:

    Pre v0.3.0:

    DataSource::resolve_post_object( $id, $post_type );

    v0.3.0

    DataSource::resolve_post_object( $id, $context );

    The specific way in which the signature for the DataSource method changed may be different depending on the method. If you’re calling any of these methods, check how it changed to be sure you’re using it the new way.

    Break: Connection Resolver Classes

    If you were making use of the ConnectionResolver classes in anyway, they’ve been completely revamped. They’ve been moved into the /Data/Connection directory, and are now stateful classes instead of classes with static methods. They are now much easier to digest and understand how to extend and create your own Connection Resolvers.

    I won’t cover changes in detail here, but if you wrote any custom Connection Resolvers, and the new way of doing it doesn’t make sense after reading the new code, feel free to reach out and we can do our best to help you update.

    Break: All kinds of restricted content is actually restricted now

    With the introduction of the Model Layer, many fields and nodes that were previously accessible in public requests have now been restricted.

    For example, our documentation previously mentioned that fields such as email on the User type was publicly exposed, and that if you wanted to hide it, you could do so via filter.

    We’ve implemented a formal Model Layer that now handles restrictions like this out of the box, so fields that you may have been querying before, might not be returned anymore. Depending on your use case, this may be a break to you application, so it’s something to get familiar with.

    How the Model Layer Works

    We’ve written some docs on the Model Layer, but the general idea is that if you download install WordPress with nothing active but a standard `twenty-*` theme, the data that is exposed to a user should be the same data that is exposed to a GraphQL request.

    For example, a non-authenticated user cannot access draft Posts in a vanilla WP install, so WPGraphQL will not return Draft posts to non authenticated users. (There’s more logic than that, but that’s just an example).

    There are dozens of conditions in place that help determine whether fields should or should not be returned to the consumer making the request.

    Other Breaking Changes

    There might be some other breaking changes that we didn’t cover here. If you read this guide and also get familiar with the latest info on https://docs.wpgraphql.com, but still run into issues that break your application after updating to v0.3.0, please reach out in Slack or Spectrum, or Open a Github Issue and we’ll do our best to help you get upgraded. We also highly recommend getting familiar with the source code of v0.3.0. We’ve commented the code very heavily to help provide an understanding of how everything is working and why it’s working that way.

    If you find something you believe is a bug, as usual, please open an issue on Github