How to get related posts with Gatsby

June 08, 2021

programming
article cover
Image by Brandi Redd

What we’re going to do

Get related posts to make the so-called ‘related posts’ section in a blog. Showing related posts would decrease the bounce rate and eventually help SEO by improving average engagement time and PV.

With Gatsby, we use Graphql query to get related posts.

It would be better if we had some logic to evaluate which post is more related, but this time we just get posts that have the same tag as the original post.

Premise

I assume we have the following post format,

blog.md

---
title: "blog title"
description: "blog description"
tags: ["tag1", "tag2", ...]
---

and query looks like this.

// blogPost.js

export const BlogPost = () => {
  // ...
} 

export const pageQuery = graphql`
  query BlogPost($id: String!) {
    markdownRemark(id: { eq: $id }) {
      id
      frontmatter {
        title
        description
        tags
      }
    }
  }
`

fetched a single article data

Create a custom resolver

To get the filtered posts by tags, we create a new resolver. With Gatsby, we can do that using the createResolvers API in gatsby-node.js file.

// gatsby-node.js

exports.createResolvers = ({ createResolvers }) => {
  const resolvers = { /* your resolver */ }
  
  createResolvers(resolvers)
}

This time, the resolver ends up like this.

// gatsby-node.js

exports.createResolvers = ({ createResolvers }) => {
  const resolvers = {
    MarkdownRemark: {
      relatedPosts: {
        type: ['MarkdownRemark'],
        resolve: (source, args, context, info) => {
          return context.nodeModel.runQuery({
            query: {
              filter: {
                id: {
                  ne: source.id,
                },
                frontmatter: {
                  tags: {
                    in: source.frontmatter.tags,
                  },
                },
              },
            },
            type: 'MarkdownRemark',
          })
        },
      },
    },
  }
  
  createResolvers(resolvers)
}

In the resolver, we defined a new field relatedPosts in markdownRemark. And relatedPosts should be an array of markdownRemark so then specified the type as type: ['MarkdownRemark'].

In the function resolve(), it’s specified to only get posts that have the same tag as the original post among all MarkdownRemark type. To avoid getting the original post itself, exclude the same ID post.

id: {
  ne: source.id,  
},

That’s it!
Let’s update the query and now we can get related posts.

// blogPost.js

export const BlogPost = () => {
  // ...
} 

export const pageQuery = graphql`
  query BlogPost($id: String!) {
    markdownRemark(id: { eq: $id }) {
      id
      frontmatter {
        title
        description
        tags
      }
      relatedPosts {
        frontmatter {
          title
        }
      }
    }
  }
`

fetched an article data with related posts


Profile picture

Photographer / Web engineer working in Berlin.
A Japanese living with a Slovak wife and two German cats.