microCMSとNext.jsによるカテゴリー絞り込み

komosyu
Next.js

目次

  1. はじめに
  2. microCMS でのデータ取得
  3. 特定のカテゴリーの取得方法は?
  4. 参考
  5. さいごに

はじめに

Next.js で microCMS を使ってのメディアサイトをつくっていて、カテゴリー絞り込みがうまいことつくれなかったのですが、なんとか解決できたのでその方法を共有していきたいと思います!

というか、ちゃんと見ればドキュメントに書いてあった内容なのですけれども…

microCMS でのデータ取得

まず、microCMS での基礎的なデータ取得の方法から見ていきましょう!

/lib/microcms/apisみたいなディレクトリをつくって、そこであらかじめ microCMS の管理画面で作成したデータを取得できるようにしておきます。

import { createClient } from 'microcms-js-sdk'

export const client = createClient({
  serviceDomain: process.env.NEXT_PUBLIC_MICROCMS_SERVICE_DOMAIN ?? '',
  apiKey: process.env.NEXT_PUBLIC_MICROCMS_API_KEY ?? '',
})

そしたら、今度はデータ取得のたびに使いまわせるスニペットをつくっておきましょう!

/lib/microcms/getDataみたいな感じで、先ほど作成しておいたclientを使ってデータを取得していきます。
contentIdは microCMS の方で設定しておいたエンドポイントの値を引数として受け入れられるようにしておきます。

import { client } from '../apis'

export const getMicroCMSData = async (contentId: string) => {
  const res = await client.getList({
    endpoint: contentId,
    queries: {
      limit: 100,
    },
  })
  return res
}

使う側はこんな感じです。

import { getMicroCMSData } from '@/lib/microcms/getData'

const contentsData = await getMicroCMSData('contents')

こうしておくことで楽に microCMS 側のデータを取得できるようになりました!

特定のカテゴリーの取得方法は?

基本的なデータ取得までの流れを抑えたところで、私が個人的につまづいたカテゴリー取得の方法について書いていきたい思います!

microCMS にはコンテンツ API というものが用意されており、先ほど/lib/microcms/getDataで行っていたデータ取得の段階でfieldsを使うことで、カテゴリーの絞り込みができるかな?という想像はついていました。

特に絞り込みしないままのデータを取得してみると…

const contentsData = await getMicroCMSData('contents')
const { contents } = contentsData
console.log(contents)

こんな感じのデータ構造になるので、

;[
  {
    id: '6q8dn2ukfqf',
    createdAt: '2023-02-10T01:55:05.898Z',
    updatedAt: '2023-03-14T11:32:57.703Z',
    publishedAt: '2023-02-10T01:55:05.898Z',
    revisedAt: '2023-03-14T11:32:57.703Z',
    thumbnail: {
      url: 'https://images.microcms-assets.io/assets/0bd1a06d39e7436b8db3dc48d6393b23/35ce316d410a4ee180aa3cb9a973a3f0/_MG_7462.jpg',
      height: 1539,
      width: 2048,
    },
    title: 'ここにタイトルが入ります',
    category: {
      id: 'i56rpuuc1',
      createdAt: '2023-02-12T10:35:02.064Z',
      updatedAt: '2023-03-04T11:33:59.051Z',
      publishedAt: '2023-02-12T10:35:02.064Z',
      revisedAt: '2023-03-04T11:33:59.051Z',
      japanese: 'プログラミング',
      english: 'programing',
    },
  },
]

この中で例えばcategory.englishprogramingという文字列と一致すれば、そのカテゴリーを持つデータのみに絞り込めるかな?と思いこんな感じのコードを書いてみました。
指定に一致したコンテンツを取得するには[equals]を使います。

export async function getMicroCMSCategoryData(
  contentId,
  offsetNumber = 0,
  limitNumber = 100,
  categoryId?
) {
  const res = await client.getList({
    endpoint: contentId,
    queries: {
      offset: offsetNumber,
      limit: limitNumber,
      filters: categoryId ? `category.english[equals]${categoryId}` : '',
    },
  })
  return res
}

使う側はこうします。

const contentsData = await getMicroCMSDataList(
  'contents',
  (currentNumber - 1) * 10,
  10,
  'programing' // カテゴリー名
)

といった感じでやってみると、category.englishprogramingだし、引数に指定したcategoryIdprogramingなので、いけそうな感じがしたのですが全然ダメでした。

しかし、ドキュメントをよく読んでみるとこう書いてあります。絞り込みの条件には、コンテンツIDを使用してください。その他の値は利用できません。
そのまんまですね w

これは典型的なドキュメントを読めていない人だったので、今度からドキュメントをきちんと読み込もうと思いました…

それでは、正しい絞り込みの実装方法を書いてみましょう!

export async function getMicroCMSCategoryData(
  contentId,
  offsetNumber = 0,
  limitNumber = 100,
  categoryId?
) {
  const res = await client.getList({
    endpoint: contentId,
    queries: {
      offset: offsetNumber,
      limit: limitNumber,
      filters: categoryId ? `category[equals]${categoryId}` : '',
    },
  })
  return res
}

といった感じで、filtersの中でcategoryに対してカテゴリー名ではなくカテゴリーの持つ id を当ててあげることで、取得したいカテゴリーのみに絞り込んでデータを取得することができます!

なので、取得する側はこんな感じになりました。

const contentsData = await getMicroCMSDataList(
  'contents',
  (currentNumber - 1) * 10,
  10,
  'i56rpuuc1' // カテゴリーid
)

これで取得したかったprogramingというカテゴリーを持つコンテンツに絞って取得することができました!

参考

  • (microCMS コンテンツ API)[https://document.microcms.io/content-api/get-list-contents]
  • (MicroCMS で記事の絞り込みを行う)[https://www.tyai-a.com/posts/microcms-filter-posts]

さいごに

これはもうドキュメントをよく見ましょうね。ということに尽きますね…
うまくいかないな?と思った時こそ、何度もドキュメントを読み返すというのが大切だなと。改めて痛感しました。

また、カテゴリー内のページネーションの実装も今回取り上げたかったのですが、内容がモリモリになってしまうな。ということで次回のブログでまた書いていきたいと思います。