When I built my website, I used to store My content in markdown files locally. This was good enough to get started and run my website quickly, until I realize that I have to find a better solution where I can be able to create, keep, manage and distribute My content from anywhere and any device.
Then with a little of research and readings I decided to go with a content management system (CMS), to find one of the most recommended systems is Contentful CMS.
In this post, I will be specifically explaining how I integrated Contentful CMS with My current Gatsby website. So, I assume this post is for those who has basic knowledge of Gatsby and want to integrate a content management system to gain more advantages and flexibility over their content.
First, I would like to mention few points, why I picked Contentful.
- They offer a free plan includes a single space with 3 environments, 2 locals, 48 content types and 25k records.
- It's a language and framework agnostic so you can use your favourite tools.
- Easy setup and flexible content model creation.
- It has scheduling & releases, content versioning, autosave and preview content.
- straight forward integration steps with Gatsby.
Now, let's start.
Setting up Contentful CMS
Let's start with Contentful first, so that you can set up your content model and add your all content data. It's so easy, straight forward and exciting.
1- Create Contentful account
Visit Contentful.com and sign up to create a free account, then log in.
2- Create a Space
A Space: is your place to keep all the content related to a project.
To create a new space:
- Click Add a space, Select your space type from the list.
- Give the space a descriptive name.
- Select “Create an empty space” from the list below the space name, then click Proceed to confirmation.
- Check your space details. Then, click Confirm and create space when you’re ready.
3- Create Content model
Content model: is where you can structure what your content should look like.
Doing this by adding content types for each kind of content in your space: blog posts, projects, images, author bio, SEO metadata and videos.
From Space page, click Content model tab, then click Add content type and fill up the required fields.
4- Add Fields to Content model
Now, you need to define what type of information to store for content type you created. This is done by adding fields.
To add fields:
- Click the “Add field” button and select your desired options. Give the new field a name and click “Create”.
- Be careful when you set up each field and be sure of setting up the correct type for it (short text, long text, date & time, media, ...etc).
- When you finished adding all fields, click save.
5- Add Content
Now you are ready to add your content.
Click Content tab, then click Add content button “ex: Add Blog Post”
Fill out the fields with your content, then click publish.
Repeat for each post you want to add.
Excellent !!!
Now you created your content.
Setting up Gatsby site
If you don't have prior experience with Gatsby framework, I highly recommend it and you can easily start by visiting Gatsby.com and check their Documentation and Tutorials.
And if you want to kick start your project and set up quickly, you can use any starter form their Starter Library
You can create a new project with required tools and plugins to get started including Contentful source plugin and other useful ones.
Simply use terminal to install:
npx gatsby new gatsby-starter-contentful-homepage https://github.com/gatsbyjs/gatsby-starter-contentful-homepage
Open your project folder in your preferred code editor (Personally I use Visual Studio Code), then start the development server: in the terminal, use Gatsby cli command gatsby develop
or use npm npm start
.
Gatsby will start a hot-reloading development environment accessible by default at http://localhost:8000
, then you can start changing your code and see any changes been made and saved on that URL.
Excellent!!!
Now you created a Gatsby App.
Integrate Contentful with Gatsby
In case you have a running Gatsby website already and you want to migrate your content to Contentful CMS, then you need to make below steps first.
- Transfer your content to Contentful CMS.
- Remove any other CMS plugins or related config in your Gatsby project.
Now, you have to install the Contentful plugin in your gatsby project.
In your terminal, install the below plugin.
npm install gatsby-source-contentful
Add the plugin into gatsby-config.js
file.
Check the code snippet below copy and paste it into your gatsby-config.js file
module.exports = { plugins: [ { resolve: `gatsby-source-contentful`, options: { spaceId: `contentful space id`, accessToken: `contentful access token`, }, }, ],}
Now you need to get your unique space id
and access token
from your Contentful space, click on “settings” and select API keys
from the drop-down, then click Add API key
follow the steps.
Choose “Content delivery / Preview tokens” tab, copy the values of Space ID
and Content Delivery API - access token
, then paste them in your gatsby-config.js
file.
Gatsby recommends using dotenv
to secure your keys data, and then expose them to the build as environment variables.
require("dotenv").config({ path: `.env.${process.env.NODE_ENV}`,})module.exports = { plugins: [ { resolve: `gatsby-source-contentful`, options: { spaceId: process.env.CONTENTFUL_SPACE_ID, accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, }, }, ],}
To use Preview API, choose Content Preview API - access token
then add host: "preview.contentful.com",
This Preview API will allow you to preview unpublished content as it were published. So, you can inspect it or show it to your client before publishing it live.
require("dotenv").config({ path: `.env.${process.env.NODE_ENV}`,})module.exports = { plugins: [ { resolve: `gatsby-source-contentful`, options: { spaceId: process.env.CONTENTFUL_SPACE_ID, accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, host: `preview.contentful.com`, }, }, ],}
Don't forget to remove Content Preview API - access token
and host: "preview.contentful.com"
, then add Content Delivery API - access token
in the time of production build.
Now we set everything, let's start develop.
Query data in GraphQL
First run gatsby develop
or npm start
in Your terminal, then go to http://localhost:8000/___graphql
.
It will open View GraphQL, an in-browser IDE to explore your site's data and schema.
You can query all for a particular Content Type
“ex: Blog Posts”,
and You will get all the blog posts fields and data You have created in Contentful.
Then you can select or add which fields data you want to get, a GraphQL query might look like this:
query MyQuery { allContentfulBlogPost { nodes { slug title description publishedDate(formatString: "Do MMMM, YYYY") } } }
Learn more about GraphQL & Gatsby.
Create Pages
Now, you know how to query your data in GraphQL. So, let's use it to build a simple Blog.
We will be creating a Home page with a list of our blog posts, and create a Page template for each post dynamically.
1- Create Home Page
To create a home page with a list of blog posts, first you need the data of the slug, title, description and publishDate to use them in your page components. Map the posts to their data and create a link for each post.
import React from "react"import { Link, graphql } from "gatsby"import Layout from "../components/layout"import SEO from "../components/seo"
// We get the data as props in the Home componentconst Home = ({ data }) => { const posts = data.allContentfulBlogPost.nodes
return ( <Layout> <SEO title="Home" /> <ul> {posts.map(post => ( <li key={post.slug}> <p>{post.publishedDate}</p> <Link to={`blog/${post.slug}`}>{post.title}</Link> <p>{post.description}</p> </li> ))} </ul> </Layout> )}
export default Home
// Fetch all blog posts from Contentfulexport const query = graphql` query MyQuery { allContentfulBlogPost { nodes { slug title description publishedDate(formatString: "Do MMMM, YYYY") } } }`
Create a GraphQL query to source the data of these fields from Contentful, then Gatsby will fetch that data and make it available to your page component during development or build process.
Then, in the page component you list all the blog posts mapping them to their data.
Now if You go to http://localhost:8000/
, you will see your Home page with a list of blog posts.
But if you click on any of these posts you will get 404 page not found
error, that is because you need to tell Gatsby to create a page for each post dynamically.
2- Gatsby Node APIs
To create pages dynamically linked to each blog post, you need to update gatsby-node.js
file, which you should find in the root directory.
const path = require("path")
exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions
const results = await graphql(` query content { allContentfulBlogPost { nodes { slug } } } `)
const posts = results.data.allContentfulArticle.nodes
posts.forEach(post => { createPage({ path: `/blog/${post.slug}`, component: path.resolve("./src/templates/blog-post.js"), context: { slug: post.slug, }, }) })}
Gatsby Node APIs allows you to use an API function called createPage
to dynamically generate a page for each post based on the slug
you fetched from Contentful.
To get the slug
for each Post, you have to create a GraphQL query, use async/await syntax to get a promise response from the graphql function. This response holds all the slug data for all Your posts.
Then take the data and loop through its nodes, use createPage
API function to dynamically create page for each post.
In the createPage function, you specify the parameters needed to create the pages (the path of the page, the component and the context)
Now you need to create blog-post.js
file under Template folder in the ./src
directory, as the template file You pointed in the component parameter.
3- Create Post Template
In the ./src
directory, create a new folder called templates. In this folder, create a file named blog-post.js
.
import React from "react"import { graphql } from "gatsby"import { MDXRenderer } from "gatsby-plugin-mdx"import Layout from "../components/layout"import SEO from "../components/seo"
const BlogPosts = ({ data }) => { const { title, publishedDate, body } = data.contentfulBlogPost
return ( <Layout> <SEO title={title} /> <div> <p>Published on {publishedDate} </p> <p>{body.childMdx.timeToRead} min read</p> <h1>{title}</h1> </div> <article> <MDXRenderer>{body.childMdx.body}</MDXRenderer> </article> </Layout> )}
export default BlogPosts
export const query = graphql` query ($slug: String!) { contentfulBlogPost(slug: { eq: $slug }) { title slug publishedDate(formatString: "Do MMMM, YYYY") body { childMdx { body timeToRead } } } }`
Create a query that has a variable ($slug: String!)
, then add a statement (slug: { eq: $slug }
to the contentfulBlogPost to fetch each blog depends on $slug
that you get from the createPage function in the gatsby-node.js file.
In the above code I use MDXRenderer
to render the content body
, this is only applicable If you choose to set your content body
as a long text Markdown field and not as a rich text field while creating Content model in Contentful.
To use MDXRenderer
, first You have to Install gatsby-plugin-mdx
in the gatsby-config.js
file.
Personally, I prefer to use Markdown for better control over my content writing.
Also, MDX lets you write JSX embedded inside markdown. It’s a great combination because it allows you to use markdown and JSX for more advanced components.
Oh! Finally, we are done!!!
Congratulations!!!
You have created your own Blog with Gatsby and Contentful 😀.
For any questions or further clarification please leave a comment below, and I will be glade to answer.
Thanks for reading!