Logo
Published on
·7 min read

Next.js 블로그 글에 연관 글 목록 추가하기

개요

제가 사용하는 Tailwind CSS Blog Starter 템플릿에서는 기본으로 이전글, 다음글 보기가 있습니다.

저에게 이전, 다음글은 별 의미가 없게 느껴져서,
이전글, 다음글 대신에 태그와 연관된 글 목록을 보여주도록 변경했습니다.

미리보기

태그와 연관된 글 목록

구현

1. 연관된 글 필터링

글에서 지정된 태그와 동일한 태그를 사용하는 글 목록 5개를 필터링합니다.

  1. pages/blog/[...slug].js 파일을 엽니다.

  2. getRelatedPosts 함수를 추가합니다.

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)
}
  • draft가 true인 글은 제외
  • 현재 글은 제외
  • 현재 글의 태그들과 동일한 태그를 포함하는 글 필터
  • 그 중 최근 글 5개만 필터링

  1. getStaticProps 함수를 수정합니다.

위에서 추가한 getRelatedPosts 함수를 호출하고, relatedPosts 변수에 담아서 props에 추가합니다.

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

  return { props: { post, authorDetails, prev, next, relatedPosts } } // <- relatedPosts 추가
}
  1. Blog 컴포넌트를 수정합니다.

위 props에 추가한 relatedPostsBlog 컴포넌트에 전달합니다.

export default function Blog({ post, authorDetails, prev, next, relatedPosts }) { // <- 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} {/* <- relatedPosts 추가 */}
        />
      ) : (
        <div className="mt-24 text-center">...생략</div>
      )}
    </>
  )
}
  1. components/RelatedPosts.js 파일을 추가합니다.

  2. 내용은 아래와 같습니다. UI는 취향에 따라서 변경하시면 됩니다.

import Link from 'next/link'

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. 표시되기 원하는 Layout 파일 열기
    (저는 이전에 만들어 둔 기본 Layout인 layouts/PostToc.js에 추가했습니다.)

  2. 원하는 Layout에 RelatedPosts 컴포넌트 호출

import RelatedPosts from '@/components/RelatedPosts' // 추가

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

export default function PostLayout({ frontMatter, authorDetails, relatedPosts, children }) { // <- 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} /> {/* <- RelatedPosts 추가 */}
            </div>
          </div>
        </div>
      </article>
    </SectionContainer>
  )
}

코드

코드는 related_post 브랜치 또는 commit history로 확인하실 수 있습니다.

모두의 구글 애널리틱스4:GA4로 하는 디지털 마케팅 데이터 분석, 길벗  아무나 쉽게 따라하는 블로그 마케팅:검색 상위노출을 위한 블로그 마케팅의 모든 것, 페이스메이커  트래픽을 쓸어 담는 검색엔진 최적화:검색엔진이 가장 좋아하는 사이트 만들기, e비즈북스  타입스크립트 리액트 Next.js로 배우는 실전 웹 애플리케이션 개발, 위키북스
(위 링크는 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.)