W.D.Sphere

ウェブ開発の技術を楽しむ空間

Gatsby.js スタティックサイトのチュートリアル Part 10

Gatsby.jsでMDXを使用したブログサイトを作成するチュートリアルのPart10です。今回はブログにタグ機能を追加します。下記のような流れで作成します。

  1. MDXファイルにタグを追加する
  2. ブログポストのすべてのタグを取得するクエリを作成する
  3. タグページのテンプレートを作成する
  4. テンプレートを使用するためにgatsby-node.jsを修正する
  5. タグリストのページを作成する
  6. ブログリストにタグを表示する

MDXファイルにタグを追加する

各ブログポストのMDXファイルにタグを追加します。各ファイルのfrontmatterを下記のように変更します。

blog/first-post/index.mdx frontmatter

---
title: "First Post"
date: "2024-04-01"
slug: "first-post"
hero_image: "./sample-image-1.png"
hero_image_alt: "Alt text for your image"
tags: ["Webdev", "HTML"]
---

blog/second-post/index.mdx frontmatter

---
title: "Second Post"
date: "2024-04-02"
slug: "second-post"
hero_image: "./sample-image-2.png"
hero_image_alt: "Alt text for your image"
tags: ["Webdev", "CSS"]
---

blog/third-post/index.mdx frontmatter

---
title: "Third Post"
date: "2024-04-03"
slug: "third-post"
hero_image: "./sample-image-3.png"
hero_image_alt: "Alt text for your image"
tags: ["Webdev", "Javascript"]
---

blog/fourth-post/index.mdx frontmatter

---
title: "Fourth Post"
date: "2024-04-04"
slug: "fourth-post"
hero_image: "./sample-image-4.png"
hero_image_alt: "Alt text for your image"
tags: ["Webdev", "React"]
---

blog/fifth-post/index.mdx frontmatter

---
title: "Fifth Post"
date: "2024-04-05"
slug: "fifth-post"
hero_image: "./sample-image-5.png"
hero_image_alt: "Alt text for your image"
tags: ["Webdev", "Gatsby"]
---

blog/sixth-post/index.mdx frontmatter

---
title: "Sixth Post"
date: "2024-04-06"
slug: "sixth-post"
hero_image: "./sample-image-6.png"
hero_image_alt: "Alt text for your image"
tags: ["Webdev", "Git"]
---

ブログポストのすべてのタグを取得するクエリを作成する

GraphiQLで下記のようにクエリを作成します。

gatsby-static-site-tutorial10-01

fieldValueでタグ名が取得できているのが確認できます。クエリは下記のようになります。

query {
  allMdx(limit: 1000) {
    group(field: {frontmatter: {tags: SELECT}}) {
      fieldValue
    }
  }
}

タグページのテンプレートを作成する

それぞれのタグのページを表示できるように下記のようにテンプレートファイルを作成します。

src/templates/tags.js

import * as React from 'react'
import { Link, graphql } from 'gatsby'
import Layout from '../components/layout'
import Seo from '../components/seo'

const Tags = ({ pageContext, data }) => {
  const { tag } = pageContext
  const { edges, totalCount } = data.allMdx
  const tagHeader = `${totalCount} post${
    totalCount === 1 ? "" : "s"
  } tagged with "${tag}"`

  return (
    <Layout>
      <h1>{tagHeader}</h1>
      <ul>
        {edges.map(({ node }) => {
        const { slug } = node.frontmatter
        const { title } = node.frontmatter
        return (
        <li key={slug}>
          <Link to={`/blog/${slug}`}>
	    {title}
	  </Link>
        </li>
        )
        })}
      </ul>
      <Link to="/tags">All tags</Link>
    </Layout>
  )
}

export const pageQuery = graphql`
  query ($tag: String) {
    allMdx(
      limit: 1000
      sort: {frontmatter: {date: DESC}}
      filter: {frontmatter: {tags: {in: [$tag]}}}
    ) {
      edges {
	node {
          frontmatter {
	    title
	    date(formatString: "MMMM D, YYYY")
	    tags
            slug
          }
	  id
	  excerpt
	}
      }
      totalCount
    }
  }
`

export const Head = () => <Seo />

export default Tags

テンプレートを使用するためにgatsby-node.jsを修正する

gatsby-node.jsを下記のように変更します。タグ名をケバブケースに統一するためlodashライブラリを使用します。またブログポスト一覧とタグ一覧を取得するために、どちらもallMdxを使用するため、それぞれindexRemarkとtagsGroupと名前を付けて使い分けます。

const path = require(`path`)
const { paginate } = require(`gatsby-awesome-pagination`)
const _ = require(`lodash`)

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions
  
  const result = await graphql(`
    {
    indexRemark: allMdx(
    sort: {frontmatter: {date: DESC}},
    limit: 1000
    ) {
        edges {
          node {
            frontmatter {
              slug
              tags
            }
          }
        }
      }
    tagsGroup: allMdx(limit: 1000) {
        group(field: {frontmatter: {tags: SELECT}}) {
          fieldValue
        }
      }
    }
  `)

  if (result.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`)
     return
  }

  const indexTemplate = path.resolve("src/templates/blog.js")
  const index = result.data.indexRemark.edges

  paginate({
    createPage,
    items: index, 
    itemsPerPage: 2,
    pathPrefix: "/blog",
    component: indexTemplate,
  })

  const tagTemplate = path.resolve("src/templates/tags.js")
  const tags = result.data.tagsGroup.group

  if (tags.length > 0) {
    tags.forEach(tag => {
      createPage({
	path: `/tag/${_.kebabCase(tag.fieldValue)}/`,
	component: tagTemplate,
	context: {
          tag: tag.fieldValue,
	},
      })
    })
  }
}

タグリストのページを作成する

タグの一覧を表示するページを作成します。

src/pages/tags.js

import * as React from 'react'
import { Link, graphql } from 'gatsby'
import kebabCase from 'lodash/kebabCase'
import Layout from '../components/layout'
import { linkText,heading } from './tags.module.css'
import Seo from '../components/seo'

const TagsPage = ({
  data: {
    allMdx: { group },
    site: {
      siteMetadata: { title },
    },
  },
}) => (
  <Layout>
    <h1 className={heading}>Tags</h1>
    <ul>
      {group.map(tag => (
        <li key={tag.fieldValue}>
          <Link to={`/tag/${kebabCase(tag.fieldValue)}/`} className={linkText}>
            {tag.fieldValue} ({tag.totalCount})
          </Link>
        </li>
      ))}
    </ul>
  </Layout>
)

export const pageQuery = graphql`
  query {
    site {
      siteMetadata {
        title
      }
    }
    allMdx(limit: 1000) {
      group(field: { frontmatter: { tags: SELECT }}) {
        fieldValue
        totalCount
      }
    }
  }
`

export const Head = () => <Seo title="Tags" />

export default TagsPage

これでタグ一覧のページが作成できました。

gatsby-static-site-tutorial10-02

タグを選択するとそのタグが含まれたブログポストの一覧が表示されます。

gatsby-static-site-tutorial10-03

ブログリストにタグを表示する

ブログページにタグを表示してリンクをつけます。下記のようにして日付の横にタグが表示されるようにしてみます。

import * as React from 'react'
import { Link, graphql } from 'gatsby'
import { GatsbyImage, getImage } from 'gatsby-plugin-image'
import Layout from '../components/layout'
import Seo from '../components/seo'
import Pager from '../components/pager'
import kebabCase from 'lodash/kebabCase'

const BlogPage = ({ data, pageContext }) => {
  return (
    <Layout pageTitle="Blog">
      {
	data.allMdx.nodes.map((node) => (
	  <article key={node.id}>
            <h2>
	      <Link to={`/blog/${node.frontmatter.slug}`}>{node.frontmatter.title}</Link>
	    </h2>
	    <Link to={`/blog/${node.frontmatter.slug}`}>
	      <GatsbyImage
		image={getImage(node.frontmatter.hero_image)}
		      alt={node.frontmatter.hero_image_alt}
	      />
	    </Link>
	    <span>Posted: {node.frontmatter.date} </span>
	    <span>
	      Tags:
	      {node.frontmatter.tags.map(
		(tag) => tag && (
		  <Link
		    to={`/tag/${kebabCase(tag)}`}>#{tag}
		  </Link>
		)
	      )}
	    </span>
	    <p>{node.excerpt}</p>
	  </article>
	))
      }
      <Pager pageContext={pageContext} />
    </Layout>
  )
}

export const query = graphql`
  query($skip: Int!, $limit: Int!) {
    allMdx(
      sort: { frontmatter: { date: DESC } }
      skip: $skip
      limit: $limit
    ) {
      nodes {
        frontmatter {
	  title
          date(formatString: "MMMM D, YYYY")
	  slug
	  tags
	  hero_image_alt
	  hero_image {
	    childImageSharp {
	      gatsbyImageData
	    }
	  }
        }
        id
        excerpt
      }
    }
  }
`

export const Head = () => <Seo title="Blog" />

export default BlogPage

kebabCaseを読みこみ、クエリにtagsを追加しています。表示を確認します。

gatsby-static-site-tutorial10-04

これでブログリストにタグを追加できました。今回は以上です。


< Previous ArticleNext Article >
Back to Articles
©2025 W.D.Sphere All Rights Reserved.