GraphQL & WordPress

JS for WordPress Online Conference

Jason Bahl | @jasonbahl

Me.

  • Senior WordPress Engineer at Digital First Media in Denver, CO
  • Denver native
  • WordPress Developer for 9+ years
  • I love WordPress, and Open Source in general
  • Creator & maintainer of WPGraphQL

This Talk.

  • What is GraphQL?
  • Compare GraphQL with existing WordPress APIs
  • How to use GraphQL with WordPress
  • Use GraphQL with Gutenberg

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools

GraphQL

A Query Language for your API

GraphQL

Open Source Specification

Created & maintained by Facebook

Used in production by Facebook since 2012

GraphQL

Graph != Graph Databases

Graph != Graph Search

Graph = Application Data Graph

QL = Query Language

GraphQL: A Query Language for Your Application Data Graph

GraphQL

{
     me {
          name
     }
}

{

     data: {

          me: {

               name: "Jason Bahl"

          }

     }
}

GraphQL Query

GraphQL Result

Post

Category

Category

Category

Post

title

"Hello World"

title

"GoodBye Mars"

Image

Image

Image

name

"news"

name

"crime"

name

"sports"

Image

WordPress as an Application Data Graph

GraphQL

GraphQL lets us pick trees out of the Application Data Graph

GraphQL

query {
  post(id: "...") {
    title
    link
    categories {
      nodes {
        name
      }
    }
  }
}
{
  data: {
    post: {
      title: "Hello World!"
      link: "http://site.com/hello-world"
      categories: {
        nodes: [
          {
            name: "sports"
          },
          {
            name: "crime"
          }
        ]
      }
    }
  }
}

Post

Category

Category

Category

Post

title

"Hello World"

title

"GoodBye Mars"

Image

Image

Image

name

"news"

name

"crime"

name

"sports"

Image

Comparing APIs

Comparing APIs

Data Requirements:

  • List of posts
  • author
    • name
    • avatar (size: 50)
      • url
  • site
    • name
    • link
  • followLink
  • title
  • featuredImage (width: 300)
    • url
  • excerpt

Comparing APIs

<?php
$posts = new WP_Query( 
    array(
        'post_type' => 'post',
        'posts_per_page' => 4,
        'post_status' => 'publish'
    ) 
);

# Loop through the posts
<?php
# Author Data
$author = get_the_author();
$author_name = $author->display_name;
$avatar = get_avatar_data( $author->ID );
$avatar_url = $avatar->url;
# Site Info
$sites = wp_get_post_terms( 
    $post->ID, 'sites' 
);
$site_name = $sites[0]->name;
$site_link = get_term_meta( 
    $sites[0]->term_id, 
    'link', 
    true 
);
# Follow Link
$follow_link = your_follow_link_func();
# Title
$title = get_the_title();
# Featured Image
$img = get_the_post_thumbnail_url( 
    $post->ID, 
    array( 300 ) 
);
# Excerpt
$excerpt = get_the_excerpt();

Comparing APIs

# Posts

# Assumes follow link is a registered
# field on the post endpoint

HTTP GET 
/wp-json/wp/v2/posts?per_page=4

$posts.map((post) => {
    $title = post.title;
    $excerpt = post.excerpt;
    $follow = post.followLink;
});
# Authors

HTTP GET 
/wp-json/wp/v2/user/{posts[0].author}
/wp-json/wp/v2/user/{posts[1].author}
/wp-json/wp/v2/user/{posts[2].author}
/wp-json/wp/v2/user/{posts[3].author}
/wp-json/wp/v2/user/{posts[0].author}/avatar
/wp-json/wp/v2/user/{posts[1].author}/avatar
/wp-json/wp/v2/user/{posts[2].author}/avatar
/wp-json/wp/v2/user/{posts[3].author}/avatar
# Sites 

# Assumes REST API was customized to show
# The "Sites Custom Taxonomy" IDs on the 
# Post endpoint

HTTP GET 
/wp-json/wp/v2/site/{posts[0].sites[0]}
/wp-json/wp/v2/site/{posts[1].sites[0]}
/wp-json/wp/v2/site/{posts[2].sites[0]}
/wp-json/wp/v2/site/{posts[3].sites[0]}
# Featured Images

HTTP GET
/wp-json/wp/v2/media/{posts[2].featured_media}
/wp-json/wp/v2/media/{posts[3].featured_media}

Comparing APIs

            
 query { 
  posts(first: 4) {
    edges {
      node {



        














      }
    }
  }
}
            
        
            
        author {
       name
       avatar(size: 50) {
         url
       }
     }

            
        
            
                        followLink

            
        
            
                        title

            
        
            
                        featuredImage(width: 300) {
   url
}

            
        
            
                        excerpt

            
        
            
        site {
       name
       link
     }

            
        

Data Requirements:

  • List of posts
  • author
    • name
    • avatar (size: 50)
      • url
  • site
    • name
    • link
  • followLink
  • title
  • featuredImage (width: 300)
    • url
  • excerpt

Observed Pain Points

Completely different experience using PHP and REST

# WordPress, PHP with WPGraphQL Active

$query = '
{
    posts {
        edges {
            node {
                id
                title
                link
            }
        }
    }
}
';

$data = do_graphql_request( $query );
# JavaScript, using Fetch
const query = `{
    posts {
        edges {
            node {
                id
                title
                link
            }
        }
    }
}
`;

fetch('site.com/graphql', {
    method: "POST", 
    body: {
        query: query
    }
});

Similar experience using GraphQL in PHP, or any other language

<?php
# Author Data
if ( $posts->have_posts() ) {
    while ( $posts->have_posts() ) {
        $posts->the_post();
       
        $author = get_the_author();
        $author_name = $author->display_name;
        $avatar = get_avatar_data( 
            $author->ID 
        );
        $avatar_url = $avatar->url;
    }
}
# Author Data
HTTP GET 
/wp-json/wp/v2/user/{posts[0].author}
/wp-json/wp/v2/user/{posts[1].author}
/wp-json/wp/v2/user/{posts[2].author}
/wp-json/wp/v2/user/{posts[3].author}
/wp-json/wp/v2/user/{posts[0].author}/avatar
/wp-json/wp/v2/user/{posts[1].author}/avatar
/wp-json/wp/v2/user/{posts[2].author}/avatar
/wp-json/wp/v2/user/{posts[3].author}/avatar
# CURL

$ curl -XPOST
  -H "Content-Type:application"
  -d '{"query":"{
      posts{
          edges{ 
              node{ 
                  id
                  title
                  link
              }
          }
      }
  }"}'
  http://site.com/graphql

Observed Pain Points

Lots of Functions / HTTP Requests

HTTP GET 
/wp-json/wp/v2/posts?per_page=4
/wp-json/wp/v2/user/{posts[0].author}
/wp-json/wp/v2/user/{posts[1].author}
/wp-json/wp/v2/user/{posts[2].author}
/wp-json/wp/v2/user/{posts[3].author}
/wp-json/wp/v2/user/{posts[0].author}/avatar
/wp-json/wp/v2/user/{posts[1].author}/avatar
/wp-json/wp/v2/user/{posts[2].author}/avatar
/wp-json/wp/v2/user/{posts[3].author}/avatar
/wp-json/wp/v2/site/{posts[0].sites[0]}
/wp-json/wp/v2/site/{posts[1].sites[0]}
/wp-json/wp/v2/site/{posts[2].sites[0]}
/wp-json/wp/v2/site/{posts[3].sites[0]}
/wp-json/wp/v2/media/{posts[2].featured_media}
/wp-json/wp/v2/media/{posts[3].featured_media}
<?php
$posts = new WP_Query( 
    array(
        'post_type' => 'post',
        'posts_per_page' => 4,
        'post_status' => 'publish'
    ) 
);
if ( $posts->have_posts() ) :
    while( $posts->have_posts() ) :
        $posts->the_post();

        $author = get_the_author();
        $author_name = $author->display_name;
        $avatar = get_avatar_data( $author->ID );
        $avatar_url = $avatar->url;

        $sites = wp_get_post_terms( 
            $post->ID, 'sites' 
        );
        $site_name = $sites[0]->name;
        $site_link = get_term_meta( 
            $sites[0]->term_id, 
            'link', 
            true 
        );

        
        $follow_link = your_follow_link_func();

        $title = get_the_title();

        $img = get_the_post_thumbnail_url( 
            $post->ID, 
            array( 300 ) 
        );

        $excerpt = get_the_excerpt();

    endwile;
endif;

Single GraphQL Request

# WordPress, PHP with WPGraphQL Active

$query = '
{
    posts {
        edges {
            node {
                id
                title
                link
            }
        }
    }
}
';

$data = do_graphql_request( $query );
  • Constantly over fetching and under fetching
  • Lots and lots of HTTP requests
  • Tight client-server coupling
  • Implicit Requests Make Maintenance Difficult
  • Maintaining Documentation
  • Versioning is difficult
  • Fetch exactly what you need, nothing more, nothing less
  • Multiple resources in a single HTTP request
  • Decoupled client-server relationship
  • Explicit requests ease maintenance
  • Self Documenting Schema / Type System
  • Easy, pain free versioning

How to use GraphQL with WordPress

WPGraphQL is a free, open-source WordPress plugin that provides an extendable GraphQL schema and API for any WordPress site.

We have stickers!

Adding the Plugin to WordPress

Install & Activate the Plugin

DEMOS

Contributors

WPGraphQL in the Wild

WPGraphQL