DEV Community

Cover image for Basic WordPress & Gatsby Setup - Guide to Gatsby WordPress Starter Advanced with Previews, i18n and more
Henrik Wirth for NeverNull

Posted on • Edited on

Basic WordPress & Gatsby Setup - Guide to Gatsby WordPress Starter Advanced with Previews, i18n and more

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 💾

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
Enter fullscreen mode Exit fullscreen mode

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:

GraphiQL Explorer

Create initial Gatsby site 💻

First of all create a Gatsby project with:

gatsby new gatsby-starter-wordpress-advanced
Enter fullscreen mode Exit fullscreen mode

After that let's install the first couple of plugins we will use for this part of the tutorial:

Plugins

yarn add dotenv gatsby-source-graphql
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

# .env.development
# This is in gitignore and should not be pushed to the repository.

WORDPRESS_URL=http://gatsby-starter-wordpress-advanced.local
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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 an ngrok.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}'`)
Enter fullscreen mode Exit fullscreen mode

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`,
      },
    },
Enter fullscreen mode Exit fullscreen mode

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.

GraphiQL Explorer

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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
                }
            }
        }
    }
`
Enter fullscreen mode Exit fullscreen mode

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}`)
  })
}
Enter fullscreen mode Exit fullscreen mode
  • 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 the allPages array.
  • Then, we map over wpPages and call createPage(). An action passed down by the createPagesStatefully() 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 our pageTemplate 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)

Collapse
 
nikokeefe profile image
Nik O'Keefe • Edited

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!

Collapse
 
cytronaute profile image
cytronaute

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 !

Collapse
 
henrikwirth profile image
Henrik Wirth

Could be that WPGraphQL changed in the newer versions. I'll have to check.

Collapse
 
henrikwirth profile image
Henrik Wirth

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 ✌️

Collapse
 
henrikwirth profile image
Henrik Wirth

I just updated this part.

  • When creating the FrontPage (root page), we need to adjust the path which is used. Instead of taking the uri (which would be home), we instead check the page for isFrontPage and use / as a path.
  • Also you need to delete the index.js in the pages folder.

I updated the codebase of all the parts.

Collapse
 
tomzur profile image
Tomzur 🚀✌️

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.

Collapse
 
robbertvancaem profile image
Robbert van Caem

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' 😬

Collapse
 
henrikwirth profile image
Henrik Wirth

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 ;)

Collapse
 
navdeepsingh profile image
Navdeep Singh

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. ?

Collapse
 
henrikwirth profile image
Henrik Wirth

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.

Collapse
 
anthonysmith8686 profile image
AnthonySmith8686

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!

Collapse
 
henrikwirth profile image
Henrik Wirth

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.

Collapse
 
dendihandian profile image
Dendi Handian

what are the pros/cons of using between gatsby-source-graphql and gatsby-source-wordpress ?

Collapse
 
henrikwirth profile image
Henrik Wirth

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 using gatsby-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.

Collapse
 
edwinalecho profile image
Elshore梦

Asante, gwe asinga papa