導入
今回は Gatsby.js で作ったブログにタグ機能を追加する手法を紹介します。
記事にタグをつけることで、関連するワードの記事を一目で確認できるため、ぜひ追加したい機能です。
Gatsby Starter Blogをテンプレートとして使い、これにタグ機能を追加します。
ファビコンや記事投稿表示、フォントの変更などの方法は前回の記事で紹介したため、気になる方は確認していただけると嬉しいです。
スポンサードリンク
タグ機能の実装
タグ機能の追加は公式も手順を出しています。(ただし英語です)
https://www.gatsbyjs.com/docs/adding-tags-and-categories-to-blog-posts/
この記事では、日本語ユーザー向けに修正を加え、手順を紹介します。
まず、ブログの投稿一覧ページとブログの各記事にタグを追加します。
Gatsby.js の内部では GraphQL を用いて markdown から必要な情報を取得し、html に変換します。
タグを追加したい記事の markdown の先頭に以下 のように tags の情報を追加します。
---title: Gatsby.jsで作ったブログをカスタマイズする1(ファビコン・記事投稿表示・フォントの変更)date: "2022-02-06T22:12+09:00"tags: ["ブログ開発", "Gatsby.js"]---
この書き方は Frontmatter と呼ばれる markdown にメタ情報を埋め込むための形式で、Jekyll が始まりのようです。
(*参考 https://jekyllrb.com/docs/front-matter/)
次に、gatsby-node.js の type Frontmatter の部分に、以下のように tags の型を設定します。
type Frontmatter { title: String description: String date: Date @dateformat tags: [String!] // 追加}
これは null でない String 型の配列(配列自体が null であってもよい)を意味します。
これを追加しないとエラーが出ます。
続いて、src/pages/index.js や src/templates/blog-post.js の pageQuery で tags を追加します。
これで、各ページの tags のデータを取得できるようになります。
export const pageQuery = graphql` query { site { siteMetadata { title } } allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) { nodes { excerpt fields { slug } frontmatter { date title description tags // 追加 } } } }
最後に、graphQL で取得したデータを表示します。
const tags = post.frontmatter.tags
<p>{moment(post.frontmatter.date).format(`YYYY年MM月DD日 HH:mm`)}</p><div className="tags-article"> {tags && tags.length > 0 && tags.map(tag => { return ( <button>{tag}</button> ) })}</div>
スポンサードリンク
タグページの追加
次に、各タグをクリックしたときにそのタグが付いてるページ一覧を表示できるようにします。
まず、gatsby-node.js を編集し、各タグの記事一覧ページを生成します。
URL をケバブケースにするために lodash をインポートします。
ケバブケースとはハイフン(-)で単語を区切ることを言うそうです。
const _ = require("lodash")
そして、tags.js という各タグの記事一覧ページのテンプレートを定義します。
const blogPost = path.resolve(`./src/templates/blog-post.js`)const tagTemplate = path.resolve("src/templates/tags.js") // 追加
そして、情報を取得する一覧の GraphQL を以下のように変更します。
const result = await graphql( ` { postsRemark: allMarkdownRemark( sort: { fields: [frontmatter___date], order: ASC } limit: 2000 ) { nodes { id fields { slug } frontmatter { tags } } } tagsGroup: allMarkdownRemark(limit: 2000) { group(field: frontmatter___tags) { fieldValue } } } `)
全ページの投稿情報を以下のように変更し、
const posts = result.data.postsRemark.nodes
各タグのページを作成してこのステップは完了です。
これで、/tags/{タグ名}でそのタグが付いた記事の一覧ページが作成されます。
const tags = result.data.tagsGroup.groupif (tags.length > 0) { tags.forEach(tag => { createPage({ path: `/tags/${_.kebabCase(tag.fieldValue)}/`, component: tagTemplate, context: { tag: tag.fieldValue, }, }) })}
次に、先ほど tagTemplate
として読み込んだタグページのテンプレートを追加します。
src/templates/tags.js を作成し、以下のように記述します。
import React from "react"import { Link, graphql } from "gatsby"import moment from "moment"import kebabCase from "lodash/kebabCase"
import Layout from "../components/layout"import Seo from "../components/seo"
const Tags = ({ data, pageContext, location }) => { const siteTitle = data.site.siteMetadata?.title || `Title` const { totalCount } = data.allMarkdownRemark const posts = data.allMarkdownRemark.nodes const { tag } = pageContext
if (posts.length === 0) { return ( <Layout location={location} title={siteTitle}> <Seo title={`タグ: "${tag}" (0記事)`} /> <p>該当するタグの投稿記事がありません。</p> </Layout> ) }
const tagHeader = `タグ: "${tag}" (${totalCount}記事)` return ( <Layout location={location} title={siteTitle}> <Seo title={tagHeader} /> <h1>{tagHeader}</h1> <ol style={{ listStyle: `none` }}> {posts.map(post => { const title = post.frontmatter.title || post.fields.slug const tags = post.frontmatter.tags
return ( <li key={post.fields.slug}> <article className="post-list-item" itemScope itemType="http://schema.org/Article" > <header> <h2> <Link to={post.fields.slug} itemProp="url"> <span itemProp="headline">{title}</span> </Link> </h2> <small> {moment(post.frontmatter.date).format( `YYYY年MM月DD日 HH:mm` )} </small> <div className="tags-index"> {tags && tags.length > 0 && tags.map(tag => { return ( <Link to={`/tags/${kebabCase(tag)}/`} itemProp="url"> <button>{tag}</button> </Link> ) })} </div> </header> <section> <p dangerouslySetInnerHTML={{ __html: post.frontmatter.description || post.excerpt, }} itemProp="description" /> </section> </article> </li> ) })} </ol> </Layout> )}
export default Tags
export const pageQuery = graphql` query ($tag: String) { site { siteMetadata { title } } allMarkdownRemark( limit: 2000 sort: { fields: [frontmatter___date], order: DESC } filter: { frontmatter: { tags: { in: [$tag] } } } ) { totalCount nodes { excerpt fields { slug } frontmatter { date title description tags } } } }`
タグへのリンクの追加
最後に、各タグをクリックするとそのタグの記事一覧ページに飛ぶようにします。
リンクの追加は簡単で、<button>
タグで表現していたタグを以下のように<Link>
タグでリンク先の URL とともに囲うだけです。
これを src/pages/index.js と src/templates/tags.js、src/templates/tags.js で行います。
<Link to={`/tags/${kebabCase(tag)}/`} itemProp="url"> <button>{tag}</button></Link>
kebabCase
を使うために、あらかじめインポートするのを忘れないようにしてください。
import kebabCase from "lodash/kebabCase"
スポンサードリンク
終わりに
今回はブログには欠かせないタグ機能を追加しました。
次回は、Gatsby.js の SEO 対策を紹介する予定です。