マークダウンに記事を書いている前提で、カテゴリページを導入したいと思ったのでメモです。手順は以下の通りです。
- マークダウン記事に category を追加
- /category/*** ページとなるテンプレート作成
- gatsby-node.js でページ生成
実際の手順は以下です。
マークダウン記事に category を追加
---
title: Gatsby.jsサイトにCategoryページを導入する
date: 2020-11-01 00:00:00 -0900
category: tech
tags: [gatsbyjs]
---
# 以下記事本文
tech
というカテゴリを追加したいとします。上記のようにcategory: tech
の 1 行を追加しました。
移行、マークダウンの記事にカテゴリを追加したい場合はこのように記載していきます。
テンプレートの作成
# /src/templates/category.js
import React from 'react'
import { graphql } from 'gatsby'
import Layout from '../components/layout'
import PostCard from '../components/postCard'
const Category = ({ pageContext, data }) => {
const { category } = pageContext
const { edges, totalCount } = data.allMarkdownRemark
const catHeader = `「${category}」カテゴリの記事(${totalCount}件)`
return (
<Layout>
<div className="md:flex">
<div className="w-full md:w-3/4">
<h1 className="pl-3 md:pl-0 text-lg mb-6">{catHeader}</h1>
<div className="">
{edges.map(({ node }) => {
return <PostCard node={node} />
})}
</div>
</div>
</div>
</Layout>
)
}
export default Category
export const pageQuery = graphql`
query($category: String) {
allMarkdownRemark(
limit: 2000
sort: { fields: [frontmatter___date], order: DESC }
filter: { frontmatter: { category: { eq: $category } } }
) {
totalCount
edges {
node {
excerpt(pruneLength: 100)
fields {
slug
}
timeToRead
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
category
}
}
}
}
}
`
pageContext
はこの後、gatsby-node.js
から引数として渡されます。
また、graphql の中の$category
も同様に gatsby-node.js から渡されてくる引数です。
PostCard
コンポーネントは各自node
配下のデータを渡してコンポーネントを作成しているだけです。
gatsby-node.js でページ生成
最後に gatsby-node.js 側でカテゴリページを生成します。
# gatsby-node.js
const path = require(`path`)
const _ = require('lodash')
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const blogPost = path.resolve(`./src/templates/blog-post.js`) //こちらは個別記事を生成する部分で今回無関係
const catTemplate = path.resolve(`./src/templates/category.js`) //ここで先ほど作ったテンプレートを読み込む
return graphql(
`
{
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
limit: 1000
) {
edges {
node {
fields {
slug
}
frontmatter {
title
category // categoryを追加
}
}
}
}
}
`
).then(result => {
if (result.errors) {
throw result.errors
}
// Create blog posts pages. 個別記事生成 今回無関係
const posts = result.data.allMarkdownRemark.edges
posts.forEach((post, index) => {
const previous = index === posts.length - 1 ? null : posts[index + 1].node
const next = index === 0 ? null : posts[index - 1].node
createPage({
path: post.node.fields.slug,
component: blogPost,
context: {
slug: post.node.fields.slug,
previous,
next,
},
})
})
// Create blog post list pages 記事リスト生成 今回無関係
const postsPerPage = 6
const numPages = Math.ceil(posts.length / postsPerPage)
Array.from({ length: numPages }).forEach((_, i) => {
createPage({
path: i === 0 ? `/` : `/${i + 1}`,
component: path.resolve('./src/templates/blog-list.js'),
context: {
limit: postsPerPage,
skip: i * postsPerPage,
numPages,
currentPage: i + 1,
},
})
})
// この部分を今回追加
// create Category pages
let categories = []
_.each(posts, edge => {
if (_.get(edge, 'node.frontmatter.category')) {
categories.push(edge.node.frontmatter.category)
}
})
// Eliminate duplicate categorya
categories = _.uniq(categories)
// Make category pages
categories.forEach(category => {
createPage({
path: `/category/${_.kebabCase(category)}/`,
component: catTemplate,
context: {
category,
},
})
})
// 今回追加ここまで
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
これで/category/tech
配下にカテゴリに属する記事一覧のページが生成されているはずです。
以上
Tag 機能は元々いろんなスターターに組み込まれていましたが、カテゴリはパッと見つからなかったのでまとめてみました。
誰かの参考になれば幸いです。