Hooking up our WordPress with a Gatsby generated site, will be the first steps we are talking on our journey towards a client-ready static-dynamic site.
Table of Contents
- Install WordPress and Plugins 💾
- Create initial Gatsby site 💻
- Final Thoughts 🏁
- Credits ❤️
- What's Next ➡️
Install WordPress and Plugins 💾
Okay, so let's start by installing WordPress. Use whatever you want for that, either local or online. I'll be using Local by Flywheel.
Plugins
- WPGraphQL (Documentation) - This will create your GraphQL endpoint.
- WPGraphiQL - Adds a GraphiQL to your WP-Admin, which helps to see changes quickly and figure out what to query.
You can download the .zip files of these repositories and install them through WP-Admin or just navigate to your plugin folder and do a git clone
like so:
git clone https://github.com/wp-graphql/wp-graphql
git clone https://github.com/wp-graphql/wp-graphiql
Now make sure to activate all the plugins.
To check out if everything works, head over to the GraphiQL explorer inside your WordPress Admin area and start playing around with it:
Create initial Gatsby site 💻
First of all create a Gatsby project with:
gatsby new gatsby-starter-wordpress-advanced
After that let's install the first couple of plugins we will use for this part of the tutorial:
Plugins
- dotenv - For loading environment variables.
- gatsby-source-graphql - Helps to source the data from our WordPress GraphQL endpoint.
yarn add dotenv gatsby-source-graphql
Configuration
We will use dotenv
to have two different files for environment variables. Create .env.development
and .env.production
in the root of your gatsby site's folder. The development one will be called when gatsby develop
is used and production is for gatsby build
.
Add .env.development
to .gitignore
:
# .gitignore
.env.development
# .env.development
# This is in gitignore and should not be pushed to the repository.
WORDPRESS_URL=http://gatsby-starter-wordpress-advanced.local
If you use a local WordPress instance, then replace http://gatsby-starter-wordpress-advanced.local
with the URL to your local installation. If you just use a online WordPress instance, then use the URL to that.
# .env.production
# Don't put any sensible data here!!!
WORDPRESS_URL=https://your-online-wordpress-instance.dev
Replace https://your-online-wordpress-instance.dev
with the URL to your online WordPress instance. In Netlify you also can use environment variables and combine them with what is in this file.
If you use Local By Flywheel, you can expose your local site by enabling
Live Link
. You will get anngrok.io
URL, which you can use for the production WORDPRESS_URL.
Now in your gatsby-config.js
add this to the top before the module.exports
:
let activeEnv =
process.env.GATSBY_ACTIVE_ENV || process.env.NODE_ENV || "development"
console.log(`Using environment config: '${activeEnv}'`)
require("dotenv").config({
path: `.env.${activeEnv}`,
})
console.log(`This WordPress Endpoint is used: '${process.env.WORDPRESS_URL}'`)
The snippet above will help to require the right .env
file.
Add the following to your configs module.exports
inside plugins:[...]
:
{
resolve: "gatsby-source-graphql",
options: {
typeName: "WPGraphQL",
fieldName: "wpgraphql",
url: `${process.env.WORDPRESS_URL}/graphql`,
},
},
This will hook up your Gatsby with the WordPress instance. And expose this data under wpgraphql
. Note: This makes your schema different to the one that is exposed in you WordPress GraphQL endpoint. As soon as you are using it with Gatsby, you now have to wrap your queries with wpgraphql{...}
.
Try running gatsby develop
and navigate to http://localhost:8000/___graphql
. You will see something like this. Play around with the GraphiQL-Explorer to get familiar with the WPGraphQL schema.
Create Pages & Posts
Now let's see, how we can create pages and posts, based on the WordPress data. First remove the index.js
and page-2.js
in your pages folder. Then, we start with some very simple templates.
Page Template
// src/templates/page/index.js
import React from "react"
import Layout from "../../components/layout"
import SEO from "../../components/seo"
const Page = ({ pageContext }) => {
const page = pageContext.page
return (
<Layout>
<SEO title={page.title} />
<h1>{page.title}</h1>
<div dangerouslySetInnerHTML={{__html: page.content}} />
</Layout>
)
}
export default Page
Post Template
// src/templates/post/index.js
import React from "react"
import Layout from "../../components/layout"
import SEO from "../../components/seo"
const Post = ({ pageContext }) => {
const post = pageContext.post
return (
<Layout>
<SEO title={post.title} />
<h1> {post.title} </h1>
<div dangerouslySetInnerHTML={{__html: post.content}} />
</Layout>
)
}
export default Post
Gatsby Node
In your Gatsby node, add these lines:
// gatsby-node.js
const createPages = require("./create/createPages")
const createPosts = require("./create/createPosts")
exports.createPagesStatefully = async ({ graphql, actions, reporter }, options) => {
await createPages({ actions, graphql, reporter }, options)
await createPosts({ actions, graphql, reporter }, options)
}
To separate their concerns, we split up the creation of posts and pages in different files. Create a folder called create
in the root directory.
Create Pages
First we add some requires and define our GraphQL query.
// create/createPages.js
const pageTemplate = require.resolve('../src/templates/page/index.js');
const GET_PAGES = `
query GET_PAGES($first:Int $after:String) {
wpgraphql {
pages(
first: $first
after: $after
# This will make sure to only get the parent nodes and no children
where: {
parent: null
}
) {
pageInfo {
hasNextPage
endCursor
}
nodes {
id
title
pageId
content
uri
isFrontPage
}
}
}
}
`
You can see some variables are passed down the query. Refer to the GraphQL Docs for more information on GraphQL query variables. Also, you can see pageInfo with hasNextPage
and endCursor
. This will help for pagination, as we should not query for all pages/posts together, but rather do 10 at a time. This will ensure, that we don't put too much pressure on our WordPress backend.
// create/createPages.js
const allPages = []
let pageNumber = 0
const itemsPerPage = 10
/**
* This is the export which Gatbsy will use to process.
*
* @param { actions, graphql }
* @returns {Promise<void>}
*/
module.exports = async ({ actions, graphql, reporter }, options) => {
/**
* This is the method from Gatsby that we're going
* to use to create pages in our static site.
*/
const { createPage } = actions
/**
* Fetch pages method. This accepts variables to alter
* the query. The variable `first` controls how many items to
* request per fetch and the `after` controls where to start in
* the dataset.
*
* @param variables
* @returns {Promise<*>}
*/
const fetchPages = async (variables) =>
/**
* Fetch pages using the GET_PAGES query and the variables passed in.
*/
await graphql(GET_PAGES, variables).then(({ data }) => {
/**
* Extract the data from the GraphQL query results
*/
const {
wpgraphql: {
pages: {
nodes,
pageInfo: { hasNextPage, endCursor },
},
},
} = data
/**
* Map over the pages for later creation
*/
nodes
&& nodes.map((pages) => {
allPages.push(pages)
})
/**
* If there's another page, fetch more
* so we can have all the data we need.
*/
if (hasNextPage) {
pageNumber++
reporter.info(`fetch page ${pageNumber} of pages...`)
return fetchPages({ first: itemsPerPage, after: endCursor })
}
/**
* Once we're done, return all the pages
* so we can create the necessary pages with
* all the data on hand.
*/
return allPages
})
/**
* Kick off our `fetchPages` method which will get us all
* the pages we need to create individual pages.
*/
await fetchPages({ first: itemsPerPage, after: null }).then((wpPages) => {
wpPages && wpPages.map((page) => {
let pagePath = `${page.uri}`
/**
* If the page is the front page, the page path should not be the uri,
* but the root path '/'.
*/
if(page.isFrontPage) {
pagePath = '/'
}
createPage({
path: pagePath,
component: pageTemplate,
context: {
page: page,
},
})
reporter.info(`page created: ${page.uri}`)
})
reporter.info(`# -----> PAGES TOTAL: ${wpPages.length}`)
})
}
- So here we first define our
fetchPages()
function, that will recursively keep on fetching pages (10 at a time) until there is no more to fetch. It adds them to theallPages
array. - Then, we map over
wpPages
and callcreatePage()
. An action passed down by thecreatePagesStatefully()
function given by the Gatsby API (See docs here). - We use
page.isFrontPage
to check if we need to adjust the path. For the home page we want the path to be the root path/
instead of/home/
. - In
createPage()
we set the path equal to the uri. This will be creating the slug for the individual page. The component gets ourpageTemplate
assigned and finally, we pass the pages data to the context.
-> See the complete file here: createPages.js
Create Posts
createPosts is basically the same with the exception of prefixing the path with blog/
.
-> See the complete file here: createPosts.js
Final Thoughts 🏁
If you run gatsby develop
now, you should be able to see your pages under http://localhost:8000/sample-page/. If you are not sure what pages got created. Just type in some random slug like http://localhost:8000/asdf/ and you will get an overview of all the pages there are.
This will give you the basic setup we need for the upcoming parts of this tutorial.
Find the code here: https://github.com/henrikwirth/gatsby-starter-wordpress-advanced/tree/tutorial/part-2
Credits ❤️
This part is highly inspired by staticfuse's (gatsby-theme-publisher). You should check it out!
What's Next ➡️
Next we'll build our navigation based on a WordPress menu.
Part 3 - Setup Menu Navigation
Top comments (15)
Hey, maybe this can help someone....or maybe its a teething problem.
My createPages kept failing when initially running gatsby develop...."Cannot read property 'uri' of null".
I removed uri from the query and it worked fine.
I then replaced it after 'isFrontPage' and it worked but wouldn't work if I placed it anywhere else in the query.
Possibly just a quirk in my enviroment but thought worth sharing....or if anyone has an explanation.
Respect Henrik!
Hey Henrik,
Thank you for this tutorial, which is I think a good way to get started with gatsby + wp :)
I had an issue when starting the project at the end of this part of the tutorial. The page and post were being created with an extra '/' at the end of the path, resulting in blank pages at localhost:8000/sample-page/ . I had to change let pagePath =
/${page.uri}/
to let pagePath =/${page.uri}
in order to have it rolling.Any idea why this happened?
Thank you !
Could be that WPGraphQL changed in the newer versions. I'll have to check.
Heya, so I just tested it with an older and newer version of WPGraphQL and indeed the newer version has a slash now in the end of the
uri
. So I'll have to update the tutorial. There has been a lot of breaking changes in WPGraphQL lately, so I'll go over some more stuff too, as soon as I have some more time. Thanks for the info ✌️I just updated this part.
home
), we instead check the page forisFrontPage
and use/
as a path.index.js
in the pages folder.I updated the codebase of all the parts.
Hi Henrik, great and advanced guide on the topic thanks for the tutorial and tips. I wanted to mention another local development tool called DevKinsta which works out of the box on your local computer.
Very nice article, thank you for taking the time to jot this down! Currently we're running NextJS apps where the data is fetched from Wordpress on every request. I planned on taking Gatsby for a spin and with your article(s) I'm pretty sure I'll make progress faster 🙏🏻
I just found a minor thingy in this sentence: "As soon as you are usinging it with Gatsby" > I think you meant 'using' instead of 'usinging' 😬
Hi Robbert,
thanks for suggesting the typo fix. It is so much to write down, I often forget to even proof-read it once. So, that is more than welcome, also for the upcoming parts.
If you find some more typos, I host all my articles here: github.com/henrikwirth/dev.to/tree...
Feel free to create a PR or if it suits you better, a comment here is also welcome.
Glad you like the tutorial so far. Actually I really would love to give NextJS a spin also, but my time is limited, so maybe next year. I'll keep you in mind ;)
Hello Henrik!
To deploy at production, the WordPress site must be at HTTPS, either Mixed content error raised by the browser and blocked the resource to load.
Where we can host with WordPress or say PHP project with SSL service enabled like Netlify, Zeit, Heroku, etc. ?
I can't tell you where to host the site. Any website host that runs PHP and gives you SSL is fine I guess. For the tutorial you can just use a local installation. I used Local by flywheel. It also gives you an option to expose your local WP to the internet. I think the nextpart of the tutorial talks about that a bit more.
Hey, I keep getting this error.
warn The gatsby-source-graphql plugin has generated no Gatsby nodes. Do you need it?
After this are several graphql errors e.g.:
There was an error in your GraphQL query:
Cannot query field "wpgraphql" on type "Query".
Looks the the plugin won't install for me, not sure what to do here. Any advice appreciated!
Seems like something with your GraphQL query is not aligned with the newest version of WPGraphQL. In general the advice is to use the new v4 version of gatsby-source wordpress plugin. Sadly this tutorial is a bit out of date.
what are the pros/cons of using between
gatsby-source-graphql
andgatsby-source-wordpress
?Well, the old
gatsby-source-wordpress
was using the REST API of WordPress to create the schema. This ended up being a "not so well formed" schema, which made it hard to work with. So certainly I don't recommend usinggatsby-source-wordpress
as it is now.That being said Tyler Barnes is working on this PR: github.com/gatsbyjs/gatsby/issues/...
The idea is to use WPGraphQL as base, which would be similar as the approach with
gatsby-source-graphql
, but with a lot of additional goodies. I think they are trying to get it ready until roughly March.So as of now I recommend using
gatsby-source-graphql
with WPGraphQL, because that will be closest to whats coming with V4 of the Gatsby-WordPress plugin. Jason Bahl, the lead developer of WPGraphQL is working for Gatsby for some time now. So this should support the fact, that WPGraphQL is the way to go with Gatsby.Asante, gwe asinga papa