https://www.gatsbyjs.com/starters/gatsbyjs/gatsby-starter-blog/
こちらをスターターとして使いましたが、タグの機能がありません。
記事にタグをつけて、タグリストのページを作ります。
(この記事は公式の日本語訳です)
post に tags を追加する
配列でタグを追加します。
---
title: 'Gatsby にタグ機能を追加する'
published: '2020-09-19'
draft: false
tags: ['Gatsby', 'タグ', 'tag']
---
...
サーバを再起動して、フィールドを追加できるようにします。
クエリを追加して、タグを取得します
GraphiQL で、以下のクエリが通ることを確認します。
GraphiQL
{
allMarkdownRemark {
group(field: frontmatter___tags) {
tag: fieldValue
totalCount
}
}
}
タグページテンプレートを作成します(/tags/{tag})
タグページテンプレートを作成して、そのあと gatsby-node.js 内で createPages して使います。
src/templates/tags.js
import React from "react"
// Components
import { Link, graphql } from "gatsby"
const Tags = ({ pageContext, data }) => {
const { tag } = pageContext
const { edges, totalCount } = data.allMarkdownRemark
const tagHeader = `${totalCount} post${
totalCount === 1 ? "" : "s"
} tagged with "${tag}"`
return (
<div>
<h1>{tagHeader}</h1>
<ul>
{edges.map(({ node }) => {
const { slug } = node.fields
const { title } = node.frontmatter
return (
<li key={slug}>
<Link to={slug}>{title}</Link>
</li>
)
})}
</ul>
{/*
This links to a page that does not yet exist.
You'll come back to it!
*/}
<Link to="/tags">All tags</Link>
</div>
)
}
export default Tags
export const pageQuery = graphql`
query($tag: String) {
allMarkdownRemark(
limit: 2000
sort: { fields: [frontmatter___date], order: DESC }
filter: { frontmatter: { tags: { in: [$tag] } } }
) {
totalCount
edges {
node {
fields {
slug
}
frontmatter {
title
}
}
}
}
}
`
gatsby-node.js でテンプレートを使ったレンダリングを追加する
gatsby-node.js
const path = require('path')
const _ = require('lodash')
exports.createPages = async ({ actions, graphql, reporter }) => {
const { createPage } = actions
const blogPostTemplate = path.resolve('src/templates/blog.js')
const tagTemplate = path.resolve('src/templates/tags.js')
const result = await graphql(`
{
postsRemark: allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
limit: 2000
) {
edges {
node {
fields {
slug
}
frontmatter {
tags
}
}
}
}
tagsGroup: allMarkdownRemark(limit: 2000) {
group(field: frontmatter___tags) {
fieldValue
}
}
}
`)
// handle errors
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`)
return
}
const posts = result.data.postsRemark.edges
// Create post detail pages
posts.forEach(({ node }) => {
createPage({
path: node.fields.slug,
component: blogPostTemplate,
})
})
// Extract tag data from query
const tags = result.data.tagsGroup.group
// Make tag pages
tags.forEach(tag => {
createPage({
path: `/tags/${_.kebabCase(tag.fieldValue)}/`,
component: tagTemplate,
context: {
tag: tag.fieldValue,
},
})
})
}
全ての記事にある全タグをリストアップするページを作る
src/pages/tags.js
import React from "react"
// Utilities
import kebabCase from "lodash/kebabCase"
// Components
import { Helmet } from "react-helmet"
import { Link, graphql } from "gatsby"
const TagsPage = ({
data: {
allMarkdownRemark: { group },
site: {
siteMetadata: { title },
},
},
}) => (
<div>
<Helmet title={title} />
<div>
<h1>Tags</h1>
<ul>
{group.map(tag => (
<li key={tag.fieldValue}>
<Link to={`/tags/${kebabCase(tag.fieldValue)}/`}>
{tag.fieldValue} ({tag.totalCount})
</Link>
</li>
))}
</ul>
</div>
</div>
)
export default TagsPage
export const pageQuery = graphql`
query {
site {
siteMetadata {
title
}
}
allMarkdownRemark(limit: 2000) {
group(field: frontmatter___tags) {
fieldValue
totalCount
}
}
}
`
これでタグを取得したページができました。タグ一覧からどれかクリックして、タグに該当する記事が選択されていれば出来上がり。
記事にタグをつける
せっかくなので、個別の記事にタグをつけてみましょう。
といっても、クエリに tags を追加して、呼び出すだけです。
例)
src\templates\blog-post.js
...
import Tag from '../components/tag'
...
<header>
<div className="postdate">{post.frontmatter.date}</div>
<h1 itemProp="headline" className="posttitle">
{post.frontmatter.title}
</h1>
<Tag tags={post.frontmatter.tags} /> ←ココ
</header>
...
export const pageQuery = graphql`
query BlogPostBySlug($slug: String!) {
site {
siteMetadata {
title
}
}
markdownRemark(fields: { slug: { eq: $slug } }) {
id
excerpt(pruneLength: 160)
html
tableOfContents
frontmatter {
title
date(formatString: "YYYY/MM/DD")
description
tags ←ココ
}
}
}
`
...
src\components\tag.js
import React from 'react'
import { Link } from 'gatsby'
import _ from 'lodash'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faTag } from '@fortawesome/free-solid-svg-icons'
const Tag = props => {
library.add(faTag)
return (
<div className={props.index ? 'tag-index' : 'tag'}>
{props.tags.map((tag, index) => {
return (
<Link
to={`/tags/${_.kebabCase(tag)}/`}
key={index}
className={props.index ? 'tag__listindex' : 'tag__list'}
>
<FontAwesomeIcon icon={faTag} />
{tag}
</Link>
)
})}
</div>
)
}
export default Tag
tag.js は、index ページと各ポストで共有しています。
ソースが長くなると見通し悪くなってなんだか辛いので。
次回は tag.js で使用した FontAwesome について。
参考
https://www.gatsbyjs.com/docs/adding-tags-and-categories-to-blog-posts/#reach-skip-nav 、