How to: Build a blog with Gatsby and GraphCMS
February 10th, 2019
Written by: Tom Settle

Gatsby
GraphCMS
JavaScript

I want to show you how easy it can be to create an extremely fast and customizable blog site using some of the newest and greatest technologies in JavaScript today.

Technologies we will be using

  • Gatsby

  • React

  • GraphQL

  • GraphCMS

1. Getting Started (Installations)

We will be installing all packages using npm so please make sure you have Node.js installed and updated; you can do so here if you have not. -- Node.js

Next, we will install and use the Gatsby CLI, this is a great tool that lets us do everything we need to do with Gatsby including creating a new site from a template or completely from scratch.

Gatsby CLI

Open your terminal of choice and enter

npm install --global gatsby-cli

Gatsby has a huge library of starters that can be used when you first create the site, today it makes the most sense to use their gatsby-starter-blog template. To do this we add the repo link to the end of the gatsby new command. Other starts can be found here

Next, let's create the site and cd into it. We can call it blog-tut, run

gatsby new blog-tut https://github.com/gatsbyjs/gatsby-starter-blog && cd blog-tut

Now that our site and folder are created make sure you are in your sites directory and run gatsby develop

This creates a web server instance on localport:8000 and will open in your browser

That was super easy... this blog site is using static markdown files that are saved directly in the sites folder we want to manage all this content from a CMS. This would most likely be the case if you were making something like this for a client because most people will not want to be writing raw markdown files.

2. Setting up and Plugins

First lets do some cleanup

Starting with the author header, let's go ahead and update that without information. This will also give you a better idea of how the file structure works.

Navigate to gatsby.config.js

The top of the file shows an object called siteMetadata this is where the bio page is pulling the data from so go ahead and update your information here

siteMetadata: { title: 'Gatsby Starter Blog', author: 'Tom Settle', description: 'A starter blog demonstrating what Gatsby can do.', siteUrl: 'https://gatsby-starter-blog-demo.netlify.com/', social: { twitter: 'tsettle44', }, }

Go ahead and save gatsby.config.js and navigate to

-- src |-- components |-- Bio.js

At the bottom of the file the const bioQuery is the GraphQL query that is running locally to grab that data, you can also see that this is where is it grabbing the profile image which is located in the content folder in the root. You can also change the supporting text of the Bio component in the <p> tag to update the city it displays.

Great! now our bio component is updated. Next, let's go ahead and connect GraphCMS and get some dynamic blog posts in there.

Connect GraphCMS

Create a GraphCMS account or login [here](https://graphcms.com/) Once you login create a new project. Give it a name, description, and select the region with the lowest latency. Select the developer plan, it is free and has everything we will need.

Creating Post Schema

On the left navigation bar go to Schema and add a new Model named Post.

Here we will add all the fields that we will query from our client site.

Add Fields

  • Title - Single Line Text

  • Slug - Single Line Text

  • Date - Date

  • Preview - Multi-Line Text

  • Body - Markdown

Add Content Next, we will go ahead and add some dummy posts. Rather than quickly writing up 3 blog posts go ahead and use this site and copy the raw text. On GraphCMS navigate to the content section and add a Post and fill out each of the inputs. (Slug is going to be the title all lowercase with no spaces; this will act as the URL placeholder eg - "blog-post-example" When finished your Post content should have three published blogs. To check that your API is working you can use GraphCMS's native GraphQL playground called API Explorer. Try the query.

{ posts { title slug date body } }

This should return all your posts and each field that we queried for in our GraphQL request! Great so now we have the content and know that the API is working, let's go ahead and connect that to our client.

Gatsby GraphCMS plugin

In order to connect our CMS we need to install a plugin to our client-side Gatsby site. To do this in your terminal enter npm i gatsby-source-graphcms

With this plugin, we can add some simple code into the gatsby-config.js file and boom that API data is now accessible on our client.

Add this object to your plugins array.

{ resolve: `gatsby-source-graphcms`, options: { endpoint: `graphql_endpoint`, query: `{ posts(orderBy: date_DESC) { id title slug date preview body } }`, }, },

Replacing the graphql_endpoint with the respective string from your GraphCMS Dashboard.

Creating pages

Once the sire renders we want to create pages and paths for each blog post using the slug field pulled from the CMS. To do this we just need to modify the gatsby.node.js file a little.

Go ahead and replace the gatbsy.node.js file with this code.

const path = require(`path`) const { createFilePath } = require(`gatsby-source-filesystem`) exports.createPages = ({ graphql, actions }) => { const { createPage } = actions const blogPost = path.resolve(`./src/templates/blog-post.js`) return graphql( ` { allPost { edges { node { slug } } } } ` ).then(result => { if (result.errors) { throw result.errors } // Create blog posts pages. const posts = result.data.allPost.edges posts.forEach((post, index) => { const previous = index === posts.length - 1 ? null : posts[index + 1].node const next = index === 0 ? null : posts[index - 1].node createPage({ path: post.node.slug, component: blogPost, context: { slug: post.node.slug, previous, next, }, }) }) }) } exports.onCreateNode = ({ node, actions, getNode }) => { const { createNodeField } = actions if (node.internal.type === `MarkdownRemark`) { const value = createFilePath({ node, getNode }) createNodeField({ name: `slug`, node, value, }) } }

This will like I said create a page for each of the blog posts using the slug as the pathname!

Client-side pages

Lastly, let's go ahead and update index.js to query from our API and display the content on the page.

At the bottom of the file, let's replace the const pageQuery with our query.

export const pageQuery = graphql` query { site { siteMetadata { title } } allPost { edges { node { title slug date(formatString: "MMMM DD, YYYY") preview body } } } } `

Next let;s update the JSX to render that data. Replace the const post with const post = data.allPost.edges Then lastly, replace the post.map function with this...

{ posts.map(({ node }) => { const title = node.title || node.slug return ( <div key={node.id}> <h3 style={{ marginBottom: rhythm(1 / 4), }} > <Link style={{ boxShadow: `none` }} to={node.slug}> {title} </Link> </h3> <small>{node.date}</small> <p>{node.preview}</p> </div> ) }) }

And Boom refresh and we have our homepage should now be populated with the data from our CMS!

Awesome, so the last thing we have to do is update the blog-post.js so when we click on the blog link it will take us to the full blog. This will be easy. Navigate to blog-post.js and replace the query at the bottom with...

export const pageQuery = graphql` query BlogPostBySlug($slug: String!) { site { siteMetadata { title author } } post(slug: { eq: $slug }) { id title slug preview date(formatString: "MMMM DD, YYYY") body } } `

Next, replace the render() statement with...

render() { const post = this.props.data.post; const siteTitle = this.props.data.site.siteMetadata.title; const { previous, next } = this.props.pageContext; return ( <Layout location={this.props.location} title={siteTitle}> <SEO title={post.title} description={post.preview} /> <h1>{post.title}</h1> <p style={{ ...scale(-1 / 5), display: `block`, marginBottom: rhythm(1), marginTop: rhythm(-1) }} > {post.date} </p> <div dangerouslySetInnerHTML={{ __html: post.body }} /> <hr style={{ marginBottom: rhythm(1) }} /> <Bio /> <ul style={{ display: `flex`, flexWrap: `wrap`, justifyContent: `space-between`, listStyle: `none`, padding: 0 }} > <li> {previous && ( <Link to={previous.slug} rel="prev"> ← {previous.title} </Link> )} </li> <li> {next && ( <Link to={next.slug} rel="next"> {next.title} → </Link> )} </li> </ul> </Layout> ); }

We are basically done! Everything should work now, but we need to add a package to render our markdown from GraphCMS as HTML

To do this install npm i react-markdown

Now at the top of blog-post.js import ReactMarkdown from 'react-markdown', and then replace the div where we insert the post.body with <ReactMarkdown source={post.body} />

There you have it! A quick and easy blog template using a headless CMS! The major advantage here is now that we have the skeleton you can customize this however you like and always just pull the data in from the same place. Thanks so much for following along!

© 2020, Built by me with ❤️ and Gatsby

View Source