Gatsby & WordPress — Bringing together the best of a CMS and an SSG
This will be an ongoing series of posts that will explore the various ways in which to effectively bring together the magic of Static Site Generation (SSG) with the power of the CMS that has stood the test of time.
In this post, we’ll take a look at what Gatsby is and does and how to use Gatsby’s own GraphQL source plugin to interface with a CMS like WordPress.
Prerequisites:
- Basic knowledge of React and UI components (a little bit of GraphQL know-how; not really necessary though for this post)
- WordPress setup (you could use the docs or Local by Flywheel to easily spin up a WP instance)
- A stable version (LTS) of Node.js and NPM
What is Static Site Generation (or SSG)?
Unlike server-side rendering (SSR) where everything that is needed on a page is rendered on the server at runtime and then sent down to the browser for download and rendering, static site generation is a solution where you generate a site and its pages/routes at build/compile-time and serve everything as HTML, CSS and JS artefacts (and images, of course). What SSG helps with is the time to the first byte i.e., TTFB (and a few others things discussed below), which is a fancy way of saying the first frame of the web page your user will see.
Some of the frameworks that already help with SSG in the React world are Gatsby and Next.
The docs define Gatsby as a blazing fast modern site generator for React.
Let’s jam on a little about the Jamstack
No introduction about Gatsby is complete without an introduction to the Jamstack.
The Jamstack is an architecture that is essentially a coming together of many tools, workflows and best practices of building, deploying and scaling sites, that is growing every day to support a wide range of use-cases and websites/apps.
J A M stack stands for:
- JavaScript: which is mainly the technology used in the frontend framework/library that is used to build the UI components of the website/app.
- APIs: The API economy that has built over the years and is currently available for use with websites/apps
- Markup: The idea is to be able to generate and deploy all files as HTML files
Why Jamstack?
- Pre-rendering — This is a core principle that is used in the Jamstack world where the entire site is pre-built even before deploying into highly optimized assets and static artefacts (HTML, JS, CSS) that can be served over a cheap yet awesome hosting service like Netlify ❤️
- Decoupling & Security — Since the API layer is completely separate and operates like a third party entity, the site does not have server/database related vulnerabilities
- Highly Scalable — Given that the previous two points take care of optimization and quick secure deploys, this part is a natural consequence since the generated sites can be deployed to be accessed with quick response times in any region through any global CDN provider
Now let’s generate a static site
In order to generate your first gatsby site, this is all you’ll need to run in your terminal that’s configured to run NodeJS and related commands:
npx gatsby new <directory-name> gatsbyjs/gatsby-starter-hello-world
<directory-name> would be the name of the folder where all the good stuff generated by the gatsby-cli will be stored. Once created, just change directory with the cd command and then run gatsby develop
:
cd <directory-name>
gatsby develop
gatsby develop
basically fires up a hot reloading environment for local development at http://localhost:8080 (or a different port depending on your local setup).
The gatsby new command that we executed earlier will generate the following directory structure as a starting point for your Gatsby site.
├── LICENSE
├── README.md
├── gatsby-config.js
├── package-lock.json
├── package.json
├── src
│ └── pages
│ └── index.js
└── static
└── favicon.ico
Note: During any part of this exercise, if you notice that the Gatsby site is displaying stale or out of sync data (this could be due to the GraphQL cache or other factors like changes in the gatsby-node.js file), just stop this command in your terminal (ctrl + c) and re-run gatsby develop again.
Setting up the WordPress side of things
Once you have the WordPress instance setup (refer links mentioned in the prerequisites), you’ll need two plugins that you’ll need to install in WordPress:
- WPGraphQL: This plugin exposes a full GraphQL API layer for WordPress. You may get the latest zip from here.
- WPGraphiQL: Notice the ‘i’ as in graphical. This will create an interactive playground so you may familiarize yourself with the WordPress GraphQL API for some much-needed Swagger (see what I did there? 😉). Download the zip from here.
Clicking around in the GraphiQL playground will give you a feel of how to build a query and then hitting the ‘play’ button up top will display the query response on the right.
This is all we’ll need for our WordPress instance. Let’s get back to our Gatsby project in our terminal.
Gatsby Config
All the configuration related data like stuff need for SEO (site title, site URL, description), plugins that manage and transform other Gatsby site-related data (GraphQL source plugins, filesystem plugins and image optimization plugins), etc. go into gatsby-config.js
In order to pull in the gatsby-source-graphql
plugin into our gatsby project we’ll need to install the npm package first with this command in our project root:
npm install gatsby-source-graphql
Then to pull in the remote GraphQL API that we set up earlier in our WordPress dashboard, we configure the plugins array in the gatsby-config.js file like so:
gatsby-source-graphql
is used in the world of Gatsby sites to connect remote GraphQL APIs to Gatsby’s own GraphQL layer. In this above code, the typeName
was set to ‘WPGraphQL’(this can be set to any arbitrary name), thefieldName
to ‘wpgraphql’ which we will use next to query the pages created in WordPress and then url
is set to the URL that we intend to query from (this will change based on your WordPress site URL).
Once you’ve your Gatsby config set up like above, launch your Gatsby GraphiQL. Yes, this is similar to the GraphiQL we installed in our WordPress earlier. These are again to interact with any GraphQL schema that belongs to your Gatsby site/app. The URL for your Gatsby GraphiQL may be found in your terminal where you run the command: gatsby develop
like earlier:
Now that we have the remote schema within our Gatsby project, we need to query the WordPress pages that we want to be created on our Gatsby site. For this, we created two additional pages in our WordPress instance in addition to the ‘sample-page’ that ships by default in WordPress.
In order to build our GraphQL query, we need to add all the fields/nodes we need from our ‘wpgraphql’ schema:
Now onto creating the actual pages with the query we now have handy.
Gatsby Node APIs
Since Gatsby has a build cycle that generates all the artefacts needed for rendering and deploy of the site/app, Gatsby gives us a cool set of Node APIs for use in this very process. The APIs help with creating pages dynamically or making other changes to the way GraphQL is structured or to hook into different events during the build process.
In order to create our pages, we use the createPages
Node API that ships with Gatsby. Every API supported by Gatsby has a bunch of Node helpers that’s passed in through the first argument.
Gatsby uses Redux (a popular state management library from the JS frontend libraries’ world) under the hood to manage state and therefore the actions object seen passed in the async function above as one of the ES6 destructured objects contains the createPage
Node helper. We use this helper on line 21 to create our page after looping over the pages response object that we received with our GraphQL query await.
The createPage
is passed an object with a path property set to be the same as our WordPress page slug. This will make sure that URL of each page will be of the format: example.com/<page-slug>.
The other two properties are a component and a context respectively. The component as we will see is a regular React component that uses the page.id that we are passing in as the context to query for page-specific data.
Page Template
In order to render each of our dynamically generated pages, we’ll need to prepare another GraphQL query from the Gatsby GraphiQL interface (as we did earlier) to be able to query page data like so:
The ($id: ID!) mentioned in line 5 allows us the ability to query with a dynamic ID for each page. This dynamic id
is what we passed in, in our previous createPage
step. How is this sorcery happening you ask?
That’s because of the particular way in which Gatsby handles its special GraphQL template tag that we are using on line 4 in the above gist. There’s more information about how this is done in the Gatsby Internals section in the Gatsby docs on how queries work but suffice it, for now, to say that the GraphQL tag automagically passes the context information as variables to be used by the GraphQL query (in this case, the only variable needed is id).
With all of this setup and if you still have gatsby develop
running in your terminal project root, navigate to the localhost URL with the route set as one of the slugs we saw earlier in the GraphQL query response objects: localhost:8000/<page-slug>
Of course, there are so many more things we can do now that we have all the pages from WordPress populating in our Gatsby site and being rendered through our basic React component. In the upcoming posts, we’ll get into creating nav menus, layouts, pagination and other good stuff.
Let’s generate! 🎉
Before we sign off on this post, there’s one last thing we can do to see the real magic of static site generation. All we need to do for this is instead of running gatsby develop
in our project root, we’ll run gatsby build
to check how the output of the build process looks like. Once the build process has completed, open the new public/ folder that would have now got generated in your project root.
You’ll see all of the built artefacts including our WordPress pages that got dynamically fetched with our GraphQL queries and that got built and bundled into HTML and JS files (no CSS because we don’t have any styles added yet)
That’s all for now, folks!