Payloadのブロックフィールドの使い方
はじめに
Payloadには、ブロックフィールドという特殊なフィールドがあります。テキストフィールドやチェックボックスフィールドのようなシンプルなフィールドとは異なり、ブロックフィールドは少し複雑です。
この記事では、ブロックフィールドの使い方について、ブロックフィールドの定義方法やフロント画面の実装方法を交えて解説したいと思います。
前提
- ブロックフィールドを使用するには必要なコード量が多いため、Payloadのwebsiteテンプレートを使用している前提で解説します
- 管理画面のサポート言語に日本語と英語を設定しています
管理画面の言語設定については、下記の記事をご参照ください。
ブロックフィールドの概要
ブロックフィールドとは、Webページをブロックというパーツの組み合わせで作成するための機能です。
たとえば、下記のブロックを用意したとします。
- スライダー
- 見出し
- リッチテキスト
- メディア
- アコーディオン
そうすると、Webサイトのトップページや各種下層ページをこれらのブロックの組み合わせで作成することができます。
ブロックフィールドの管理画面でのUIは、下記キャプチャのようになります。
「Add Layout」をクリックすると、下記キャプチャのモーダルが表示され、あらかじめ定義したブロックの一覧が表示されます。
使用したいブロックを選択すると先ほどの画面に戻り、選択したブロックがブロックフィールドに追加されます。
Webページの構成に必要なブロックを次々に追加していくことができます。
これにより、簡単に好みのレイアウトでWebページを作成できます。また、追加したブロックは後からドラッグ&ドロップで順番を入れ替えたり、特定のブロックのみを削除できたりします。
ブロックの定義方法
ブロックの定義方法について解説したいと思います。
この記事では例として、「テキスト + メディア」というブロックを定義してみます。「テキスト + メディア」ブロックは、テキストとメディアを横並びの2カラムで表示するためのブロックです。左にテキスト・右にメディアのパターンと、左にメディア・右にテキストのパターンに対応したいと思います。
上記の仕様を実現するために、「テキスト + メディア」ブロックには下記のフィールドを設けます。
- テキスト
- メディア
- メディアの位置(左か右かを選択するラジオボタン)
以上を踏まえてブロックを定義していきます。
まず、「テキスト + メディア」ブロックを定義するにはsrc/blocks/TextAndMediaBlock/config.ts
を作成し、下記のコードを記述します。
import type { Block } from 'payload'
export const TextAndMediaBlock: Block = {
slug: 'textAndMediaBlock',
labels: {
singular: {
en: 'Text + Media Block',
ja: 'テキスト + メディア ブロック',
},
plural: {
en: 'Text + Media Block',
ja: 'テキスト + メディア ブロック',
},
},
interfaceName: 'TextAndMediaBlock',
fields: [
{
name: 'text',
label: {
en: 'Text',
ja: 'テキスト',
},
type: 'richText',
required: true,
},
{
name: 'media',
label: {
en: 'Media',
ja: 'メディア',
},
type: 'upload',
relationTo: 'media',
required: true,
},
{
name: 'mediaPostion',
label: {
en: 'Media Postion',
ja: 'メディアの位置',
},
type: 'radio',
options: [
{
label: {
en: 'Left',
ja: '左'
},
value: 'left',
},
{
label: {
en: 'Right',
ja: '右',
},
value: 'right',
}
],
required: true,
defaultValue: 'left',
}
],
}
次に、websiteテンプレートにあるPagesコレクションのブロックフィールドに、上記で定義した「テキスト + メディア」ブロックを追加します。
import { TextAndMediaBlock } from '../../blocks/TextAndMediaBlock/config'
// ...
export const Pages: CollectionConfig<'pages'> = {
// ...
fields: [
{
name: 'layout',
type: 'blocks',
blocks: [CallToAction, Content, MediaBlock, Archive, FormBlock, TextAndMediaBlock],
required: true,
admin: {
initCollapsed: true,
},
},
],
label: 'Content',
// ...
}
以上の対応で、追加した「テキスト + メディア」ブロックがブロック一覧に表示され、使用できるようになります。
フロント画面の実装
「テキスト + メディア」ブロックをフロント画面に表示させる実装方法について解説したいと思います。
まず、src/blocks/TextAndMediaBlock/Component.tsx
を作成し、下記のコードを記述します。これは「テキスト + メディア」ブロックを表示するためのコンポーネントです。mediaPosition
の値に応じて、テキストとメディアの表示位置が切り替わるよう実装しています。
import React from 'react'
import type { TextAndMediaBlock as TextAndMediaBlockProps } from '@/payload-types'
import RichText from '@/components/RichText'
import { Media } from '@/components/Media'
export const TextAndMediaBlock: React.FC<TextAndMediaBlockProps> = (props) => {
const {
text,
media,
mediaPostion
} = props
const mediaComponent = media && <Media resource={media} />
const textComponent = text && <RichText data={text} enableGutter={false} className="w-full" />
return (
<div className="container grid grid-cols-2 gap-20">
{mediaPostion === 'left' ? (
<>
{mediaComponent}
{textComponent}
</>
) : (
<>
{textComponent}
{mediaComponent}
</>
)}
</div>
)
}
次に、src/blocks/RenderBlocks.tsx
に、上記で作成したコンポーネントを追加します。
import { TextAndMediaBlock } from '@/blocks/TextAndMediaBlock/Component'
const blockComponents = {
archive: ArchiveBlock,
content: ContentBlock,
cta: CallToActionBlock,
formBlock: FormBlock,
mediaBlock: MediaBlock,
textAndMediaBlock: TextAndMediaBlock,
}
// ...
以上で完了です。
動作確認
最後に動作確認をします。
まず、下記の設定でページを作成し、左にメディア・右にテキストのパターンを確認します。
問題なく左にメディア・右にテキストが表示されることを確認できました。
次に、下記の設定でページを作成し、左にテキスト・右にメディアのパターンを確認します。
問題なく左にテキスト・右にメディアが表示されることを確認できました。
まとめ
この記事では、ブロックフィールドの使い方について、ブロックフィールドの定義方法やフロント画面の実装方法を交えて解説しました。ブロックフィールドを使用することで、簡単に好みのレイアウトでWebページを作成できることを理解していただけたかと思います。
ただし、ブロックの定義追加やフロント画面の実装は結構手間がかかります。また、実際の開発ではどのようなブロックを用意するかといった要件定義や設計にも多大な時間を要することになります。本当にブロックフィールドが必要かは慎重に検討されることをおすすめします。
参考
Discussion