😸
Gatsby+Contentfulでタグ一覧ページを作成する
Contentfulのタグ機能
Contentfulで記事にタグをつけるためにはタグのContent modelを作成し、記事に紐付ける作業が必要だったのですが、
2021年3月にContentfulでタグ機能がリリースされました🎉
今回はこちらのタグ機能を用いて、記事にタグを付け、それをGraphQLで取得、記事一覧ページ作成までを行なっていきたいと思います。
記事にタグをつける
Contentfulで記事にタグを付けるのは簡単で、記事編集ページのTags
タブを選択すると、そこからタグの作成、紐付けを行うことができます。
一点注意が必要なのが、タグを作成する際、Tag visibility
オプションでPrivate
かPublic
かを選択できるのですが、Private
を選択すると、GraphQLからの取得ができません。
サイトに表示させるタグの場合は、Public
を選択するようにしましょう。
GraphQLで記事に紐付いたタグ情報を取得する
GatsbyからGraphQLを用いてタグ情報を取得します。
そのためにgatsby-source-contentful
モジュールを使います。
$ npm install gatsby-source-contentful
そしてgatsby-config.js
にて設定を行います。
gatsby-config.js
{
resolve: `gatsby-source-contentful`,
options: {
spaceId: process.env.GATSBY_CONTENTFUL_SPACE_ID,
accessToken: process.env.GATSBY_CONTENTFUL_API_KEY,
enableTags: true,
}
},
タグ情報を取得するにはenableTags
のオプションをtrue
にする必要があるので、注意してください。
例えば、以下のようなクエリで「記事情報」+「記事に紐付くタグ」を取得することができます。
query allContentfulArticles {
allContentfulArticles(sort: {fields: createdAt, order: DESC}) {
edges {
node {
id
title
metadata {
tags {
contentful_id
name
}
}
createdAt(locale: "ja-JP", formatString: "YYYY年MM月DD日")
}
}
}
}
タグ一覧ページを作成する
実際にGatsbyでタグ一覧ページを作成してみたいと思います。
build時に生成するので、gatsby-node.js
に記載します。
gatsby-node.js
const path = require("path")
exports.createPages = async({ graphql, actions, reporter}) => {
const { createPage } = actions
const result = await graphql(`
{
allContentfulArticles(sort: {fields: createdAt, order: DESC}) {
edges {
node {
id
title
description {
description
}
thumbnail {
file {
url
}
}
body {
childMarkdownRemark {
html
}
}
createdAt(locale: "ja-JP", formatString: "YYYY年MM月DD日")
metadata {
tags {
contentful_id
name
}
}
}
}
}
}
`)
if (result.errors) {
reporter.panicOnBuild(`Error while runnning GraphQL query.`)
return
}
const { edges } = result.data.allContentfulArticles
const articlesByTag = {}
edges.forEach(edge => {
// 記事ページ生成
createPage({
path: `/articles/${edge.node.id}/`,
component: path.resolve("./src/templates/article.js"),
context: { article: edge.node }
})
// タグに紐付く記事のオブジェクトを作成
edge.node.metadata.tags.forEach((tag) => {
if (tag.contentful_id in articlesByTag) {
articlesByTag[tag.contentful_id].contents.push(edge.node)
} else {
articlesByTag[tag.contentful_id] = {
name: tag.name,
contents: [edge.node]
}
}
})
})
// タグページの生成
Object.keys(articlesByTag).forEach((tagId) => {
createPage({
path: `/tags/${tagId}`,
component: path.resolve("./src/templates/article-list-by-tag.js"),
context: {
name: articlesByTag[tagId].name,
contents: articlesByTag[tagId].contents,
}
})
})
}
なんかもっと上手い方法がありそうですが、とりあえずこれでタグ一覧ページを作成することができました。
Discussion