Logo
Published on
ยท8 min read

Adding Related Post List to Next.js Blog Posts

I apologize in advance for any awkward expressions in English. ๐Ÿ™

English is not my native language, and I have relied on ChatGPT's assistance to proceed with the translation.

Overview

In the Tailwind CSS Blog Starter template I use, there's a default feature to display Previous and Next posts.

However, I found "Previous" and "Next" posts to be less meaningful for my needs, so instead of displaying them, I decided to show a list of Related Posts based on the tags used in the current post.

Preview

related posts based on the tags

Implementation

We will filter a list of 5 posts that share the same tags as the current post.

  1. Open the pages/blog/[...slug].js file.

  2. Add the getRelatedPosts function.

import kebabCase from '@/lib/utils/kebabCase'

function getRelatedPosts(allPosts, currentPost) {
  const defaultCount = 5

  return allPosts
    .filter(
      (item) =>
        item.draft !== true &&
        item.slug !== currentPost.frontMatter.slug &&
        item.tags.filter((tag) =>
          currentPost.frontMatter.tags.map((m) => kebabCase(m)).includes(kebabCase(tag))
        ).length > 0
    )
    .slice(0, defaultCount)
}
  • Exclude posts with draft set to true.
  • Exclude the current post.
  • Filter posts that contain tags identical to those of the current post.
  • Filter only the latest 5 posts from this list.

  1. Modifying the getStaticProps Function.

Call the getRelatedPosts function we added earlier, store the result in the relatedPosts variable, and add it to the props.

export async function getStaticProps({ params }) {
  const allPosts = await getAllFilesFrontMatter('blog')
  // ... omitted
  const relatedPosts = getRelatedPosts(allPosts, post) // <- add
  // ... omitted

  return { props: { post, authorDetails, prev, next, relatedPosts } } // <- add relatedPosts
}
  1. Modifying Blog Component

Pass the relatedPosts added to the props to the Blog component.

export default function Blog({ post, authorDetails, prev, next, relatedPosts }) { // <- add relatedPosts
  const { mdxSource, toc, frontMatter } = post

  return (
    <>
      {frontMatter.draft !== true ? (
        <MDXLayoutRenderer
          layout={frontMatter.layout || DEFAULT_LAYOUT}
          toc={toc}
          mdxSource={mdxSource}
          frontMatter={frontMatter}
          authorDetails={authorDetails}
          prev={prev}
          next={next}
          relatedPosts={relatedPosts} {/* <- add relatedPosts */}
        />
      ) : (
        <div className="mt-24 text-center">...omitted</div>
      )}
    </>
  )
}
  1. Create a new file named RelatedPosts.js in the components folder.

  2. Add the following content to the file. You can customize the UI according to your preference.

import Link from 'next/link'
import siteMetadata from '@/data/siteMetadata'

const RelatedPosts = ({ posts }) => {
  if (!posts || posts.length === 0) return null

  return (
    <div className="my-2 rounded-lg bg-gray-100 py-4 pl-4 pr-4 dark:bg-gray-800 xl:py-8">
      <h2 className="toc-ignore mb-2 text-base font-bold uppercase tracking-wide text-gray-800 dark:text-gray-200">
        Related Tags Posts
      </h2>
      {posts.map((post, index) => (
        <div key={post.slug} className="py-2">
          <div className="flex flex-row content-center justify-start space-x-6">
            <div className="min-w-[80px] text-xs font-semibold text-rose-400">
              {new Date(post.date).toLocaleDateString(siteMetadata.locale, {
                year: 'numeric',
                month: '2-digit',
                day: '2-digit',
              })}
            </div>
            <Link key={index} href={`/blog/${post.slug}`}>
              <a className="truncate text-sm font-semibold text-gray-500 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300">
                {post.title}
              </a>
            </Link>
          </div>
        </div>
      ))}
    </div>
  )
}

export default RelatedPosts
  1. Open the layout file where you want the RelatedPosts to be displayed. (I added it to the default layout I previously created, layouts/PostToc.js).

  2. Place the RelatedPosts component where you want it to appear.

import RelatedPosts from '@/components/RelatedPosts' // add

const postDateTemplate = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }

export default function PostLayout({ frontMatter, authorDetails, children, relatedPosts }) { // <- add relatedPosts
  const { slug, date, title, tags } = frontMatter

  return (
    <SectionContainer>
      // ...
      <ScrollTopAndComment />
      <article>
        <div className="...">
          <div className="..." style={{ gridTemplateRows: 'auto 1fr' }}
          >
            <div className="...">
              <div className="...">{children}</div>
              <Comments frontMatter={frontMatter} />
              <RelatedPosts posts={relatedPosts} /> {/* <- add RelatedPosts */}
            </div>
          </div>
        </div>
      </article>
    </SectionContainer>
  )
}

Code

You can review the code on the related_post branch or by checking the commit history on GitHub.