Author: Jason Bahl

  • What’s coming in v0.3.0?

    The next release of WPGraphQL will be version v0.3.0, and is slated to be released next week.

    This release is arguably the most substantial release to date. It’s going to made up of 2 major features: “DataLoader” and “Model Layer

    DataLoader

    The role of DataLoader is to load data as efficiently as possible. You can read some of the highlights in the PR comment here: https://github.com/wp-graphql/wp-graphql/pull/722#issue-261315185

    Model Layer

    The goal of the Model Layer is to centralize access control to objects and properties throughout the Graph. In short, that means we just want to make things more secure.

    At the moment, some potentially sensitive data is exposed by default, and it’s the site owner’s responsibility to filter and adjust the Schema and resolvers to only expose data they want to be exposed in the API. You can read more about that here (under the Sensitive Data heading): https://docs.wpgraphql.com/getting-started/users

    The Model Layer switches the plugins stance to be more restrictive by default, and allow site owners to loosen the restrictions when necessary, instead of expecting site owners to go through the effort of limiting potentially private content out of the box. Of course, each application is different, and our defaults may not be what you need for your application, so you will be able to filter access at a very granular level to make the GraphQL API work best for your specific needs.

    The Model Layer centralizes access checks by taking into consideration the “current_user” making the request, then determines what objects (Posts, Terms, Comments, etc) and fields of those objects (Title, Content, etc) should be exposed to the user making the request. Fields like user emails will now only be exposed by default to authenticated users with “list_users” capabilities, for example. If you want to make override that new default and expose a field that we have restricted, you’ll have the ability to control that via various filters.

    We’ll be working on a formal upgrade guide, as there will be numerous breaking changes for this release, but we think they’re all very welcome breaking changes.

    You can keep an eye on progress in the branches here:

    Security Audit

    Over the past weekend we received the results of a Security Audit performed by Simone Quatrini of Pen Test Partners. The security audit pointed out some Insecure Access Control violations. Most of the violations in the report had already been resolved by the in-progress Model Layer branch, such as exposed user email addresses, which, as mentioned above is documented here.

    There were 2 issues presented that we were not on our radar and we are grateful to Simone for bringing to our attention. We will be patching shortly as part of the v0.3.0 release. One issue, in particular, will be fixed for previous versions of the plugin as well, and details will be published about that once it has been resolved.

    Full details of the Security Audit and resolutions to the issues will be published after the v0.3.0 release and other mentioned patches have been released.

  • WPGraphQL at WordCamp Montreal


    Étienne Bélanger gave a talk at WordCamp Montreal 2018 titled: “Your First Headless WordPress Project with ReactJS and GraphQL”.

    In the talk, he covers some basic differences between the WP REST API and WPGraphQL, then shows how to use React and Apollo Client to consume data from a WordPress site with the WPGraphQL plugin active.

    Great talk, Étienne! – and thanks for sharing the video with us.

  • WPGraphQL + Gatsby Tutorial

    Zac Gordon put together a group of engineers to work on a formal project, GatsbyWPThemes.com to port popular WordPress themes to Gatsby themes.

    Recently, Muhammad Muhsin published a tutorial showcasing how users can create a Gatsby theme using WordPress as the CMS and WPGraphQL as the API for Gatsby to consume data from.

    Take a look at the tutorial, and let us know what you build with Gatsby and WPGraphQL!

  • Release v0.2.3

    Today we released a new version of WPGraphQL, v0.2.3.

    The release can be found here: https://github.com/wp-graphql/wp-graphql/releases/tag/v0.2.3

    Below is a recap of the release notes:

    Breaking Changes

    • none

    New Features

    • #676: New TimezoneEnum type added to the Schema
    • #719: New graphql_menu_item_connection_args and graphql_menu_item_connection_query_argsfilters added to the MenuItemConnectionResolver. Thanks @epeli!

    Bug Fixes

    • #714 Fixes global $post not properly being setup before resolving fields for posts. Thanks @epeli!
    • #716: Adjusts how the MenuLocationEnum values are determined to include all locations, not just locations with a menu already assigned.

  • Preventing unauthenticated requests to your WPGraphQL API

    Someone asked in the Slack channel how they could lock down the WPGraphQL endpoint so that only authenticated users could access it.

    Provided Solution

    add_action( 'do_graphql_request', 'force_graphql_api_authentication', 10, 1 );
    
    function force_graphql_api_authentication( $query ) {
    	if ( ! defined( 'GRAPHQL_HTTP_REQUEST' ) || true !== GRAPHQL_HTTP_REQUEST ) {
    		return;
    	}
    
    	$introspection_query = \GraphQL\Type\Introspection::getIntrospectionQuery();
    	$is_introspection_query = trim($query) === trim($introspection_query);
    
    	if ( $is_introspection_query ) {
    		return;
    	}
    
    	if ( ! get_current_user_id() ) {
    		throw new \GraphQL\Error\UserError( __( 'You do not have permission to access the API', 'your-textdomain' ) );
    	}
    }

    What this does

    Below, I’ll walk through what this snippet does.

    Hook into the GraphQL request lifecycle

    add_action( 'do_graphql_request', 'force_graphql_api_authentication', 10, 1 );

    This snippet hooks into the do_graphql_request action, which is fired when a GraphQL request is about to be executed, and fires the function force_graphql_api_authentication

    The action passes 4 args to the force_graphql_api_authentication callback: $query, $operation, $variables and $params. For this particular case, we only care about the first argument, $query, which is the query string to be executed.

    Determine if the request is an HTTP Request

    Since WPGraphQL can be used internally within your Plugin and Theme PHP code to hydrate data for page templates, shortcodes, etc, locking down all GraphQL requests could have unintentional consequences, so we don’t want to prevent all unauthenticated requests from executing with GraphQL, we just want to prevent unauthenticated requests coming over HTTP.

    So we first check:

    if ( ! defined( 'GRAPHQL_HTTP_REQUEST' ) || true !== GRAPHQL_HTTP_REQUEST ) {
      return;
    }

    This checks to see if the request is indeed a GraphQL HTTP Request. If it’s not, it simply returns and we let GraphQL carry on as usual. That means internal GraphQL requests using the graphql() function can be processed as usual.

    Ignore Introspection Queries

    GraphQL has an awesome feature where the Schema itself is queryable. Tools such as WPGraphiQL, GraphQL Playground and Altair make use of the IntrospectionQuery to fetch the Schema and render Schema documentation for users.

    $introspection_query = \GraphQL\Type\Introspection::getIntrospectionQuery();
    $is_introspection_query = trim($query) === trim(introspection_query);
    
    if ( $is_introspection_query ) {
      return;
    }

    Here we use a helper method from the underlying GraphQL PHP library which is part of WPGraphQL to get the Introspection Query.

    $introspection_query = \GraphQL\Type\Introspection::getIntrospectionQuery();

    Then, we compare the incoming query, which is passed through the do_graphql_request action to check if the incoming query is an IntrospectionQuery or not:

    $is_introspection_query = trim($query) === trim(introspection_query);

    And last, if we’ve determined that the incoming query is indeed an IntrospectionQuery, we return and allow GraphQL to execute as normal. This will allow GraphQL to execute the Introspection Query and send the Schema back to the tool requesting it.

    if ( $is_introspection_query ) {
      return;
    }

    Throw an error if the request is not authenticated

    Lastly, we check to see if the request is authenticated by checking for the ID of the current user. If the ID is “0”, then the request is not authenticated, so we want to throw an error.

    if ( ! get_current_user_id() ) {
    	throw new \GraphQL\Error\UserError( __( 'You do not have permission to access the API', 'your-textdomain' ) );
    }

    Conclusion

    With this snippet, you can lock down your WPGraphQL endpoint so nothing will be executed if the request is not authenticated.

    If you need to make authenticated requests, we recommend using WPGraphQL JWT Authentication, but any of the Auth plugins that work for the REST API plugin _should_ work well with WPGraphQL as well.


    NOTE:

    The Application Passwords plugin requires a filter to play nice with WPGraphQL:

    add_filter( 'application_password_is_api_request', function( $api_request ) {
      if ( defined( 'GRAPHQL_HTTP_REQUEST' ) && true === GRAPHQL_HTTP_REQUEST ) {
         return true;
      }
      return $api_request;
    });
  • Querying Sticky Posts with GraphQL

    Recently, a WPGraphQL user asked how to query only sticky posts with a GraphQL query. 

    One of the great things about WPGraphQL is how customizable it is with hooks and filters, making it easy to extend the API for your needs. 

    End goal

    One (of many possible) solutions would be to allow the client to specify that they only want sticky posts as an argument on the posts connection query.

    A query could look something like the following: 

    query GET_STICKY_POSTS {
      posts( where: {onlySticky: true }) {
        nodes {
          id
          title
          date
          link
        }
      }
    }

    This query would allow the client to specify that they want posts, but onlySticky posts

    This should give us what we were looking for, a way to query only sticky posts using WPGraphQL. 

    The issue is that the onlySticky argument doesn’t exist in the WPGraphQL plugin, so if we want to use it, we’ll need to add it ourselves.

    Register the “onlySticky” argument

    To add this field as an argument, we can use the following snippet:

    add_action( 'graphql_register_types', function() {
        register_graphql_field( 'RootQueryToPostConnectionWhereArgs', 'onlySticky', [
            'type' => 'Boolean',
            'description' => __( 'Whether to only include sticky posts', 'your-textdomain' ),
        ] );
    } );

    Here we hook into the graphql_register_types action, to make sure the GraphQL Type registry is ready to be hooked into. 

    Next, we register a field to the GraphQL schema by using the register_graphql_field() method.

    The first argument is the name of the Type to register the field to. In our case, that Type is RootQueryToPostConnectionWhereArgs. This is the Input Type that is used by the root posts field to provide filters to the query. 

    The next argument is the name of the field we’re registering. Here, we’re using onlySticky as the field name. 

    The third argument is an array to configure the field. We declare the Type the field should be is Boolean, meaning it should be either true or false, and provide a description for the field. 

    At this point, our query would validate, as onlySticky would be a valid argument on the query now, but our actual results aren’t affected.

    Filter the WP_Query to respect the onlySticky input

    The next step we need to take is to filter how WPGraphQL resolves the query and make sure it respects the onlySticky argument that was input. 

    We can do so with the following snippet:

    add_filter( 'graphql_post_object_connection_query_args', function( $query_args, $source, $args, $context, $info ) {
        if ( isset( $args['where']['onlySticky'] ) && true === $args['where']['onlySticky'] ) {
            $sticky_ids = get_option( 'sticky_posts' );
            $query_args['posts_per_page'] = count( $sticky_ids );
    	$query_args['post__in'] = $sticky_ids;
        }
        return $query_args;
    }, 10, 5 );

    Here, we filter graphql_post_object_connection_query_args. This filter can be found in the PostObjectConnectionResolver.php file in the WPGraphQL plugin. 

    This allows for the $query_args that are prepared to send to WP_Query for execution to be filtered prior to WP_Query fetching the posts. 

    Inside this filter, we check to see if the $args that were passed through the resolver from GraphQL include the onlySticky input, and if that value is true

    If those conditions are met, then we define custom $query_args, by first getting a list of the sticky posts, then asking to query only those IDs and the posts_per_page equal to the number of sticky posts we have. 

    Then we return the modified $query_args for WP_Query to use to resolve the query.

    In action

    Now, we can see our query in action. 

    First, go set a couple posts to sticky, if you haven’t already:

    Screenshot showing a few sticky posts

    Then, using WPGraphiQL, execute the query, and the results returned should only be the Sticky posts!

    GIF showing how the query with onlySticky set to true, and the results being only sticky posts

    Conclusion

    My hope is that this shows how easy it is to extend WPGraphQL for your system’s needs. The plugin is powerful out of the box, but if you have custom needs for your application, take advantage of the various hooks and filters in the plugin to make it work for you!

  • Introducing playground.wpgraphql.com

    I’ve done many presentations about the WPGraphQL plugin, and I find myself showing demos of many of the same features, so in order to streamline the demos before my presentation at the 2018 WordCamp Phoenix, I created https://playground.wpgraphql.com

    This site showcases examples of GraphQL Queries and Mutations on a live WordPress site with the WPGraphQL plugin active. The demos start out very basic, and as you work down the list, you will see progressively more advanced examples of GraphQL use cases, demonstrating both unique features of the WPGraphQL plugin and the broader GraphQL Query Language.

    Enjoy.

  • WPGraphQL Featured on FreeCodeCamp

    FreeCodeCamp is a popular YouTube channel that posts free videos about coding. Today, Jesse Weigel did a live coding session diving into using GraphQL with WordPress and after comparing a few options, he settled on using WPGraphQL.

    Watching the video was eye opening. It was great to see that folks are interested in using GraphQL with WordPress, but it was also clear that the documentation and resources to get started using WPGraphQL are still pretty lacking. Documentation will be a focus over the next few weeks to make sure folks have what they need to get up and running with WPGraphQL.

    Thanks, Jesse for featuring the plugin!

    Check out the video from FreeCodeCamp here:

     

     

  • Tracing for WPGraphQL

    In 2015, Huey Petersen wrote an article about instrumenting a GraphQL schema to track resolver times and provide insight into how the GraphQL server is performing. Since then Apollo Optics has taken the instrumentation to a new level, providing a SaaS solution for storing data about your GraphQL requests. The Apollo team has also been working on a proposal to standardize the instrumentation, and they’re calling it Apollo Tracing.

    The proposed spec is still young, but the goal is to come up with a standard for how GraphQL schemas should record performance metrics for requests and their resolvers so that tools like Apollo and perhaps even GraphiQL or others can make use of these standard extensions.

    While the spec is still young, having these metrics is pretty important for us, so we’ve introduced WPGraphQL Insights. It’s a plugin that adds tracing to your WPGraphQL server. The plugin is pretty early in development, so I wouldn’t suggest running it in production quite yet, but feel free to test it out on your local/dev environments and provide any feedback on the Github repo so we can make it better!

    The near-future plans for the WPGraphQL Insights plugin are:

    • add the ability for the server to enable/disable tracing
      • add a settings page
      • define via a constant, ex: define( ‘GRAPHQL_TRACING’, true );
    • allow the client to request tracing in the response (see this discussion)
    • provide storage options for the trace data
      • We’re working with the Apollo Optics team to figure out how we can get the trace data from a WPGraphQL server into Optics
      • We’re experimenting with storing trace data locally in WordPress to some degree
      • We’re experimenting with sending the data elsewhere, like logstash/elasticsearch.

    Here’s a look at tracing in action on WPGraphQL. Enjoy!

  • Using GraphQL Queries in PHP within your WordPress Theme or Plugin

    GraphQL is most popularly known as a way to fetch data from remote sources via HTTP requests, but with WPGraphQL, you can access your local WordPress data in your plugin or theme via declarative GraphQL queries. An example use case would be a simple shortcode for a list of posts.

    Example shortcode that outputs a list of posts and is populated with the site’s content with a GraphQL query

    Let’s look at how we can build a simple shortcode that populates a list of posts from the site and renders an unordered list with the post’s title and date. First, lets register our shortcode:

    add_shortcode( 'graphql_basic_post_list', function( $atts ) {
      return ! empty ( $output ) ? $output : '';
    } );

    Now we have a [graphql_basic_post_list] shortcode but it’s not useful. Our end goal is to output a list of posts with the title and date, and we’ll use the ID as the “id” of each list item. Since we know what data we’ll need, we can start with writing our GraphQL query to get the data. Inside the shortcode function, let’s add our query. GraphQL queries are static strings, so we can simply add:

    $query = '
    query basicPostList($first:Int){
       posts(first:$first){
          edges{
             node{
                id
                title
                date
             }
          }
       }
    }
    ';
    
    $data = do_graphql_request( $query );

    This will give us an array of posts, which contains an array of “edges” and each edge will contain a “node”. The node is our post object, and this is where the fields we requested are. In our case, we asked for idtitle, and date. The raw data returned from the query should look like this (of course with your site’s data):

    [data] => Array (
    	[posts] => Array (
    		[edges] => Array (
    			[0] => Array (
    				[node] => Array (
    					[id] => cG9zdDoyOTI0
    					[title] => Test GraphQL Basic Post List
    					[date] => 2017-08-19 14:49:25
                    )
                )
                [1] => Array (
    				[node] => Array (
    					[id] => cG9zdDoyOTE3
    					[title] => Test Color Field
    					[date] => 2017-08-11 19:42:10
                        )
                    )
                [2] => Array (
    				[node] => Array (
    					[id] => cG9zdDoyODc0
    					[title] => Denverpost Content in Gutenberg
    					[date] => 2017-08-04 21:22:17
                    )
                )
                [3] => Array (
    				[node] => Array (
    					[id] => cG9zdDoyNDA3
    					[title] => Fieldmanager Test, yo
    					[date] => 2017-06-28 16:25:13
                    )
                )
                [4] => Array (
    				[node] => Array (
    					[id] => cG9zdDoyMzg2
    					[title] => Testing a Gutenburg(sp?) Post
    					[date] => 2017-06-23 21:02:57
                    )
                )
            )
        )
    )

    This data looks pretty easy to work with! Now we just need to loop through the data and return our markup.

    $edges = ! empty( $data['data']['posts']['edges'] ) ? $data['data']['posts']['edges'] : [];
    
    if ( ! empty( $edges ) && is_array( $edges ) ) {
       $output = '
      '; foreach ( $edges as $edge ) { $node = ! empty( $edge['node'] ) ? $edge['node'] : ''; if ( ! empty( $node ) && is_array( $node ) ) { $output .= '
    • ' . $node['title'] . ' ' . $node['date'] . '
    • '; } } $output .= '
    '; }

    This makes sure that we have an array of “edges” and if we do, it creates an unordered list and loops through the edges, creating a list item for each node, with the node’s id as the <li> id property, and the post’s title and date as the text within the list item. The complete shortcode, with an example argument for how many posts to query is:

    add_shortcode( 'graphql_basic_post_list', function( $atts ) {
       $query = '
       query basicPostList($first:Int){
          posts(first:$first){
             edges{
                node{
                   id
                   title
                   date
                }
             }
          }
       }
       ';
    
       $variables = [
          'first' => ! empty( $atts['first'] ) ? absint( $atts['first'] ) : 5,
       ];
    
       $data = do_graphql_request( $query, 'basicPostList', $variables );
    
       $edges = ! empty( $data['data']['posts']['edges'] ) ? $data['data']['posts']['edges'] : [];
    
       if ( ! empty( $edges ) && is_array( $edges ) ) {
          $output = '
      '; foreach ( $edges as $edge ) { $node = ! empty( $edge['node'] ) ? $edge['node'] : ''; if ( ! empty( $node ) && is_array( $node ) ) { $output .= '
    • ' . $node['title'] . ' ' . $node['date'] . '
    • '; } } $output .= '
    '; } return ! empty( $output ) ? $output : ''; });

    NOTE: this post was written using Gutenberg v0.9.0