😸

Gatsby+Contentfulでタグ一覧ページを作成する

2022/01/26に公開

Contentfulのタグ機能

Contentfulで記事にタグをつけるためにはタグのContent modelを作成し、記事に紐付ける作業が必要だったのですが、
2021年3月にContentfulでタグ機能がリリースされました🎉
今回はこちらのタグ機能を用いて、記事にタグを付け、それをGraphQLで取得、記事一覧ページ作成までを行なっていきたいと思います。

記事にタグをつける

Contentfulで記事にタグを付けるのは簡単で、記事編集ページのTagsタブを選択すると、そこからタグの作成、紐付けを行うことができます。
一点注意が必要なのが、タグを作成する際、Tag visibilityオプションでPrivatePublicかを選択できるのですが、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