はじめに
公式サイトにあるCreating Tags Pages for Blog Postsを参考にしながら、このブログにある記事をカテゴライズしていく。このブログはgatsby-starter-blog
ベースなので、公式のコードをいくつか修正する必要があった。
カテゴライズでやりたいことは3つある。
- カテゴリ毎の記事一覧ページを作成する(=タグページ
/tags/tag
) - カテゴリページを作成する(=タグインデックスページ
/tags
) - 記事にタグを載せる、タグとタグページをリングさせる
以下の手順でやってく。
- 記事にタグを追加
- タグ収集クエリを作成
- タグページのテンプレートを作成
- テンプレートからタグページを生成
- タグインデックスページを生成
- 記事一覧ページにタグを表示
1. 記事にタグを追加
各記事にtags:["xxx"]
を追加、“xxx”がカテゴリーとなる。
いくつかの記事にgatsby
,misc
,imgui
をとりあえず追加。
---
title: Gatsbyブログ その6 カテゴライズ1
date: "2021-07-22T19:46:00"
tags: ["gatsby"] //ここ追加
description: Gatsbyブログ その6 タグを使ってカテゴリページをつくる
---
2. タグ収集クエリを作成
GraphQLで全記事のタグ情報を収集するクエリを作成する。
{
allMarkdownRemark {
group(field: frontmatter___tags) {
tag: fieldValue
totalCount
}
}
}
以下実行結果。
tag
はカテゴリ名、totalCount
はカテゴリ毎の記事数となる。
{
"data": {
"allMarkdownRemark": {
"group": [
{
"tag": "gatsby",
"totalCount": 6
},
{
"tag": "imgui",
"totalCount": 1
},
{
"tag": "misc",
"totalCount": 1
}
]
}
},
"extensions": {}
}
3. タグページテンプレートを作成
タグページテンプレートはtags/[tag]
のページを作成するためのテンプレート。
公式にあるコードをsrc/templates/tags.js
としてコピーする。
なにもかえない。
import React from "react"
import PropTypes from "prop-types"
// 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>
)
}
Tags.propTypes = {
pageContext: PropTypes.shape({
tag: PropTypes.string.isRequired,
}),
data: PropTypes.shape({
allMarkdownRemark: PropTypes.shape({
totalCount: PropTypes.number.isRequired,
edges: PropTypes.arrayOf(
PropTypes.shape({
node: PropTypes.shape({
frontmatter: PropTypes.shape({
title: PropTypes.string.isRequired,
}),
fields: PropTypes.shape({
slug: PropTypes.string.isRequired,
}),
}),
}).isRequired
),
}),
}),
}
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
}
}
}
}
}
`
4. テンプレートからタグページを生成
gatsby-node.js
を修正し、テンプレートから具体的なタグページを生成する。
公式のコードを参考に一部修正した。
graphqlでタグ情報を取得、タグ数分createPage
を生成しているところが大事。
const path = require(`path`)
const _ = require("lodash")
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
// Define a template for blog post
const blogPost = path.resolve(`./src/templates/blog-post.js`)
// Get all markdown blog posts sorted by date
const result = await graphql(
`
{
postsRemark: allMarkdownRemark(
sort: { fields: [frontmatter___date], order: ASC }
limit: 1000
) {
nodes {
id
fields {
slug
}
frontmatter {
tags
}
}
}
tagsGroup: allMarkdownRemark(limit: 2000) {
group(field: frontmatter___tags) {
fieldValue
}
}
}
`
)
if (result.errors) {
reporter.panicOnBuild(
`There was an error loading your blog posts`,
result.errors
)
return
}
const posts = result.data.postsRemark.nodes
// Create blog posts pages
// But only if there's at least one markdown file found at "content/blog" (defined in gatsby-config.js)
// `context` is available in the template as a prop and as a variable in GraphQL
if (posts.length > 0) {
posts.forEach((post, index) => {
const previousPostId = index === 0 ? null : posts[index - 1].id
const nextPostId = index === posts.length - 1 ? null : posts[index + 1].id
createPage({
path: post.fields.slug,
component: blogPost,
context: {
id: post.id,
previousPostId,
nextPostId,
},
})
})
}
// Extract tag data from query
const tagTemplate = path.resolve("./src/templates/tags.js")
const tags = result.data.tagsGroup.group
// Make tag pages
tags.forEach(tag => {
createPage({
path: `/tags/${_.kebabCase(tag.fieldValue)}/`,
component: tagTemplate,
context: {
tag: tag.fieldValue,
},
})
})
}
5. タグインデックスページを作成
タグインデックスページ/tags
を作成する。
公式にあるコードをsrc/pages/tags.js
としてコピーする。
そのまんま。
import React from "react"
import PropTypes from "prop-types"
// 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>
)
TagsPage.propTypes = {
data: PropTypes.shape({
allMarkdownRemark: PropTypes.shape({
group: PropTypes.arrayOf(
PropTypes.shape({
fieldValue: PropTypes.string.isRequired,
totalCount: PropTypes.number.isRequired,
}).isRequired
),
}),
site: PropTypes.shape({
siteMetadata: PropTypes.shape({
title: PropTypes.string.isRequired,
}),
}),
}),
}
export default TagsPage
export const pageQuery = graphql`
query {
site {
siteMetadata {
title
}
}
allMarkdownRemark(limit: 2000) {
group(field: frontmatter___tags) {
fieldValue
totalCount
}
}
}
`
この時点で/tags/gatsby
にアクセスするとgatsby
タグのある記事一覧を確認できる。
/tags/
にアクセスするとタグインデックスページを確認できる。
6. 記事一覧ページにタグを表示
記事にタグを載せて、タグページとリンクさせる。
記事一覧ページのpages/index.js
を修正していく。
まず、graphqlのfrontmatter
にtags
を追加し、タグ情報を扱えるようにする。
allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
nodes {
excerpt
fields {
slug
}
frontmatter {
date(formatString: "MMMM DD, YYYY")
title
tags //ここ追加
description
}
}
}
タグを表示したい箇所にTags
コンポーネントをおく。
import Tags from "../components/tags"
をインポートしておくこと。
コンポーネントの詳細はこの後でやる。
<header>
<h2>
<Link to={post.fields.slug} itemProp="url">
<span itemProp="headline">
<FontAwesomeIcon icon={faPenSquare} />
{title}
</span>
</Link>
</h2>
<small>{post.frontmatter.date}</small>
<Tags>{tags}</Tags> //ここ追加
</header>
コンポーネント/tags/components/tags.js
を作成
こちらのサイトhttps://dev.to/gabcimato/how-to-add-tags-to-your-gatsby-blog-part-1-34fk を参考にさせていただいた。
以下詳細。
import * as React from "react"
import { Link } from "gatsby"
const Tags = ({ children }) => {
return children && (
<ul style={{ marginBottom: 0, marginLeft: 10, display: "inline-flex" }}>
{children.map(tag => (
<Link to={`/tags/${tag}/`}>
<li
key={tag}
style={{
borderRadius: `4px`,
padding: `1px 4px`,
marginRight: `5px`,
fontSize: `80%`,
backgroundColor: "#005b99",
color: "white",
listStyle: "none",
}}
>
#{tag}
</li>
</Link>
))}
</ul>
)
}
export default Tags
これでタグの表示とタグページへのリンクができた。
個々の記事についても同様に、Tagsコンポーネントを埋め込むだけで表示できる。