Headless CMS — Integrating Gatsby with WordPress

CT Solutions
The Startup
Published in
7 min readMay 6, 2020

A headless CMS is a back-end content management system that allows content authoring, which delivers the content as data over a RESTful API instead of rendering a website.

Headless CMS — Integrating Gatsby with WordPress

In terms of using headless WordPress, it already has REST API built-in, which means we have the API part sorted. Moreover, we can make use of the well-known WordPress back end to manage the content.

Before you run any queries, make sure that the WordPress JSON API is working correctly. You can check this by adding /wp-json at the end of your website URL. For example,

https://demo.wp-api.org/wp-json/

This means with just a few basic and essential steps, we can have our own headless CMS in the form of WordPress. Acknowledging the fact that WordPress is very popular, using it as a headless CMS also means that our CMS can perform well on a different range of hardware and software combinations and also be under regular maintenance and security updates.

What is Gatsby?

Gatsby is a react based static site generator in which we use graphQL to fetch the data. It provides a very good development experience with the best elements of React, webpacks, react routers, graphs QL, or other front end tools. Don’t hang up on the “dead web builder” tag. This term has gone for a long time, but Gatsby is far more similar than an old static site generator to a modern front end frame.

It uses powerful pre-confinement to create a web site using only static files for extremely rapid page loading, service providers, division of code, server-side rendering, smart image loading, asset improvement and data prefixing. Everything from the box. Until I tried it myself, I didn’t believe the speed.

What is WordPress?

WordPress is an open-source blog software package that works unusually well as a content management system, a blog system, or a traditional website. It makes easy for anyone to set up, manage and maintain a website — without having an advanced degree.

WordPress lets you build pages (stand-alone content) and posts (time-driven content) to build out the content of your site. And also, you can easily manage your site’s look and feel with themes. These are custom designs for your site that control how everything is laid out and organized. (If you’re familiar with the term “template” just substitute the term “theme” when talking about WordPress.)

The software is highly customizable and has thousands of “plugin” pieces of software so you can use your site for just about anything.

How to get the best of both WordPress and Gatsby — A combination of Speed and data management from CMS

Gatsby and WordPress is an impressive combo. It makes perfect sense as Gatsby can suck up data from anywhere, and with WordPress having a native REST API, it makes a great pairing. Of course, Gatsby has a first-class plugin for sourcing data from WordPress that even supports data from popular plugins like Advanced Custom Fields.

Step 1: Installation and Setup of gatsby-source-WordPress

Inside your terminal type the following to install this plugin.

npm install — save gatsby-source-wordpress

After installing, setup the gatsby-source-WordPress

Business and e-commerce plans will run the WordPress.org version, so it is recommended to set “hostingWPCOM: false”.

{  resolve: “gatsby-source-wordpress”,  options: {    baseUrl: “live-gatbsyjswp.pantheonsite.io”,    protocol: “https”,    hostingWPCOM: false,    useACF: true,    verboseOutput: true  }}

The baseURL of the WordPress site without the trailing slash and the protocol. This is required.

Example: ‘demo.wp-api.org’ or ‘www.example-site.com'

The protocol. This can be HTTP or https.

The hostingWPCOM indicates whether the site is hosted on wordpress.com. If false, then the assumption is made that the site is self-hosted. If true, then the plugin will source its content on wordpress.com using the JSON REST API V2. If your site is hosted on wordpress.org, then set this to false.

WordPress Plugins

List of useful plugins to make WordPress and gatsby work together

  • Custom post type

it will work seamlessly, no further option needs to be activated. (“Show in REST API” setting needs to be set to true on the custom post in the plugin settings for this to work. It’s set to “false” by default.)

  • ACF
wordpressPost(wordpress_id: { eq: $wordpress_id }) {
title
excerpt
content
author {
name
description
acf {
facebook
twitter
linkedin
}
avatar_urls {
wordpress_48
}
}
date
yoast_meta {
yoast_wpseo_title
yoast_wpseo_metadesc
}
}

The option useACF: true must be activated in your site’s gatsby-config.js.

Fetching Data

By default, gatsby-source-wordpress plugin will fetch data from all endpoints provided by introspection /wp-json response. To customize the routes fetched, two configuration options are available: includeRoutes for whitelisting and excludeRoutes for blacklisting. Both options expect an array of glob patterns. Glob matching is done by minimatch. To test your glob patterns, use this tool. You can inspect discovered routes by using verboseOutput: true configuration option.

includedRoutes: [
"**/posts",
"**/pages",
"**/media",
"**/categories",
"**/tags",
"**/taxonomies",
"**/users",
],

Which would include most commonly used endpoints and would skip pulling Comments.

  • Posts
{
allWordpressPost {
edges {
node {
id
slug
title
content
excerpt
date
modified
}
}
}
}
  • Pages
{   
allWordpressPage {
edges {
node {
id
title
content
excerpt
date
modified
slug
status
}
}
}
}

Same thing for other types of entity (tag, media, categories, …).

  • Media
  • Categories
wordpressPost(wordpress_id: { eq: $wordpress_id }) {
title
excerpt
content
date
categories {
name
slug
}
}
  • Tags
  • Taxonomies
  • Users

How to create templates

We want to create a detailed page for each post node. The path field stems from the original WordPress link and we use it for the slug to preserve URL structure.

class PostTemplate extends Component {
render() {
const { data, location } = this.props;
const post = data.wordpressPost;
const relatedPosts = data.allWordpressPost.edges;
console.log("related posts blog detail ", relatedPosts);
const {
title,
excerpt,
author,
date,
content,
jetpack_featured_media_url: imgUrl,
categories,
yoast_meta: yoastMeta
} = post;
const {
name: authorName,
description,
acf,
avatar_urls: avatarUrl
} = author;
const { wordpress_48: authorImg } = avatarUrl;
const { twitter, facebook, linkedin } = acf;
const { name, slug: categorySlug } = categories[0];
const {
yoast_wpseo_title: metaTitle,
yoast_wpseo_metadesc: metaDesc
} = yoastMeta;
// format date into 12.1.2020 format
const formatDate = formatdate => {
const day = formatdate.getDate();
const month = formatdate.getMonth() + 1;
const year = formatdate.getFullYear();
return `${day}.${month}.${year}`;
};
const newDate = new Date(date);
const formattedDate = formatDate(newDate);
return (
<Layout location={location}>
<Helmet>
<title>{`Blog | ${name} | ${title}`}</title>
<meta name="title" content={metaTitle} />
<meta name="description" content={metaDesc} />
<meta
property="og:image"
content="https://example.com/images/image.jpg"
/>
<meta
name="keywords"
content="JavaScript, Linter, Linting, Pluggable, Configurable, Code Quality"
/>
<meta
name="description"
content="A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease."
/>
<meta name="theme-color" content="#463fd4" />
<meta property="og:locale" content="en_US" />
<meta
property="og:site_name"
content="ESLint - Pluggable JavaScript linter"
/>
<meta property="og:title" content="require-jsdoc - Rules" />
<meta property="og:url" content="/docs/rules/require-jsdoc" />
<meta property="og:image" content="/assets/img/favicon.512x512.png" />
<meta name="twitter:site" content="@geteslint" />
<meta name="twitter:title" content="require-jsdoc - Rules" />
<meta
name="twitter:description"
content="A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease."
/>
</Helmet>
<div className="category blogs-detail">
<BlogDetail
postTitle={title}
excerpt={excerpt}
author={authorName}
authorBio={description}
linkedin={linkedin}
twitter={twitter}
facebook={facebook}
authorImg={authorImg}
date={formattedDate}
content={content}
imgUrl={imgUrl}
categoryName={name}
categorySlug={categorySlug}
/>
<div className="related-articles container">
<div className="inner-container">
{relatedPosts.length > 0 && (
<h4 className="uppercase">Related articles</h4>
)}
{relatedPosts.map(item => {
const relatedPost = item.node;
console.log("related post ", relatedPost);
const {
title: relatedPostTitle,
slug,
jetpack_featured_media_url: relatedPostImgUrl,
date: relatedPostDate,
author: relatedPostAuthor,
categories: relatedPostCategories
} = relatedPost;
const {
slug: relatedPostCategorySlug
} = relatedPostCategories[0];
const newRelatedPostDate = new Date(relatedPostDate);
const relatedPostFormattedDate = formatDate(newRelatedPostDate);
return (
<div className="article-wrapper section grid-2">
<div className="featured-image col">
<a href={`/blog/${relatedPostCategorySlug}/${slug}`}>
<img src={relatedPostImgUrl} alt={relatedPostTitle} />
</a>
</div>
<div className="post-data col">
<small>{relatedPostAuthor.name}</small>
<small>{relatedPostFormattedDate}</small>
<a href={`/blog/${relatedPostCategorySlug}/${slug}`}>
<h4 className="post-title">{relatedPostTitle}</h4>
</a>
</div>
</div>
);
})}
</div>
</div>
</div>
</Layout>
);
}
}export default PostTemplate;

How to use the template

exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(`
{
allWordpressPost {
edges {
node {
id
wordpress_id
path
status
template
format
slug
categories {
slug
wordpress_id
}
}
}
}
}
`);
// Check for any errors
if (result.errors) {
throw new Error(result.errors);
}
// Access query results via object destructuring
const { allWordpressPost } = result.data;
const postTemplate = path.resolve(`./src/templates/post.js`);
allWordpressPost.edges.forEach(edge => {
createPage({
path: `/blog/${edge.node.categories[0].slug}${edge.node.path}`,
component: slash(postTemplate),
context: {
wordpress_id: edge.node.wordpress_id,
category_id: edge.node.categories[0].wordpress_id
}
});
});
};

Go to this URL to create more queries,

http://localhost:3000/___graphiql

Conclusion

We should always analyse the project specifications and goals when choosing a technology. If the emphasis is on scalability, performance, speed of development, long lifecycle and ability to make changes, fast headless WordPress is a good approach.

I didn’t believe the speed until I tried it myself. 😃

Reach out to us via Instagram Twitter LinkedIn

Or send us an email ✉️ on admin@catalyst.sh.

--

--

CT Solutions
The Startup

Driven by the zeal to bring in a change in the digital world, Catalyst Technology Solutions will evolve your brand globally.