1. ホーム
  2. WordPress

【WordPress】block.json の example の使い方|ブロックインサーターにプレビューを表示する方法

Share

ブロックエディターの左側に開くブロックインサーターでは、ブロック名にマウスを乗せると、そのブロックを挿入したときの見た目が小さく表示されます。コアブロックではおなじみの機能ですが、自作したカスタムブロックでは何も設定しないとプレビューが出ません。このプレビューの中身を決めるのが block.json の example です。この記事では、example の基本の書き方から、innerBlocks を使った入れ子の見本、動的ブロックで見本を用意するときの考え方まで、カスタムブロックを作り始めた方向けに解説します。

example はインサーターのプレビュー用の「見本データ」

example は、プレビューを描画するときに使う属性値や内側のブロックをまとめたオブジェクトです。エディターはインサーターでブロックにホバーされると、example の内容から一時的なブロックを組み立て、そのブロックの edit コンポーネントを縮小表示します。実際の投稿にブロックが追加されるわけではなく、あくまで「こういう見た目になります」という見本を見せるためだけのデータです。

ここで覚えておきたいのは、example が定義されていないブロックはプレビュー自体が表示されないという点です。プレビュー欄には英語環境なら「No preview available.」という文言だけが表示され、見た目は確認できません。属性の初期値(default)が揃っていても、example がなければプレビューは作られません。

基本の書き方

まずは、見出しと本文のテキストを持つシンプルなお知らせブロックを例にします。attributes で定義した属性に、example.attributes で見本用の値を入れます。

src/block.json
{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 3,
    "name": "my-plugin/notice",
    "title": "お知らせ",
    "category": "text",
    "icon": "megaphone",
    "attributes": {
        "heading": {
            "type": "string",
            "default": ""
        },
        "message": {
            "type": "string",
            "default": ""
        },
        "type": {
            "type": "string",
            "default": "info"
        }
    },
    "example": {
        "attributes": {
            "heading": "メンテナンスのお知らせ",
            "message": "10月10日 2:00〜4:00 の間、サイトを一時停止します。",
            "type": "warning"
        }
    },
    "editorScript": "file:./index.js",
    "style": "file:./style-index.css"
}

edit 側では特別な処理は要りません。普段どおり attributes を読んで表示していれば、プレビューのときは example.attributes の値がそのまま渡されます。

src/edit.js
import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function Edit( { attributes, setAttributes } ) {
    const { heading, message, type } = attributes;
    const blockProps = useBlockProps( {
        className: `is-type-${ type }`,
    } );

    return (
        <div { ...blockProps }>
            <RichText
                tagName="p"
                className="notice__heading"
                value={ heading }
                onChange={ ( value ) => setAttributes( { heading: value } ) }
                placeholder="見出しを入力"
            />
            <RichText
                tagName="p"
                className="notice__message"
                value={ message }
                onChange={ ( value ) => setAttributes( { message: value } ) }
                placeholder="本文を入力"
            />
        </div>
    );
}

この状態でインサーターから「お知らせ」にホバーすると、「メンテナンスのお知らせ」という見出しと本文が入った状態のブロックが表示されます。プレースホルダーだけが並んだ空のブロックよりも、どんな用途のブロックなのかがずっと伝わりやすくなります。

example に指定できるキー

example の中で使うキーは次の3つです。どれも省略できます。

キー説明
attributesプレビュー用のブロックに渡す属性値のオブジェクト。キーは attributes で定義した属性名と合わせる
innerBlocks内側に入れるブロックの配列。各要素は name と attributes、さらに入れ子の innerBlocks を持てる
viewportWidthプレビューを描画するときの横幅(px)。この幅で描画したものがプレビュー欄に合わせて縮小される

見本の値がなくてもプレビューだけは出したいとき

属性を持たないブロックや、初期値のままで十分に見た目が伝わるブロックでは、わざわざ値を用意する必要はありません。その場合は空のオブジェクトを書いておきます。

src/block.json(抜粋)
{
    "example": {}
}

example というキーが存在すること自体がプレビューを出す合図になるため、中身が空でも各属性の default を使ったプレビューが表示されます。

viewportWidth でプレビューの描画幅を変える

プレビューは、ある横幅でブロックを描画してから、それをプレビュー欄の大きさに縮小して表示しています。横に長いレイアウトのブロック(カラムやテーブル、横並びのカードなど)では、この描画幅が狭いと折り返しが起きて、実際とは違う見た目になることがあります。そのようなときは viewportWidth で描画幅を指定します。

src/block.json(抜粋)
{
    "example": {
        "attributes": {
            "columns": 3
        },
        "viewportWidth": 800
    }
}

値を大きくするほど広い画面で描画したものが縮小されるので、全体の配置は分かりやすくなる反面、文字は小さくなります。逆に小さくすると、スマートフォン幅で見たときの姿に近づきます。ブロックの主な使われ方に合わせて、見本として一番伝わる幅を選んでください。

InnerBlocks を持つブロックの見本を作る

InnerBlocks を使って、中に他のブロックを入れられるブロックを作った場合、example.attributes だけでは中身が空のプレビューになってしまいます。中に入るブロックは属性ではなく「子ブロック」として扱われるためです。この場合は innerBlocks に子ブロックの一覧を書きます。

例として、見出しと段落、ボタンを入れて使う「カード」ブロックを考えます。

src/block.json
{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 3,
    "name": "my-plugin/card",
    "title": "カード",
    "category": "design",
    "icon": "index-card",
    "attributes": {
        "hasShadow": {
            "type": "boolean",
            "default": false
        }
    },
    "example": {
        "attributes": {
            "hasShadow": true
        },
        "innerBlocks": [
            {
                "name": "core/heading",
                "attributes": {
                    "level": 3,
                    "content": "初心者向けコース"
                }
            },
            {
                "name": "core/paragraph",
                "attributes": {
                    "content": "HTML と CSS の基本から、レスポンシブ対応まで順番に学べます。"
                }
            },
            {
                "name": "core/buttons",
                "innerBlocks": [
                    {
                        "name": "core/button",
                        "attributes": {
                            "text": "詳しく見る"
                        }
                    }
                ]
            }
        ]
    },
    "editorScript": "file:./index.js",
    "style": "file:./style-index.css"
}

innerBlocks の各要素には、ブロック名を name に、そのブロックの属性を attributes に書きます。core/buttons のように、子ブロックがさらに子ブロックを持つ場合は、その中にもう一段 innerBlocks を書けば入れ子にできます。コアブロックの属性名(core/heading の level や content など)は、ブロックエディターハンドブックの「Core Blocks Reference」で確認できます。

edit 側は、いつもどおり InnerBlocks(または useInnerBlocksProps)で子ブロックの置き場所を用意しておくだけです。

src/edit.js
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';

const TEMPLATE = [
    [ 'core/heading', { level: 3, placeholder: 'カードの見出し' } ],
    [ 'core/paragraph', { placeholder: 'カードの説明文' } ],
    [ 'core/buttons' ],
];

export default function Edit( { attributes } ) {
    const blockProps = useBlockProps( {
        className: attributes.hasShadow ? 'has-shadow' : undefined,
    } );
    const innerBlocksProps = useInnerBlocksProps( blockProps, {
        template: TEMPLATE,
    } );

    return <div { ...innerBlocksProps } />;
}

ここで指定している template は、ブロックを実際に挿入したときの初期構成です。一方の example.innerBlocks はプレビューだけに使われる中身で、両者は別々に管理されます。テンプレートはプレースホルダーだけ、見本は具体的な文言入り、というように役割を分けておくと、インサーターでは完成イメージを、挿入後はすぐに書き込める空の枠を見せられます。

registerBlockType 側で example を指定する

example は block.json だけでなく、JavaScript の registerBlockType() に渡す設定オブジェクトにも書けます。見本の文言を翻訳対象にしたい場合は、こちらが便利です。block.json で翻訳の対象になるのは title や description、keywords などの決められた項目で、example の中の文字列は含まれません。JavaScript 側なら __() で文言を包めます。

src/index.js
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import Edit from './edit';
import save from './save';
import metadata from './block.json';

registerBlockType( metadata.name, {
    edit: Edit,
    save,
    example: {
        attributes: {
            heading: __( 'メンテナンスのお知らせ', 'my-plugin' ),
            message: __( '10月10日 2:00〜4:00 の間、サイトを一時停止します。', 'my-plugin' ),
            type: 'warning',
        },
    },
} );

同じブロックに対して block.json と registerBlockType() の両方に example を書くと、どちらの内容がプレビューに出ているのかが分かりにくくなります。翻訳が必要なら JavaScript 側、そうでなければ block.json 側、というように一か所にまとめておくのがおすすめです。

ブロックバリエーションにも example を持たせられる

registerBlockVariation() で登録するバリエーションも、インサーターに独立した項目として並びます。バリエーションの設定にも example を書けるので、バリエーションごとに見本を変えたいときはそれぞれに指定します。書き方はブロック本体の example と同じです。

動的ブロックで見本を用意するときの考え方

render.php や render_callback でフロントの HTML を作る動的ブロックでも、example の使い方は同じです。ただし、プレビューに描画されるのは edit コンポーネントの出力であり、PHP の出力ではありません。この点を押さえておくと、見本づくりで迷いにくくなります。

edit がデータを取得するブロック

最新記事の一覧のように、edit の中で useSelect を使って投稿を取得するブロックでは、プレビューを表示するときにも同じ処理が動きます。サイトに投稿があればそれが見本として表示されますが、投稿がまだない開発環境では「投稿がありません」のような表示になることもあります。example.attributes では表示件数などの「取得条件」は指定できても、取得される投稿そのものは指定できない点に注意してください。

edit で ServerSideRender を使っている場合も、プレビューのたびに example.attributes を使ってサーバーへ描画リクエストが送られます。表示に少し時間がかかるのはこのためです。

プレビュー専用の属性で画像を見せる方法

取得結果に左右されない見本を見せたいときは、プレビュー専用の属性を1つ用意し、example でだけ true にするという方法があります。example.attributes に書けるのは attributes で定義済みの属性だけなので、まず属性として定義しておきます。

src/block.json(抜粋)
{
    "attributes": {
        "postsToShow": {
            "type": "number",
            "default": 3
        },
        "isExample": {
            "type": "boolean",
            "default": false
        }
    },
    "example": {
        "attributes": {
            "isExample": true
        }
    },
    "render": "file:./render.php"
}

edit では、この属性が true のときだけ見本用の画像を返します。画像はビルド対象のフォルダーに置いて import すると、@wordpress/scripts がビルド先へコピーし、URL に置き換えてくれます。

src/edit.js
import { useBlockProps } from '@wordpress/block-editor';
import ServerSideRender from '@wordpress/server-side-render';
import previewImage from './preview.png';

export default function Edit( { attributes } ) {
    const blockProps = useBlockProps();

    // インサーターのプレビューでは画像だけを表示する
    if ( attributes.isExample ) {
        return (
            <div { ...blockProps }>
                <img src={ previewImage } alt="" style={ { width: '100%' } } />
            </div>
        );
    }

    return (
        <div { ...blockProps }>
            <ServerSideRender
                block="my-plugin/latest-items"
                attributes={ attributes }
            />
        </div>
    );
}

実際に挿入したブロックでは isExample が初期値の false のままなので、通常どおり ServerSideRender の結果が表示されます。プレビューのたびにリクエストが飛ぶこともなくなります。ただし、この属性は投稿に保存されうる普通の属性なので、サイドバーなどから編集できる UI は作らないでおきます。

プレビューに見本が反映されないときの確認どころ

ビルド後の block.json が更新されていない

@wordpress/scripts を使っている場合、WordPress が読み込むのは src/block.json ではなく、ビルドでコピーされた build/block.json です。src 側だけを編集してビルドしていなければ、example を書き足しても何も変わりません。npm run start で監視中か、npm run build を実行したかを確認し、そのうえでエディターの画面を再読み込みしてください。

属性名が attributes の定義と食い違っている

プレビューは表示されるのに値が入っていない、という場合は属性名の綴りを疑います。example.attributes のキーは attributes で定義した名前と一致している必要があり、定義されていないキーはプレビュー用のブロックを作る段階で取り除かれます。headline と heading のような似た名前や、大文字・小文字の違いに気をつけてください。型が違う値(数値の属性に文字列を入れるなど)も意図どおりに反映されないことがあります。

innerBlocks に書いたブロックが出てこない

innerBlocks の name には、core/paragraph のように名前空間付きの正式なブロック名を書きます。paragraph だけでは認識されません。また、自作の子ブロックを入れる場合は、そのブロックもエディターに登録されている必要があります。子ブロック用のスクリプトが読み込まれていないと、プレビューにも表示されません。

まとめ

block.json の example は、ブロックインサーターでホバーしたときのプレビューに使う見本データです。example がないとプレビューは表示されず、空のオブジェクトでも書いておけば初期値でのプレビューが出ます。属性値は attributes、子ブロックは innerBlocks、描画幅は viewportWidth で指定します。見本の文言を翻訳したい場合は registerBlockType() 側に書く方法もあります。動的ブロックではプレビューに出るのが edit の出力である点を意識し、必要に応じてプレビュー専用の属性で見本を切り替えると、インサーターで完成イメージを伝えやすくなります。

参考ページ