😊

Payloadでコレクションを定義してフロント画面に表示する

に公開

はじめに

Payloadのコレクションとは、複数のレコードを登録できるデータモデルです。
Webサイトでいうとお知らせやブログなどのページをはじめ、ブログのカテゴリやユーザーなどページを持たないデータもコレクションに該当します。

この記事では、シンプルな「お知らせ」コレクションを定義してフロント画面に表示するまでの手順を紹介します。

前提

  • フロントエンドの実装はNext.js App Routerで行います
  • フロントエンドの実装ではTailwind CSSを使用しています
  • 管理画面のサポート言語に日本語と英語を設定しています

管理画面の言語設定については、下記の記事をご参照ください。

https://zenn.dev/ksk1kd/articles/b69038ec67f799

お知らせコレクションの定義追加

Payloadでは、すべての設定をpayload.config.tsで行いますが、設定が増えてくるとファイルが肥大化するため、コレクションの定義はファイルを分割しpayload.config.tsからインポートすることが推奨されています。

コレクション定義ファイルの作成

まずは、src/collections/News/index.tsを作成し、下記の「お知らせ」コレクションの定義を記述します。

src/collections/News/index.ts
import type { CollectionConfig } from 'payload'

export const News: CollectionConfig = {
  slug: 'news',
  admin: {
    defaultColumns: ['title', 'publishedAt', 'updatedAt'],
    useAsTitle: 'title',
  },
  labels: {
    singular: {
      en: 'News',
      ja: 'お知らせ',
    },
    plural: {
      en: 'News',
      ja: 'お知らせ',
    },
  },
  fields: [
    {
      name: 'title',
      label: {
        en: 'Title',
        ja: 'タイトル',
      },
      type: 'text',
      required: true,
    },
    {
      name: 'body',
      label: {
        en: 'Body',
        ja: '本文',
      },
      type: 'richText',
    },
    {
      name: 'publishedAt',
      label: {
        en: 'Published At',
        ja: '公開日',
      },
      type: 'date',
      required: true,
      admin: {
        date: {
          pickerAppearance: 'dayOnly',
        },
        position: 'sidebar',
      },
    },
  ],
}

上記の定義内容について、主要な部分のみ解説したいと思います。

フィールド

下記3つのフィールドを定義しています。

  • タイトル ※必須項目
  • 本文
  • 公開日 ※必須項目

ラベル

コレクションのラベルやフィールドのラベルには、日本語用と英語用のラベルを設定しています。これは、管理画面のサポート言語に日本語と英語を設定しているためです。ご自身の環境の管理画面サポート言語設定に則して適宜編集してください。

公開日のUI設定

公開日フィールドのadminキー配下は、管理画面におけるUI設定です。pickerAppearance: 'dayOnly'の設定により、管理画面では日付のみ指定でき時刻は指定できないUIとなります。また、position: 'sidebar'の設定により、メインエリアではなく管理画面右側のサイドバーに表示されます。

コレクション定義ファイルのインポート

作成したコレクション定義ファイルをsrc/payload.config.tsからインポートします。

src/payload.config.tsに下記を追加します。

src/payload.config.ts
import { News } from './collections/News'

export default buildConfig({
  // ...
  // すでにcollectionsキーがある場合は配列の中に「News」を追加します
  // Payload管理画面では配列の要素順で表示されるため、適切な位置に挿入します
  // e.g. collections: [Pages, Posts, News, Media, Categories, Users],
  collections: [News],
})

これでコレクションの定義追加は完了です。

サンプルデータの登録

設定が完了し管理画面にアクセスすると、左メニューに「News」が追加されたことを確認できると思います。管理画面の言語設定を日本語にしていると「お知らせ」と表示されます。

お知らせコレクションが表示されている管理画面

後ほどフロント画面を実装するため、いくつかサンプルデータを作成しておきます。
編集画面は、先ほどのコレクション定義により下記キャプチャのようになります。フィールドの種類に応じた入力フォームが表示され、公開日は右側のサイドバーに表示されていることを確認できると思います。

お知らせコレクションの編集画面

お知らせ詳細ページの実装

次にお知らせ詳細ページの実装を行います。Next.js App Routerで実装しますが、Next.js App Router自体の解説は省略させていただきます。

src/app/(frontend)/news/[id]/page.tsxを作成して、下記のコードを記述します。
このコードはパフォーマンスを考慮していませんので、その点はご注意ください。

src/app/(frontend)/news/[id]/page.tsx
import configPromise from '@payload-config'
import { RichText } from '@payloadcms/richtext-lexical/react'
import { getPayload } from 'payload'
import { notFound } from 'next/navigation'

type Args = {
  params: Promise<{
    id: number
  }>
}

export default async function Page({ params: paramsPromise }: Args) {
  const { id } = await paramsPromise

  const payload = await getPayload({ config: configPromise })

  const result = await payload.find({
    collection: 'news',
    limit: 1,
    where: {
      id: {
        equals: id,
      },
    },
  })

  const news = result.docs?.[0]

  if (!news) notFound()

  return (
    <article className="mx-40 py-20">
      <time className="block mb-5">{new Date(news.publishedAt).toLocaleDateString()}</time>
      <h1 className="mb-12 text-4xl">{news.title}</h1>
      {news.body && <RichText data={news.body} />}
    </article>
  )
}

上記の実装により、/news/[id]のパスでお知らせ詳細ページを表示できるようになります。アクセスしてみると、下記キャプチャのように公開日、タイトル、本文が表示されていることを確認できます。

お知らせ詳細ページのサンプル
※デザインはご自身の環境に依存します

お知らせ一覧ページの実装

次にお知らせ一覧ページの実装を行います。

src/app/(frontend)/news/page.tsxを作成して、下記のコードを記述します。
こちらのコードもパフォーマンスを考慮していませんので、その点はご注意ください。

src/app/(frontend)/news/page.tsx
import configPromise from '@payload-config'
import { getPayload } from 'payload'
import Link from 'next/link'
import React from 'react'

export default async function Page() {
  const payload = await getPayload({ config: configPromise })

  const news = await payload.find({
    collection: 'news',
    sort: '-publishedAt',
  })

  return (
    <div className="mx-40 py-20">
      <h1 className="mb-16 text-4xl">News</h1>
      <ul className="flex flex-col gap-4">
        {news.docs.map((news) => (
          <li key={news.id}>
            <Link href={`/news/${news.id}`} className="py-3 px-2">
              {new Date(news.publishedAt).toLocaleDateString()} {news.title}
            </Link>
          </li>
        ))}
      </ul>
    </div>
  )
}

上記の実装により、/newsのパスでお知らせ一覧ページを表示できるようになります。アクセスしてみると、下記キャプチャのようにサンプルデータとして登録したお知らせの一覧が表示されていることを確認できます。

お知らせ一覧ページのサンプル
※デザインはご自身の環境に依存します

まとめ

この記事では、「お知らせ」コレクションを定義してフロント画面に表示するまでの手順を紹介しました。コレクションの定義追加とそれに対応するフロント画面表示は、Payloadを用いた開発の基本ですので、この記事を通して開発の流れを把握していただけたならば幸いです。

参考

https://payloadcms.com/docs/configuration/collections

https://payloadcms.com/docs/local-api/overview

Discussion