Waka blog.

microCMSで月別アーカイブを実装する

microCMSのフィルタに存在するbegin_withを活用して実装する。

begins_withは指定した値から始まるコンテンツを取得するためのフィルタだが、公式ドキュメントにあるよう publishedAt[begins_with]2023-11 のようにすることで指定した年月に公開された記事の一覧を取得することができる。

指定した年月から現在の年月までを文字列の配列で取得

["2024-01", "2024-02", ..., "2024-12"] のような形で連続した年月の配列を生成する関数を実装

export const getMonthListFromStartToDate = (start: string): string[] => {
  const result: string[] = [];
  const [startYear, startMonth] = start.split("-").map(Number);

  const startDate = new Date(startYear, startMonth - 1); // 開始年月
  const currentDate = new Date(); // 現在年月

  let currentYear = startDate.getFullYear();
  let currentMonth = startDate.getMonth(); // 0から始まる月

  while (
    currentYear < currentDate.getFullYear() ||
    (currentYear === currentDate.getFullYear() && currentMonth <= currentDate.getMonth())
  ) {
    // YYYY-MM 形式で年月をリストに追加
    const monthString = `${currentYear}-${String(currentMonth + 1).padStart(2, "0")}`;
    result.push(monthString);

    // 翌月に移行
    currentMonth++;
    if (currentMonth > 11) {
      currentMonth = 0;
      currentYear++;
    }
  }

  return result;
};

Promise.allでまとめて月別記事数一覧を取得

以下のようにPromise.allを使用することで処理時間の短縮を図る

  const getPosts = months.map(async (month) => {
    const data = await client.getList<Post>({
      endpoint: "blog",
      queries: {
        limit: 100,
        filters: `publishedAt[begins_with]${month}`,
      },
    });
    return {
      totalCount: data.totalCount,
      month: month,
    };
  });

  const monthlyPosts = await Promise.all(getPosts);

月別アーカイブ一覧表示

月別の記事件数が取得できたので、あとは任意の形式で一覧表示する。

以下はremix + tailwindを活用した例。年月クリックで年月単位の記事一覧に遷移する想定。

export const MonthlyPosts: FC<Props> = ({ monthlyPosts }: Props) => {
  return (
    <>
      <p className="mb-4">Monthly Archives</p>
      {monthlyPosts
        .filter((monthlyPost) => monthlyPost.totalCount >= 1)
        .map((monthlyPost) => (
          <Link key={monthlyPost.month} to={`monthly/${monthlyPost.month}`}>
            <p className="text-gray-600 text-sm pl-2 pb-2">{`${monthlyPost.month.replace(/-/g, "/")} (${
              monthlyPost.totalCount
            })`}</p>
          </Link>
        ))}
    </>
  );
};

以上。