Native Search vs. Jetpack Instant Search in Headless WordPress With Gatsby

Have you already tried using WordPress headlessly with Gatsby? If you haven’t, you might check this article around the new Gatsby source plugin for WordPress; gatsby-source-wordpress is the official source plugin introduced in March 2021 as a part of the Gatsby 3 release. It significantly improves the integration with WordPress. Also, the WordPress plugin WPGraphQL providing the GraphQL API is now available via the official WordPress repository.

With stable and maintained tools, developing Gatsby websites powered by WordPress becomes easier and more interesting. I got myself involved in this field, I co-founded (with Alexandra Spalato), and recently launched Gatsby WP Themes — a niche marketplace for developers building WordPress-powered sites with Gatsby. In this article, I would love to share my insights and, in particular, discuss the search functionality.

Search does not come out of the box, but there are many options to consider. I will focus on two distinct possibilities — taking advantage of WordPress native search (WordPress search query) vs. using Jetpack Instant Search.

Getting started

Let’s start by setting up a WordPress-powered Gatsby website. For the sake of simplicity, I will follow the getting started instructions and install the gatsby-starter-wordpress-blog starter.

gatsby new gatsby-wordpress-w-search https://github.com/gatsbyjs/gatsby-starter-wordpress-blog

This simple, bare-bone starter creates routes exclusively for individual posts and blog pages. But we can keep it that simple here. Let’s imagine that we don’t want to include pages within the search results.

For the moment, I will leave the WordPress source website as it is and pull the content from the starter author’s WordPress demo. If you use your own source, just remember that there are two plugins required on the WordPress end (both available via the plugin repository):

  • WPGraphQL – a plugin that runs a GraphQL server on the WordPress instance
  • WPGatsby – a plugin that modifies the WPGraphQL schema in Gatsby-specific ways (it also adds some mechanism to optimize the build process)

Setting up Apollo Client

With Gatsby, we usually either use the data from queries run on page creation (page queries) or call the useStaticQuery hook. The latter is available in components and does not allow dynamic query parameters; its role is to retrieve GraphQL data at build time. None of those two query solutions works for a user’s-initiated search. Instead, we will ask WordPress to run a search query and send us back the results. Can we send a graphQL search query? Yes! WPGraphQL provides search; you can search posts in WPGraphQL like so:

posts(where: {search: "gallery"}) {
  nodes {
    id
    title
    content
  }
}

In order to communicate directly with our WPGraphQL API, we will install Apollo Client; it takes care of requesting and caching the data as well as updating our UI components.

yarn add @apollo/client cross-fetch

To access Apollo Client anywhere in our component tree, we need to wrap our app with ApolloProvider. Gatsby does not expose the App component that wraps around the whole application. Instead, it provides the wrapRootElement API. It’s a part of the Gatsby Browser API and needs to be implemented in the gatsby-browser.js file located at the project’s root.

// gatsby-browser.js
import React from "react"
import fetch from "cross-fetch"
import { ApolloClient, HttpLink, InMemoryCache, ApolloProvider } from "@apollo/client"
const cache = new InMemoryCache()
const link = new HttpLink({
  /* Set the endpoint for your GraphQL server, (same as in gatsby-config.js) */
  uri: "https://wpgatsbydemo.wpengine.com/graphql",
  /* Use fetch from cross-fetch to provide replacement for server environment */
  fetch
})
const client = new ApolloClient({
  link,
  cache,
})
export const wrapRootElement = ({ element }) => (
  <ApolloProvider client={client}>{element}</ApolloProvider>
)

SearchForm component

Now that we’ve set up ApolloClient, let’s build our Search component.

touch src/components/search.js src/components/search-form.js src/components/search-results.js src/css/search.css

The Search component wraps SearchForm and SearchResults

// src/components/search.js
import React, { useState } from "react"
import SearchForm from "./search-form"
import SearchResults from "./search-results"

const Search = () => {
  const [searchTerm, setSearchTerm] = useState("")
  return (
    <div className="search-container">
      <SearchForm setSearchTerm={setSearchTerm} />
      {searchTerm && <SearchResults searchTerm={searchTerm} />}
    </div>
  )
}
export default Search

<SearchForm /> is a simple form with controlled input and a submit handler that sets the searchTerm state value to the user submission.

// src/components/search-form.js
import React, { useState } from "react"
const SearchForm = ({ searchTerm, setSearchTerm }) => {
  const [value, setValue] = useState(searchTerm)
  const handleSubmit = e => {
    e.preventDefault()
    setSearchTerm(value)
  }
  return (
    <form role="search" onSubmit={handleSubmit}>
      <label htmlFor="search">Search blog posts:</label>
      <input
        id="search"
        type="search"
        value={value}
        onChange={e => setValue(e.target.value)}
      />
      <button type="submit">Submit</button>
    </form>
  )
}
export default SearchForm

The SearchResults component receives the searchTerm via props, and that’s where we use Apollo Client.

For each searchTerm, we would like to display the matching posts as a list containing the post’s title, excerpt, and a link to this individual post. Our query will be like so:

const GET_RESULTS = gql`
  query($searchTerm: String) {
    posts(where: { search: $searchTerm }) {
      edges {
        node {
          id
          uri
          title
          excerpt
        }
      }
    }
  }
`

We will use the useQuery hook from @apollo-client to run the GET_RESULTS query with a search variable.

// src/components/search-results.js
import React from "react"
import { Link } from "gatsby"
import { useQuery, gql } from "@apollo/client"
const GET_RESULTS = gql`
  query($searchTerm: String) {
    posts(where: { search: $searchTerm }) {
      edges {
        node {
          id
          uri
          title
          excerpt
        }
      }
    }
  }
`
const SearchResults = ({ searchTerm }) => {
  const { data, loading, error } = useQuery(GET_RESULTS, {
    variables: { searchTerm }
  })
  if (loading) return <p>Searching posts for {searchTerm}...</p>
  if (error) return <p>Error - {error.message}</p>
  return (
    <section className="search-results">
      <h2>Found {data.posts.edges.length} results for {searchTerm}:</h2>
      <ul>
        {data.posts.edges.map(el => {
          return (
            <li key={el.node.id}>
              <Link to={el.node.uri}>{el.node.title}</Link>
            </li>
          )
        })}
      </ul>
    </section>
  )
}
export default SearchResults

The useQuery hook returns an object that contains loading, error, and data properties. We can render different UI elements according to the query’s state. As long as loading is truthy, we display <p>Searching posts...</p>. If loading and error are both falsy, the query has completed and we can loop over the data.posts.edges and display the results.

if (loading) return <p>Searching posts...</p>
if (error) return <p>Error - {error.message}</p>
// else
return ( //... )

For the moment, I am adding the <Search /> to the layout component. (I’ll move it somewhere else a little bit later.) Then, with some styling and a visible state variable, I made it feel more like a widget, opening on click and fixed-positioned in the top right corner.

Paginated queries

Without the number of entries specified, the WPGraphQL posts query returns ten first posts; we need to take care of the pagination. WPGraphQL implements the pagination following the Relay Specification for GraphQL Schema Design. I will not go into the details; let’s just note that it is a standardized pattern. Within the Relay specification, in addition to posts.edges (which is a list of { cursor, node } objects), we have access to the posts.pageInfo object that provides:

  • endCursor – cursor of the last item in posts.edges,
  • startCursor – cursor of the first item in posts.edges,
  • hasPreviousPage – boolean for “are there more results available (backward),” and
  • hasNextPage – boolean for “are there more results available (forward).”

We can modify the slice of the data we want to access with the additional query variables:

  • first – the number of returned entries
  • after – the cursor we should start after

How do we deal with pagination queries with Apollo Client? The recommended approach is to use the fetchMore function, that is (together with loading, error and data) a part of the object returned by the useQuery hook.

// src/components/search-results.js
import React from "react"
import { Link } from "gatsby"
import { useQuery, gql } from "@apollo/client"
const GET_RESULTS = gql`
  query($searchTerm: String, $after: String) {
    posts(first: 10, after: $after, where: { search: $searchTerm }) {
      edges {
        node {
          id
          uri
          title
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
`
const SearchResults = ({ searchTerm }) => {
  const { data, loading, error, fetchMore } = useQuery(GET_RESULTS, {
    variables: { searchTerm, after: "" },
  })
  if (loading && !data) return <p>Searching posts for {searchTerm}...</p>
  if (error) return <p>Error - {error.message}</p>
  const loadMore = () => {
    fetchMore({
      variables: {
        after: data.posts.pageInfo.endCursor,
      },
      // with notifyOnNetworkStatusChange our component re-renders while a refetch is in flight so that we can mark loading state when waiting for more results (see lines 42, 43)
      notifyOnNetworkStatusChange: true,
    })
  }

  return (
    <section className="search-results">
      {/* as before */}
      {data.posts.pageInfo.hasNextPage && (
        <button type="button" onClick={loadMore} disabled={loading}>
          {loading ? "Loading..." : "More results"}
        </button>
      )}
    </section>
  )
}
export default SearchResults

The first argument has its default value but is necessary here to indicate that we are sending a paginated request. Without first, pageInfo.hasNextPage will always be false, no matter the search keyword.

Calling fetchMore fetches the next slice of results but we still need to tell Apollo how it should merge the “fetch more” results with the existing cached data. We specify all the pagination logic in a central location as an option passed to the InMemoryCache constructor (in the gatsby-browser.js file). And guess what? With the Relay specification, we’ve got it covered — Apollo Client provides the relayStylePagination function that does all the magic for us.

// gatsby-browser.js
import { ApolloClient, HttpLink, InMemoryCache, ApolloProvider } from "@apollo/client"
import { relayStylePagination } from "@apollo/client/utilities"
const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        posts: relayStylePagination(["where"]),
      },
    },
  },
})
/* as before */

Just one important detail: we don’t paginate all posts, but instead the posts that correspond to a specific where condition. Adding ["where"] as an argument to relayStylePagination creates a distinct storage key for different search terms.

Making search persistent

Right now my Search component lives in the Layout component. It’s displayed on every page but gets unmounted every time the route changes. What if we could keep the search results while navigating? We can take advantage of the Gatsby wrapPageElement browser API to set persistent UI elements around pages.

Let’s move <Search /> from the layout component to the wrapPageElement:

// gatsby-browser.js
import Search from "./src/components/search"
/* as before */
export const wrapPageElement = ({ element }) => {
  return <><Search />{element}</>
}

The APIs wrapPageElement and wrapRootElement exist in both the browser and Server-Side Rendering (SSR) APIs. Gatsby recommends that we implement wrapPageElement and wrapRootElement in both gatsby-browser.js and gatsby-ssr.js. Let’s create the gatsby-ssr.js (in the root of the project) and re-export our elements:

// gatsby-ssr.js
export { wrapRootElement, wrapPageElement } from "./gatsby-browser"

I deployed a demo where you can see it in action. You can also find the code in this repo.

The wrapPageElement approach may not be ideal in all cases. Our search widget is “detached” from the layout component. It works well with the position “fixed” like in our working example or within an off-canvas sidebar like in this Gatsby WordPress theme.

But what if you want to have “persistent” search results displayed within a “classic” sidebar? In that case, you could move the searchTerm state from the Search component to a search context provider placed within the wrapRootElement:

// gatsby-browser.js
import SearchContextProvider from "./src/search-context"
/* as before */
export const wrapRootElement = ({ element }) => (
  <ApolloProvider client={client}>
    <SearchContextProvider>
      {element}
    </SearchContextProvider>
  </ApolloProvider>
)

…with the SearchContextProvider defined as below:

// src/search-context.js
import React, {createContext, useState} from "react"
export const SearchContext = createContext()
export const SearchContextProvider = ({ children }) => {
  const [searchTerm, setSearchTerm] = useState("")
  return (
    <SearchContext.Provider value={{ searchTerm, setSearchTerm }}>
      {children}
    </SearchContext.Provider>
  )
}

You can see it in action in another Gatsby WordPress theme:

Note how, since Apollo Client caches the search results, we immediately get them on the route change.

Results from posts and pages

If you checked the theme examples above, you might have noticed how I deal with querying more than just posts. My approach is to replicate the same logic for pages and display results for each post type separately.

Alternatively, you could use the Content Node interface to query nodes of different post types in a single connection:

const GET_RESULTS = gql`
  query($searchTerm: String, $after: String) {
    contentNodes(first: 10, after: $after, where: { search: $searchTerm }) {
      edges {
        node {
          id
          uri
          ... on Page {
            title
          }
          ... on Post {
            title
            excerpt
          }
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
`

Our solution seems to work but let’s remember that the underlying mechanism that actually does the search for us is the native WordPress search query. And the WordPress default search function isn’t great. Its problems are limited search fields (in particular, taxonomies are not taken into account), no fuzzy matching, no control over the order of results. Big websites can also suffer from performance issues — there is no prebuilt search index, and the search query is performed directly on the website SQL database.

There are a few WordPress plugins that enhance the default search. Plugins like WP Extended Search add the ability to include selected meta keys and taxonomies in search queries.

The Relevanssi plugin replaces the standard WordPress search with its search engine using the full-text indexing capabilities of the database. Relevanssi deactivates the default search query which breaks the WPGraphQL where: {search : …}. There is some work already done on enabling Relevanssi search through WPGraphQL; the code might not be compatible with the latest WPGraphQL version, but it seems to be a good start for those who opt for Relevanssi search.

In the second part of this article, we’ll take one more possible path and have a closer look at the premium service from Jetpack — an advanced search powered by Elasticsearch. By the way, Jetpack Instant search is the solution adopted by CSS-Tricks.

Using Jetpack Instant Search with Gatsby

Jetpack Search is a per-site premium solution by Jetpack. Once installed and activated, it will take care of building an Elasticsearch index. The search queries no longer hit the SQL database. Instead, the search query requests are sent to the cloud Elasticsearch server, more precisely to:

https://public-api.wordpress.com/rest/v1.3/sites/{your-blog-id}/search

There are a lot of search parameters to specify within the URL above. In our case, we will add the following:

  • filter[bool][must][0][term][post_type]=post: We only need results that are posts here, simply because our Gatsby website is limited to post. In real-life use, you might need spend some time configuring the boolean queries.
  • size=10 sets the number of returned results (maximum 20).
  • with highlight_fields[0]=title, we get the title string (or a part of it) with the searchTerm within the <mark> tags.
  • highlight_fields[0]=content is the same as below but for the post’s content.

There are three more search parameters depending on the user’s action:

  • query: The search term from the search input, e.g. gallery
  • sort: how the results should be orderer, the default is by score "score_default" (relevance) but there is also "date_asc" (newest) and "date_desc" (oldest)
  • page_handle: something like the “after” cursor for paginated results. We only request 10 results at once, and we will have a “load more” button.

Now, let’s see how a successful response is structured:

{
  total: 9,
  corrected_query: false,
  page_handle: false, // or a string it the total value > 10
  results: [
    {
      _score: 196.51814,
      fields: {
        date: '2018-11-03 03:55:09',
        'title.default': 'Block: Gallery',
        'excerpt.default': '',
        post_id: 1918,
        // we can configure what fields we want to add here with the query search parameters
      },
      result_type: 'post',
      railcar: {/* we will not use this data */},
      highlight: {
        title: ['Block: <mark>Gallery</mark>'],
        content: [
          'automatically stretch to the width of your <mark>gallery</mark>. ... A four column <mark>gallery</mark> with a wide width:',
          '<mark>Gallery</mark> blocks have two settings: the number of columns, and whether or not images should be cropped',
        ],
      },
    },
    /* more results */
  ],
  suggestions: [], // we will not use suggestions here
  aggregations: [], // nor the aggregations
}

The results field provides an array containing the database post IDs. To display the search results within a Gatsby site, we need to extract the corresponding post nodes (in particular their uri ) from the Gatsby data layer. My approach is to implement an instant search with asynchronous calls to the rest API and intersect the results with those of the static GraphQL query that returns all post nodes.

Let’s start by building an instant search widget that communicates with the search API. Since this is not specific to Gatsby, let’s see it in action in this Pen:

Here, useDebouncedInstantSearch is a custom hook responsible for fetching the results from the Jetpack Search API. My solution uses the awesome-debounce-promise library that allows us to take some extra care of the fetching mechanism. An instant search responds to the input directly without waiting for an explicit “Go!” from the user. If I’m typing fast, the request may change several times before even the first response arrives. Thus, there might be some unnecessary network bandwidth waste. The awesome-debounce-promise waits a given time interval (say 300ms) before making a call to an API; if there is a new call within this interval, the previous one will never be executed. It also resolves only the last promise returned from the call — this prevents the concurrency issues.

Now, with the search results available, let’s move back to Gatsby and build another custom hook:

import {useStaticQuery, graphql} from "gatsby"

export const useJetpackSearch = (params) => {
  const {
    allWpPost: { nodes },
  } = useStaticQuery(graphql`
    query AllPostsQuery {
      allWpPost {
        nodes {
          id
          databaseId
          uri
          title
          excerpt
        }
      }
    }
  `)
  const { error, loading, data } = useDebouncedInstantSearch(params)
  return {
    error,
    loading,
    data: {
      ...data,
      // map the results
      results: data.results.map(el => {
        // for each result find a node that has the same databaseId as the result field post_id
        const node = nodes.find(item => item.databaseId === el.fields.post_id)
        return {
          // spread the node
          ...node,
          // keep the highlight info
          highlight: el.highlight
        }
      }),
    }
  }
}

I will call the useJetpackSearch within <SearchResults />. The Gatsby-version of <SearchResults /> is almost identical as that in the Pen above. The differences are highlighted in the code block below. The hook useDebouncedInstantSearch is replaced by useJetpackSearch (that calls the former internally). There is a Gatsby Link that replaces h2 as well as el.fields["title.default"] and el.fields["excerpt.default"] are replaced by el.title and el.excerpt.

const SearchResults = ({ params, setParams }) => {
  const { loading, error, data } = useJetpackSearch(params)
  const { searchTerm } = params
  if (error) {
    return <p>Error - {error}</p>
  }
  return (
    <section className="search-results">
      {loading ? (
        <p className="info">Searching posts .....</p>
      ) : (
        <>
          {data.total !== undefined && (
            <p>
              Found {data.total} results for{" "}
              {data.corrected_query ? (
                <>
                  <del>{searchTerm}</del> <span>{data.corrected_query}</span>
                </>
              ) : (
                <span>{searchTerm}</span>
              )}
            </p>
          )}
        </>
      )}
      {data.results?.length > 0 && (
        <ul>
          {data.results.map((el) => {
            return (
              <li key={el.id}>
                <Link to={el.uri}>
                  {el.highlight.title[0]
                    ? el.highlight.title.map((item, index) => (
                        <React.Fragment key={index}>
                          {parse(item)}
                        </React.Fragment>
                      ))
                    : parse(el.title)}
                </Link>
                <div className="post-excerpt">
                  {el.highlight.content[0]
                    ? el.highlight.content.map((item, index) => (
                        <div key={index}>{parse(item)}</div>
                      ))
                    : parse(el.excerpt)}
                </div>
              </li>
            );
          })}
        </ul>
      )}
      {data.page_handle && (
        <button
          type="button"
          disabled={loading}
          onClick={() => setParams({ pageHandle: data.page_handle })}
        >
          {loading ? "loading..." : "load more"}
        </button>
      )}
    </section>
  )
}

You can find the complete code in this repo and see it in action in this demo. Note that I no longer source WordPress data from the generic WordPress demo used by Gatsby starter. I need to have a website with Jetpack Search activated.

Wrapping up

We’ve just seen two ways of dealing with search in headless WordPress. Besides a few Gatsby-specific technical details (like using Gatsby Browser API), you can implement both discussed approaches within other frameworks. We’ve seen how to make use of the native WordPress search. I guess that it is an acceptable solution in many cases.

But if you need something better, there are better options available. One of them is Jetpack Search. Jetpack Instant Search does a great job on CSS-Tricks and, as we’ve just seen, can work with headless WordPress as well. There are probably other ways of implementing it. You can also go further with the query configuration, the filter functionalities, and how you display the results.


The post Native Search vs. Jetpack Instant Search in Headless WordPress With Gatsby appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

API Security Weekly: Issue #144

This week, JustDial has had to re-fix an old API vulnerability that they already fixed in 2019. We also have a set of scripts for automated API key validation, and two videos from recent conferences on the OAuth roadmap and GraphQL security.

Vulnerability: JustDial

JustDial had a regression as they accidentally reintroduced the API vulnerability that they had fixed (and we reported) back in 2019. Ironically, it was found and resubmitted to the vendor by the same reporter as last time, Rajshekhar Rajaharia.

How to Set Up a GraphQL Endpoint on a Database

Introduction

I have been working around databases for about four decades (that does date me!). From the early days of System R and Ingres, through the commercial engines of DB2 and Oracle, the open sources of MySQL and Postgres, to the current generations of NoSQLs like MongoDB and Cassandra and scalable SQL like CockroachDB and Yugabyte, anyone who has predicted the demise of databases has proven to be wrong. SQL as the query language has persisted, evolved, and improved, but the basic select * from foo where x = 1 group by y  is the language known to hundreds of thousands of developers. Why is that? Because databases just work, and how can you say that about too many things?

As a frontend developer, you want to see data in logical business constructs. Say a customer has one or more addresses, then your React application would love to see data like this:

Building Modern 3factor Apps in 2021 With Event-Driven Programming

Before OOP languages, the programmer would control how the program is executed and that would be from the app’s main routine. In modern programming, that control is delegated to the external non-main loops, and the main routine becomes an event-loop that waits for events to occur and then executes it with the relevant event handler.

This new model of programming (it has been around since the 70s though) is called event-driven programming.

API Security Weekly: Issue #137

This week, we take a look at the recent API vulnerabilities in VMware vCenter and Apache Pulsar, how GraphQL implementations may be vulnerable to cross-site request forgery (CSRF) attacks, an upcoming webinar on API Security and Postman, a DZone webinar with this newsletter’s author next week, and a video on how the API security vendor landscape looks like.

Vulnerability: VMware vCenter

A recently patched vulnerability in VMware vCenter is now being actively exploited.

RESTful APIs Are Good, But GraphQL APIs Are Usually Better

According to the GraphQL Foundation, GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. Like many influential technologies, GraphQL was developed by Facebook in 2012. In their own words they “needed a data-fetching API powerful enough to describe all of Facebook, yet simple enough to be easy to learn” by their developers.

For a few years, GraphQL was used internally for their mobile applications. The first GraphQL repos were open-sourced in 2015. One of the Github repos contained the GraphQL specification and another contained a GraphQL JavaScript reference implementation. 

API Security Weekly: Issue #131

This week, we check out the recent API vulnerability in John Deere farming machinery, the best practices in using Springfox annotations for API security, a new JWT penetration testing lab, and AutoGraphQL — a tool for GraphQL authorization testing.

Vulnerability: John Deere

John Deere is one of the leading manufacturers of expensive farming equipment, such as tractors and combine harvesters. Many of these are automated to the highest degree and cost millions of dollars.

Why Your Microservices Need GraphQL

While microservices offer tremendous benefits and help you stay agile, it’s important to get them right.

In this post, we are going to see how the nature of microservices makes choosing the right API layer even more important and how  GraphQL perfectly fits in it.

Using New Gatsby Source WordPress Plugin

In my previous article, I discussed how I learned to create a decoupled WordPress powered Gatsby site using the Gatsby Source WPGraphQL plugin. The project was done following the ongoing developmental version of WPGraphQL and an excellent tutorial by Henrik Wirth. Although WPGraphQL was used in some production sites at that time, there were lot of iterations that introduced breaking changes. Since the release of WPGraphQL v1.0 last November, the plugin is stable and available via the WordPress plugin directory.

The WPGraphQL plugin can be used to create a site that uses WordPress for content management, but with a front-end that’s driven by Gatsby. We call this a “decoupled” or “headless” CMS because the site’s back-end and front-end are separate entities that still talk to one another via APIs where components on the front end consume data from the CMS.

The WPGraphQL plugin site has solid step-by-step documentation for getting started, and the release announcement post lists nine examples of production-level sites using the plugin.

Selected screenshots of production level decoupled WordPress sites with WPGraphQL.
The Denver Post, The Twin Cities Pioneer Press, The San Jose Mercury News, and Credit Karma have a decoupled WordPress site with WPGraphQL.

In the true sense of a “decoupled” or “headless” site, WPGraphQL can be used to port WordPress data to other frameworks, like Next.js, Vue.js, among others. For the Gatsby framework, the Gatsby Source WordPress plugin is recommended, and it utilizes WPGraphQL to source data from WordPress.

Let’s set everything up together and tour the plugin.

Prerequisites

In my previous article, we covered the prerequisites needed for setting up WordPress and Gatsby sites, and porting back-end WordPress data to a Gatsby-powered front-end site with site deployment. I’m skipping a lot of those details here because the fundamental concepts are the same for this article, except that WordPress data is fetched by the Gatsby Source WordPress plugin this time.

If you are new to Gatsby and just now jumping into Gatsby’s generated static site generator bandwagon, I’d suggest reading “An Honest Review of Gatsby” by React expert David Cramer and “Gatsby vs Next.js” by Jared Palmer. What we’re going to cover isn‘t for everyone, and these articles may be helpful to evaluate for yourself whether it’s the right technology for you and your project.

WPGraphQL, or GraphQL is the primary query language API used in Gatsby’s framework. There are frequent updates in GraphQL and that often requires expert knowledge and keeping an eye out for breaking changes. After all, GraphQL is designed by React experts for other React experts. That said, there’s some troubleshooting instructions and a WPGraphQL Slack where both the WPGraphQL and Gatsby Source WordPress plugin authors actively participate and help answer questions.

This article is not a step-by-step guide on how to use Gatsby Source WordPress Plugin. Again, that’s already available in Gatsby’s documentation. Conversely, if you happen to be an expert in React, JavaScript, Node.js or GraphQL, then what we cover here is probably stuff you already know. This article is an opinion piece based on my personal experience, which I hope is useful for the average WordPress user with basic working knowledge on the subject.

And, before we get started, it’s worth mentioning that the Gatsby Source WordPress plugin was completely rewritten in version 4 and uses WPGraphQL as its data source. The previous release, version 3, was built with REST API as its data source. Since the stable version of the plugin was recently released, the number of starter themes and demos that support it are limited.

First, we need WordPress

For this project, I set up a fresh WordPress site with Local by Flywheel that uses the default Twenty Twenty theme. I imported theme unit test data for pages and posts, as described in the WordPress Codex. While this was the baseline I was working with, this could have just as easily been an existing WordPress site that’s either on a remote server or a local install.

Now that we have an established baseline, we can log into the WordPress admin and install the WPGraphQL and WPGatsby plugins we need and activate them.

As we covered in the previous article, what this does is expose GraphQL and WPGraphiQL API in the WordPress admin, allowing the GraphiQL API to create a “playground” for testing GraphQL queries based on WordPress data.

Screenshot of the GraphiQL UI in the WordPress admin, showing a three-panel UI.
The GraphiQL screen provides three panels: one to navigate between different objects (left), one to query data (center), and one to visualize the returned data (right).

Now we need a Gatsby front-end

Gatsby is well known for good documentation and solid starter templates. To create a new WordPress-powered site, Gatsby tutorials suggest that either using a starter or starting from scratch is just fine for what we’re doing.

Gatsby also offers a library of example websites for basic use cases that are built around a specific technology. There currently happens to be one that uses WordPress and one that uses WordPress with the Advanced Custom Fields plugin. Note that the example sites in the library still use gatsby-source-wordpress plugin 3 and have not yet updated to the version 4, as of this writing.

According to Gatsby tutorials, there are three options for creating a WordPress-powered Gatsby site. Let’s look at each one.

Option 1: Using the Gatsby starter

The docs have a step-by-step guide on how to set up a WordPress-Gatsby site, but here’s the gist.

Run the following in the command line to fetch the starter from GitHub repository and clone it into a my-wpstarter project folder:

#! clone starter repo
gatsby new my-wpstarter https://github.com/gatsbyjs/gatsby-starter-wordpress-blog 

Then, install the npm packages

#! npm
npm install

#! or yarn
yarn install 

Now that the starter is cloned, let’s open the gatsby-config.js file in our code editor and update its URL option to fetch data from our WordPress endpoint (see above).

// gatsby-config.js
{
  resolve: gatsby-source-wordpress,
    options: {
     // WordPress is the GraphQL url.
     url: process.env.WPGRAPHQL_URL || https://wpgatsbydemo.wpengine.com/graphql,
  },
},

Now, we’ll replace the starter’s data source endpoint URL with our own WordPress site URL:

// gatsby-config.js file
{
  resolve: `gatsby-source-wordpress`,
  options: {
    url: `http://gatsbywpv4.local/graphql`,
  },
},

Let’s make sure we are in the my-wpstarter project directory. From the project folder, we’ll run the gatsby develop command to build our new Gatsby site from our WordPress data source endpoint. In the terminal we should be able see the gatsby-source-wordpress plugin fetching data, including errors and successful site processes along the way.

If we see a success Building development bundle message at the end, that means the Gatsby site build process is complete and the site can be viewed at http://localhost:8000.

The homepage of our starting site, displaying posts pulled from WordPress data in a single column.

This is a bare-bone starter blog with basic files and a few components. It’s file structure is very similar to the gatsby-starter-blog, except this one has a templates folder that includes blog-post.js and blog-post-achive.js template files.

When we view the GraphiQL API explorer at http://localhost:8000/___graphql we can see all of the data from WordPress exposed by WPGraphQL, as well as query and retrieve specific data right from the UI.

The GraphiQL UI showing three panels, one for the Explorer, one for the GraphiQL query, and one that displays the returned data from the query.
This example shows a query for menu items in WordPress (middle panel) and the returned data of that query (right panel).

You got it! Gatsby assumes the rest is up to us to build, using Gatsby components that pull in WordPress data for the presentation.

Option 2: Building from scratch

Gatsby’s documentation offers a detailed step-by-step guide on how to create a new WordPress-Gatsby site from scratch using Gatsby’s default starter theme.

We’ll spin up a new project from the command line:

#! create a new Gatsby site
gatsby new wpgatsby-from-scratch-demo

This gets us a wpgatsby-from-scratch-demo folder that includes the starter theme. From here, we’ll cd into that folder and start developing:

cd wpgatsby-from-scratch-demo
gatsby develop

Now we can open up http://localhost:8000 in the browser and get the welcome page.

Now we are good to go to get start grabbing data from our WordPress site. Let’s install the Gatsby Source Plugin:

#! install with rpm
npm install gatsby-source-wordpress

#! install with yarn
yarn add Gatsby-source-wordpress

If we check our browser now, you’ll noticed that nothing happens — we still get the same Gatsby welcome. To fetch our WordPress site data, we need to add the plugin to the gatsby-config.js file. Open the file and insert the following:

// gatsby-config.js
module.exports = {
  siteMetadata: {
    // ...
  },
  plugins: [
  // Add Gatsby-source-wordpress plugin
  {
      resolve: `gatsby-source-wordpress`,
      options: {
        /*
         * The full URL of the WordPress site's GraphQL API.
         * Example : 'https://www.example-site.com/graphql'
         */
        url: `http://gatsbywpv4.local/graphql`,
       },
     },
    // The following plugins are not required for gatsby-source-wordpress ....
  ],
}

Just like last time, we need to change the WordPress data endpoint source to the URL of our WordPress site. Let’s run gatsby develop in our terminal to start things up.

Two terminal windows, side-by-side. They are dark with light text.
Now we see that the createPages function is running successfully to build a development bundle (left), and that WordPress data for posts, pages, taxonomies, users, menus, and everything else are fetched (right).

However, when we open http://localhost:8000 in our browser, nothing seems to happen. We still see the same welcome screen. But if we examine GraphiQL in our browser (at http://localhost:8000/___graphql) then we see all WordPress data exposed to our Gatsby site that we can query and display as we want.

The three-panel GraphiQL UI.
GraphiQL shows that WordPress data is indeed exposed and we are able to create and execute queries.

Let’s test the following query I pulled straight from Gatsby’s tutorial, in the GraphiQL explorer:

query {
  allWpPost {
    nodes {
      id
      title
      excerpt
      slug
      date(formatString: "MMMM DD, YYYY")
    }
  }
}

When we run the above query, we will see the allWpPost.nodes property value, with sub properties for id, title, excerpt, and others.

Now, let’s open our src/components/pages/index.js component file and replace the code with this:

// src/components/pages/index.js
import  React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"
import SEO from "../components/seo"

export default function Home({ data }) {
  return (
    <Layout>
      <SEO title="home" />
      <h1>My WordPress Blog</h1>
      <h4>Posts</h4>
      {data.allWpPost.nodes.map(node => (
        <div>
          <p>{node.title}</p>
          <div dangerouslySetInnerHTML={{ __html: node.excerpt }} />
        </div>
      ))}
    </Layout>
  )
}

export const pageQuery = graphql`
  query {
    allWpPost(sort: { fields: [date] }) {
      nodes {
        title
        excerpt
        slug
      }
    }
  }
`

Save it, restart the server with gatsby develop, and refresh the page. If the build was successful, then our site’s homepage should display a list of sorted blog posts from WordPress!

Following the tutorial, let’s create pages for each blog post and link the post title from the list to the post page. The process of creating pages using Markdown data is described in detail in Part 7 of the Gatsby’s foundational tutorial, which we will follow here as well.

As described in the tutorial, Gatsby uses createPages API, or what it calls as its “workhorse” API, to programmatically create pages from data (from Markdown or WordPress). Unlike Markdown data, we don’t need to create a slug here because each WordPress post has its own unique slug which can be fetched from the WordPress data endpoint.

Creating pages for each post

Gatsby uses the gatsby-node.js file, located at the root of our project, to programmatically create blog post. Let’s open the gatsby-node.js file in our text editor add the following code from the tutorial.

// gatsby-node.js 
const path = require(`path`)

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions
  return graphql(`
    {
      allWpPost(sort: { fields: [date] }) {
        nodes {
          title
          excerpt
          content
          slug
        }
      }
    }
  `).then(result => {
    console.log(JSON.stringify(result, null, 4))
    process.exit()
  })
}

As noted in the Gatsby Part 7 tutorial, the above code is the first part of creating our post pages from WordPress data source. Following the guide, let’s restart our server and develop our site with gatsby develop.

We should see console.log output in our terminal as pages being build). However, our homepage still looks the same. To create single posts, Gatsby requires templates to build pages, which we will create in next step.. That’s what we’ll do next.

Creating blog post templates

Let’s create a src/components/templates folder in the src/ directory and create a blog-post.js file by pasting the following code snippets from the tutorial:

// src/templates/blog-post.js
import React from "react"
import Layout from "../components/layout"
import { graphql } from "gatsby"

export default function BlogPost({ data }) {
  const post = data.allWpPost.nodes[0]
  console.log(post)
  return (
    <Layout>
      <div>
        <h1>{post.title}</h1>
        <div dangerouslySetInnerHTML={{ __html: post.content }} />
      </div>
    </Layout>
  )
}
export const query = graphql`
  query($slug: String!) {
    allWpPost(filter: { slug: { eq: $slug } }) {
      nodes {
        title
        content
      }
    }
  }
`

As explained in the tutorial, the above code snippets create a single post with React JSX and wraps post.title and post.content (lines 12-13) around the src/components/layout.js components. At the bottom section of the file, a GraphQL query is added and calls a specific post based on the post slug variable $slug. This variable is passed to the blog-post.js template when the page is created in gatsby-node.js.

Next we should also update lines 12-13 of our gatsby-node.js file with the following code from the tutorial.

// gatsby-node.js
const path = require(`path`)

 exports.createPages = ({ graphql, actions }) => {
   const { createPage } = actions
   return graphql(`
     {
       allWpPost(sort: { fields: [date], order:DEC }) {
         nodes {
           title
           excerpt
           content
           slug
         }
       }
     }
   `).then(result => {
    result.data.allWpPost.nodes.forEach(node => {
        createPage({
          path: node.slug,
          component: path.resolve(`./src/templates/blog-post.js`),
          context: {
            // This is the $slug variable passed to blog-post.js
            slug: node.slug,
          },
        })
      })
   })
 }

Let‘s stop and restart our local server with gatsby develop and view the site. We won’t see our homepage with a list of blog post links. However, if we check with http://localhost:8000/abcdf we should see the following 404 page with a list of individual pages and posts links.

If we check http://localhost:8000/hello-gatsby-world, we should our “Hello Gatsby WordPress World” post in all its glory.

The next step is to link the post titles from the homepage to the actual posts.

Linking to posts from the homepage

Linking the work from the homepage to post pages is done by wrapping post titles in the index.js file with Gatsby‘s Link component. Let’s open the index.js file that we created earlier and add the Link component:

// src/components/pages/index.js
import React from "react"
import { Link, graphql } from "gatsby"
import Layout from "../components/layout"
import SEO from "../components/seo"

export default function Home({ data }) {
  return (
    <Layout>
      <SEO title="home" />
     {/* <h1>My WordPress Blog</h1>
      <h4>Posts</h4> */}
      {data.allWpPost.nodes.map(node => (
        <div key={node.slug}>
          <Link to={node.slug}>
            <h2>{node.title}</h2>
          </Link>
          <div dangerouslySetInnerHTML={{ __html: node.excerpt }} />
        </div>
      ))}
    </Layout>
  )
}

export const pageQuery = graphql`
  query {
    allWpPost(sort: { fields: [date], order: DEC  }) {
      nodes {
        title
        excerpt
        slug
      }
    }
  }
`

We imported the Link component from Gatsby and then wrapped the post title with the Link component and reference the slug of the post. Let’s clean up the code by commenting out the page title, changing the title element to <h2>, and adding sorted posts order to DEC in our graphql query as well as the gatsby-node.js file.

As we did earlier, let’s stop and restart the development server with gatsby develop, and view our homepage at http://localhost:8000. The post title should link to single post page.

This is as far as we’re going to take this second method. The rest of what we cover will describe how to fetch menu items and query other data types — like custom post types — and configure incremental build and previews etc.

You can apply the same procedure to calling and creating pages, custom post types, custom fields, taxonomies, and all the fun and flexible content WordPress is known for. This can be as simple or as complex as you would like it to be, so explore and have fun with it!

Gatsby tutorial doc 

Option 3: Using Gatsby’s WordPress Twenty Twenty Starter

Gatsby’s starter template for the default WordPress Twenty Twenty theme is created and maintained by Henrik Wirth, who also has an extremely detailed and thorough step-by-step guide that you might recall from my previous article. This starter, unlike the others, is actually updated to version 4 of the Gatsby Source Plugin and works out of the box after the initial WordPress setup described in the documentation. It maintains the same Twenty Twenty styling in the Gatsby front-end site, but has few limitations — including, comments, monthly archive pages, and tags — that are unsupported.

First let’s clone the starter in our twenty-twenty-starter folder.

#! clone gatsby-starter-wordpress-twenty-twenty 
gatsby new twenty-twenty-starter https://github.com/henrikwirth/gatsby-starter-wordpress-twenty-twenty

Let’s cd into that folder and then run gatsby develop to spin up the site. It won’t work properly the first time because we have not changed our WPGRAPHQL_URL value yet in the env.example file. We need to rename the file from .env.example to simply .env, as suggested in the documentation.

After that, restart the development server with gatsby develop. It should build the site successfully.

The menu may or may not appear depending on how the WordPress menu is named. The starter’s menu slug for querying menu items is primary in Menu.js (line 8). Because I had set my WordPress site up using main-menu instead, I had to update the Menu.js file accordingly.

Screenshot showing Menu.js file with changed menu slug to “main-menu” in line 8.

Because the starter was tested with older versions of our tools , I decided bump up the plugins  to the latest versions — WPGraphQL 1.2.6, WPGatsby 1.0.6, and Gatsby Source WordPress  4.0.1 — and it worked fine without any errors.

The Twenty Twenty starter follows the file structure of the Twenty Nineteen Gatsby theme, as well as Gatsby Starter WordPress Advanced. Henrik Wirth describes how WordPress data is ported to Gatsby in his step-by-step guide, as does Muhammad Muhsin in a tutorial. Otherwise, creating pages, page templates, porting menu items is exactly the same.

Screenshot showing Gatsby Starter WordPress Twenty Twenty’s file structure.

This starter uses the same CSS that the default WordPress Twenty Twenty theme does, and the same assets folder, including fonts, images, SVG files, and other files that are included in the default theme.

Screenshot showing the Gatsby Starter WordPress Twenty Twenty assets folder contents open in VS Code.

If you are happy with WordPress Twenty Twenty styling, then that’s it. Enjoy your new decoupled Gatsby site!

But let’s say we want to work with custom styles. The CSS files are imported from the assets folder via the gatsby-browser.js file.

Screenshot showing the Gatsby StarterWordPress Twenty Twenty style.css file opened next to the WordPress Twenty Twenty theme’s style.css file. The two contain the exact same code.

Let’s modify the styles for the site’s header, footer, posts and pages. Gatsby provides different options to style its components and, in this project, I followed the CSS module for styling and modified CSS markup of the Twenty Twenty starter components accordingly.

We can start by creating a style folder at src/components/styles and, inside it, a base folder. Here’s the general file structure we’re aiming for:

#! partial structure of /style folder
src
 |--/components
   |--/styles
     |--main.css          
     |--/base
       |--reset.css
       |--variables.css
     |--/scss
       |--header.module.css
       |--mainNav.module.css
       |--footer.module.css
       |--elements.module.css
       // and so on...

We want to style the site’s header and footer, so let’s open up the Header.js and Footer.js components in the starter and replace the code with the following:

// src/components/Header.js
import React from "react"
import { graphql, Link, useStaticQuery } from "gatsby"
import Menu from "./menu"
import style from "../styles/scss/header.module.css"
import logo from '../images/gatsby-icon.png'

const Header = ( ) => {
  const { wp } = useStaticQuery(graphql`
    {
      wp {
        generalSettings {
          title
          description
        }
      }
    }
  `)
  return (
    <header className={style.masthead}>
      <div className={style.masthead_info}>

      <Link to="/">
        <img src={logo} alt="logo" width="100" height="100" display="inline-block" marginBottom= "0"  className={style.site_logo} />
      </Link>
      <div className={style.site_header} >
        <div className={style.site_title}>
          <Link
            to="/"
            dangerouslySetInnerHTML={{ __html: wp.generalSettings.title }} />
        </div>
        <div className={style.site_description} dangerouslySetInnerHTML={{ __html: wp.generalSettings.description }} /></div>

      </div>
      <Menu />
    </header>
  )
}

export default Header

Similarly, the Footer.js component was modified as follows:

// src/components/Footer.js
import React from "react"

import style from "../styles/scss/footer.module.css"

export default () => (
  <footer className={style.colophon}>
    <p>© {new Date().getFullYear()} | This site is Powered by {'   ' } <a href="https://www.gatsbyjs.org">GatsbyJS</a> {'   and  '} <a href="https://www.wordpress.org">WordPress</a></p>
  </footer>
)

Now, let’s restart our development server. We should see the following, including a new customized header and footer. I used the same style from Learning Gatsby which is an online course by Morten Rand-Hendriksen (I am a fan!).

Screenshot showing modified header and footer styling.
Screenshot showing modified header and footer styling.

You can grab the all the code I used over at GitHub.

What all this means for WordPress enthusiasts

There are many posts that compare the advantages and disadvantages of a decoupled WordPress and Jamstack site like the Gatsby examples we’ve covered. In my research, I realized that none of them are as exhaustive as what Chris already wrote in ”WordPress and Jamstack” where he compares everything, from performance and features, to the developer experience and build processes, and beyond.

I found the following articles draw some helpful conclusions on a variety of topics, including:

What’s the cost?

The general assumption is that Jamstack hosting is cheap, and cheaper than traditional LAMP stack hosting. But there’s actually quite a bit to consider and your actual costs might vary.

  • “How to Run Your WordPress Site On Local, Gatsby and Netlify for FREE!” (Nate Fitch): Nate’s take is that a headless WordPress setup like this might be a good option if the project is a static blog or a site that doesn’t require any interactions. For example, It wouldn’t take too much work to get images hosted on Cloudinary, or another CDN, but it would for large, interactive sites.
  • “WordPress and Jamstack” (Chris Coyier): There’s a specific section in here where Chris breaks down the pricing for different types of hosting for Jamstack sites and why a blanket statement like “Jamstack is cheaper” doesn’t fly because the actual cost depends on the site and its usage.
  • “Choosing between Netlify, Vercel and Digital Ocean” by (Zell Liew): Zell discusses his experience choosing a hosting plan. His take: If you have a small project, go with Netlify; if you have a larger project, use Digital Ocean.

Why go static at all?

Considering all the things you get for “free” in WordPress — think comments, plugins, integrations, etc. — you might wonder if it’s even worth trading in a server-side setup for a client-side solution. In his “Static or Not?” post, Chris breaks down the reasons why you’d want to choose one over the other.

How do we get commenting functionality?

We get native commenting right out of the box with WordPress. Yet, support for comments on a static site is a bit of a juggernaut. In “JAMstack Comments” here on CSS-Tricks, the author explains how dynamic comments can be implemented in a static site, like Gatsby, using Netlify services. I briefly touched on this in my previous article.

What about SEO?

  • “Gatsby SEO For WpGraphQL and Yoast” (Gatsby Community Plugin): The widely used Yoast SEO plugin for WordPress can be integrated into a Gatsby front-end using this plugin.
  • “A primer on JavaScript SEO for WordPress” (Jono Alderson): This exhaustive guide includes a section on how to integrate Yoast SEO into a headless architecture and the implications of relying on JavaScript for SEO. The bottom line is that theme and plugin developers shouldn’t worry much about the changing landscape of JavaScript and SEO as long as they continue following best practices. At the same time, they should be aware of what’s changing and adapt accordingly.

How do things work together?

There are currently no Gatsby React templates that are geared toward non-developers but some agencies, like Gatsby WP Themes and the Themeforest marketplace, are beginning to fill the gap. For example, Gatsby WP Themes covers plugins for dynamic contents like MailChimp integration, using the Contact Form 7 plugin for forms, Yoast SEO, and more. Themeforest lists 30+ Gatsby templates, including the Gatsby – WordPress + eCommerce theme which gives you an idea of how far we can go with this sort of setup. Just remember: these are commercial sites, and much of what you’ll find has a cost attached to it.

My evolving personal take

If you recall, I ended my last article with a personal reflection on my journey to create a headless WordPress site that uses Gatsby as the front end. My initial take was less than a glowing review:

Based on my very limited experience, I think that currently available Gatsby WordPress themes are not ready for prime time use for users like me. Yeah, it is exciting to try something on the bleeding edge that’s clearly in the minds of many WordPress users and developers. At the same time, the constantly evolving work being done on the WordPress block editor, WPGraphQL and Gatsby Source WordPress plugins makes it difficult to predict where things are going and when it will settle into a state where it is safe to use in other contexts.

So, after all this my long journey to headless WordPress site, what is my take now? As an open-minded learner, my thoughts are still evolving. But I couldn’t agree more with what Chris says in his “Static or Not?” post:

It’s a perfectly acceptable and often smart choice to run a WordPress site. I think about it in terms of robustness and feature-readiness. Need e-commerce? It’s there. Need forms? There are great plugins. Need to augment how the CMS works? You have control over the types of content and what is in them. Need auth? That’s a core feature. Wish you had a great editing experience? Gutenberg is glorious.

I am a WordPress enthusiast and I love WordPress as a CMS. However, as a technological learning challenge, I have not given up yet to have a decoupled WordPress site as a personal project.

I must admit that learning to create a decoupled Gatsby site with WordPress has continued to be frustrating. I acknowledge that any modern technology stack is not “a cup of tea” for many WordPress users. Gatsby has steep learning curve as these stacks are targeted for experienced React and JavaScript developers.

Self-learning a new technology can be a frustrating experience. Learning Gatsby is especially frustrating if we (including yours truly) happen to lack experience with Node, React, JavaScript and, most importantly, GraphQL. My learning project sites would break because of some dependency and fixing it might take me several days of research. I sometimes wonder if the trouble is worth the outcome. Don’t get me wrong; my frustration is with my own lack of experience, not the frameworks themselves (because they are amazing).

Even experienced developers like David Cramer and Jared Palmer find using Gatsby and GraphQL frustrating and echo some of the same sentiments that we beginners face when using GraphQL. I couldn’t agree more with David who writes:

It’s a static website generator. It literally does not need GraphQL all over the place. While there are few instances in the real world where that is valuable, it shouldn’t require a GraphQL API to read objects that are already in memory.

GraphQL is an opinionated query language API and its specification changes frequently. Indeed, most of the discussion in the WPGraphQL Slack are related to queries.

While working on this project, I came cross the Frontity React Framework while reading an article on CSS-Tricks. It fetches all WordPress data with the REST API without writing a single query. That seems to be a better option, at least for my use case. Additionally, it appears to be a much simpler alternative. In my brief experience with it, I didn’t have to deal with any dependency or library issues at all. Frontity’s themes concept is so WordPress-y and provides excellent tutorials.

I am currently exploring whether the Frontity framework would be a better option for my decoupled project site and will share my experience in a future article.

Resources

Gatsby feels like it is targeted at experienced React and JavaScript developers, not for beginners like me! The gatsby-source-wordpress and gatsby-source-wpgraphql plugins do an excellent job of exposing WordPress data into Gatsby sites, but the rest is up to users to present the data on the front end using your framework of choice: React, Vue, Next, etc.

A lack of sound knowledge of React and JavaScript is the main hurdle for beginners. The Gatsby community fills a lot of these gaps, and there are a lot of resources available to keep learning and exploring.

Gatsby Conference 2021 talks

Two workshop talks from the recent 2021 Gatsby Conference were related to Gatsby WordPress sites. In one, Jason Bahl hosts a workshop that walks through how to create a Gatsby blog powered by WordPress data, including support the Yoast SEO plugin, and how to deploy the site to Gatsby Cloud.

There’s another workshop hosted by WP Engine’s Matt Landers where he demonstrates how to set things up using the Advanced Custom Fields plugin to create a team member page.

Both talks are good, especially if you learn better with hands-on experience. I also found this Matt Report podcast episode with Jason Bahl where Jason answers basic questions that are geared toward beginners.

Tutorial courses

Morten Rand-Hendriksen has an excellent course on LinkedIn Learning that uses the Gatsby Source WordPress plugin. If you are interested in more hands-on experience making a customized site that expands on the two Gatsby starters we covered, this course is great because in teaches how to create a complete working site, complete with a dropdown header navigation, footer menus, posts, pages, categories, tags, and page navigation.

Check that out, a homepage, post template, categories, tags, a header that includes navigation… there’s a lot going on here!

The exercise files for the course are available in the GitHub LinkedIn Learning repository.

Gatsby starters

At the time I’m writing this, there are ten Gatsby starters for WordPress. As we mentioned earlier, only Gatsby Starter WordPress Twenty Twenty is based on the latest version of the Gatsby Source WordPress plugin; the rest are version 3.


Thanks for reading. I am always interested to know how fellow WordPress users who lack heavy technical experience like me are using this plugin. If you have any feedback, please feel free to post them in the comments.


The post Using New Gatsby Source WordPress Plugin appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

GraphQL Revisited: Adoption in Blockchains

GraphQL Revisited

GraphQL Logo

Key Takeaways

  1. GraphQL is an open-source data query and modification language for APIs leveraged by several prominent tech shops such as Facebook (original creator), Github, Pinterest, Intuit, Coursera, Paypal, Yelp, and Shopify to name a few. It has gotten a lot of positive attention from the engineering community and supporters have termed it as 'Better REST,' asserting a range of benefits over traditional REST.
  2. With all the buzz around GraphQL, do developers need to make an active shift towards it and deprecate REST endpoints completely? It depends on many factors, which are discussed in this article. While GraphQL is an extremely powerful and flexible API strategy, it is not a silver bullet for all your data CRUD needs. You should evaluate your application needs and developer skills to make the right call (by using a skills assessment like this one: https://pluralsight.pxf.io/doLnDj).  
  3. GraphQL adoption (switching from REST) usually requires a major rewrite of the API and Client layer for your application. While there are material benefits to make the switch, depending on the size and complexity of your app, this can be a massive undertaking in terms of time and resources. There is also a learning curve with GraphQL and its best practices which should be taken into account before taking the leap.
  4. At the same time, GraphQL can remarkably simplify/optimize your data access and modification needs for both client and server-side engineers, regardless of the languages or environment you’re in. If you’re writing an app from scratch and/or not afraid to try something new, GraphQL presents itself as a great option with many compelling reasons to use it. It can vastly improve the performance of your app and developer experience.
  5. If you decide to leverage GraphQL, don't rush on your graph schema design. Measure twice and cut once. Mapping a good GraphQL schema is a non-trivial task. So take your time and try to get it right the first time around; it will save you from a lot of inconvenience down the line.
  6. GraphQL is seeing increased adoption in the Blockchain and Cryptocurrency space. Due to the distributed nature of blockchains, querying on-chain data is a hard problem and it is being simplified using GraphQL. With Graph APIs, viewing data across different crypto exchanges, markets, assets, and on-chain data can all be done in a single query.

Introduction

GraphQL is a data-query language created by Facebook that went open source in 2015. It provides a completely understandable description of the data in the API and enables clients to function in a declarative style to fetch exactly what they need — nothing less, nothing more. In this article, we will summarize how it works, why you should use it, what are some of its drawbacks and how it is increasingly being adopted in the Crypto space.

The Data Access Layer in Jmix: JPA on Steroids

JPA with Jmix

Introduction

The data model is one of the cornerstones of any enterprise application. When you start planning the model, you should not only take into account business data requirements but also answer some additional questions that may affect your application design. For example: do you need row-based security? Are you going to use soft delete? Do we need CRUD API and who will do this boring job?

JPA is a de-facto standard for creating a data model for Java applications. This API does not provide facilities to implement advanced security or soft delete, so developers have to implement their own solutions.

Build a Secure GraphQL API With MicroProfile

MicroProfile is an open-source community project with the goal to encourage the development of Java microservice solutions. It was created in 2016 in response to the changing needs of modern web development. In particular, it seeks to foster the development of smaller, less monolithic services (microservices) that can run on faster release cycles than the typical, old-school Enterprise Java application. Shortly after its creation, it joined the Eclipse foundation.

MicroProfile, in essence, is a set of specifications and standards agreed upon by a community of developers that allows for “write once, run anywhere” in the Java microservice ecosystem. There are currently around nine compliant runtimes for MicroProfile, including Apache TomEE, Quarkus, and Open Liberty. A program written for one can be seamlessly run on another. The community also serves as an incubator for new ideas within Enterprise Java and microservice architectures.

Creating a Unified API in GraphQL

What is Unified API?

A unified API is a single place to get all your data. It is one API that acts as an orchestration layer to fetch all downstream APIs. The benefit of this for consumers is that there is only one endpoint to integrate with, and get all the data they need from a single place.

To give an analogy, think of shopping for groceries. The things you need when shopping are things like food, flowers, stationary, etc. There are specific stores that specialize in all these things - such as Trader Joe's for food, Home Depot for flowers, Office Depot for stationery. These stores may be spread out throughout the city, so you will end up making separate trips for each of those items. If you want to optimize, you could go to one single shopping complex and aim to hit all stores in that parking lot. Or you could do yourself multiple trips and go to one store that sells all these items: Target.

GraphQL, Data Sources, and Visual Testing

In the ever-changing world of development, new tools are constantly popping up to help developers create and manage complex solutions with the ultimate goal of building a great experience for their customers.

Whether it's a tool to help that developer become more productive or an entirely new way of thinking about the architecture of the project, developers are able to spend more time focusing on the unique parts of our code and focus on that great experience.

5 Reasons Why Prismatic Chose GraphQL for Our API

Prismatic is an integration platform used by B2B software companies to build reusable integration workflows and deploy customer-specific instances that handle each customer's unique configuration and credentials.

When we set out to create Prismatic, it was clear that we needed an API for our web app and CLI to use. Additionally, we wanted our developer users to be able to hit our API programmatically so they could manage customers and integrations as they saw fit. This presented a problem: different developers would naturally have different needs and use cases. It didn't make sense to craft a series of custom RESTful endpoints for each individual's needs. GraphQL was growing in popularity (for good reason!) and was an appropriate choice for us given our needs.