1. ホーム
  2. WordPress

【WordPress】registerBlockVariation の使い方|既存ブロックのバリエーションを追加する方法

Share

ブロックエディターで「埋め込み」を探すと、YouTube や X(Twitter)などがそれぞれ別のブロックのように並んでいます。実体はどれも core/embed という1つのブロックで、初期設定だけを変えた「バリエーション」として登録されているだけです。この仕組みは自分のテーマやプラグインでも使えます。この記事では、JavaScript の registerBlockVariation() を使って、グループブロックやカラムブロックといった既存ブロックに独自のバリエーションを追加する方法を、指定できるプロパティの意味から isActive の書き方、不要なバリエーションの削除まで順に解説します。

バリエーションは「設定済みのブロック」を候補に並べる仕組み

ブロックバリエーションは、既存のブロックに対して「この属性とこの中身をあらかじめ入れた状態」に名前とアイコンを付け、別のブロックのように扱えるようにする機能です。ブロックそのものを新しく作るわけではないので、editsave を書く必要はありません。登録するのは、初期の属性値・InnerBlocks の初期構成・アイコン・説明といった「見せ方と初期状態」のセットだけです。

たとえば、グループブロックに背景色と余白を設定して、中に見出しと本文を入れた「お知らせボックス」を毎回手作業で組み立てているとします。これをバリエーションとして登録しておけば、挿入ツール(+ボタン)から「お知らせボックス」を選ぶだけで、同じ構成のブロックが一発で挿入されます。中身は普通のグループブロックなので、挿入したあとの編集方法もこれまでと変わりません。

ブロックスタイルとの違い

似た機能に、サイドバーの「スタイル」に選択肢を足すブロックスタイル(register_block_style())があります。両者は役割がはっきり分かれています。ブロックスタイルがやるのは is-style-〇〇 というクラスを付けたり外したりすることだけで、ブロックの中身や属性には手を出しません。見た目のバリエーションを CSS で切り替えたいときに使う機能です。

一方のブロックバリエーションは、属性の初期値や内側のブロック構成そのものを用意します。背景色・配置・リンク先といった属性を最初から入れておけますし、innerBlocks で子ブロックまで組み立てられます。「同じ見た目のバリエーションを切り替えたい」ならスタイル、「設定済みの状態を1クリックで挿入したい」ならバリエーション、と考えると選びやすくなります。

registerBlockVariation の基本の書き方

registerBlockVariation()@wordpress/blocks パッケージが提供する関数で、第1引数に対象のブロック名、第2引数にバリエーションの定義オブジェクトを渡します。ビルド環境を使わない場合は、同じものが wp.blocks.registerBlockVariation() としてグローバルに用意されています。

src/variations.js
import { registerBlockVariation } from '@wordpress/blocks';

registerBlockVariation( 'core/group', {
    name: 'mytheme/notice',              // バリエーションの識別子(一意にする)
    title: 'お知らせボックス',              // 挿入ツールに表示される名前
    description: '背景色つきの枠でお知らせをまとめます。',
    icon: 'megaphone',                   // Dashicon の名前が使える
    attributes: {
        className: 'is-notice-box',      // 挿入時に入る初期の属性値
    },
} );

この JavaScript がエディターで読み込まれると、挿入ツールでグループブロックの隣に「お知らせボックス」が並びます。選ぶと、classNameis-notice-box が入った状態のグループブロックが挿入されます。あとは .is-notice-box に対する CSS をテーマ側で用意すれば、見た目まで含めて完成です。

name は同じブロック内で重複しない文字列にします。コアのバリエーション名と衝突しないよう、mytheme/ のような接頭辞を付けておくと安全です。title は編集する人が目にする表示名なので、日本語で分かりやすく付けて構いません。

書いた JavaScript をエディターに読み込ませる

バリエーションの登録はブラウザ側で行われるため、書いた JS を編集画面で読み込む必要があります。使うフックは enqueue_block_editor_assets で、これは編集画面でだけ実行されるフックです。依存関係には wp-blocks を必ず入れます。

@wordpress/scripts でビルドしている場合は、出力される .asset.php に依存関係とバージョンがまとまっているので、それをそのまま渡すのが確実です。

functions.php
<?php
add_action( 'enqueue_block_editor_assets', 'mytheme_enqueue_block_variations' );

function mytheme_enqueue_block_variations() {
    // wp-scripts が出力する依存関係とバージョンを読み込む
    $asset = require get_theme_file_path( '/build/variations.asset.php' );

    wp_enqueue_script(
        'mytheme-block-variations',
        get_theme_file_uri( '/build/variations.js' ),
        $asset['dependencies'],
        $asset['version'],
        true
    );
}

ビルド環境を用意せず、素の JavaScript ファイルを1枚置くだけでも動きます。その場合は import を使わず wp.blocks 経由で呼び出し、依存関係を自分で列挙します。

functions.php(ビルドしない場合)
<?php
add_action( 'enqueue_block_editor_assets', 'mytheme_enqueue_block_variations' );

function mytheme_enqueue_block_variations() {
    wp_enqueue_script(
        'mytheme-block-variations',
        get_theme_file_uri( '/js/variations.js' ),
        array( 'wp-blocks', 'wp-dom-ready' ), // 依存を明示する
        '1.0.0',
        true
    );
}
js/variations.js
wp.blocks.registerBlockVariation( 'core/group', {
    name: 'mytheme/notice',
    title: 'お知らせボックス',
    icon: 'megaphone',
    attributes: {
        className: 'is-notice-box',
    },
} );

バリエーションに指定できるプロパティ

第2引数のオブジェクトに指定できる主なキーは次のとおりです。必須なのは name だけですが、挿入ツールに出すなら titleicon も実質的に必要です。

プロパティ意味
name必須。バリエーションの識別子。isDefault の判定や unregisterBlockVariation() での指定に使う
title挿入ツールやブロック一覧に表示される名前
descriptionバリエーションの説明文。挿入ツールのプレビュー部分などに表示される
category挿入ツールでの分類。省略すると元のブロックのカテゴリーが使われる
iconアイコン。Dashicon の名前の文字列か、SVG の要素を渡せる
attributes挿入時にセットされる属性値。元のブロックが持つ属性名で指定する
innerBlocks内側にあらかじめ入れておくブロックの構成
example挿入ツールでプレビューを出すためのサンプルデータ。空オブジェクトを渡すとプレビューなしにできる
scopeこのバリエーションを表示する場所。'block' / 'inserter' / 'transform' の配列
isDefaulttrue にすると、そのブロックの既定のバリエーションとして扱われる
isActive編集中のブロックがこのバリエーションかどうかを判定する関数、または比較する属性名の配列

attributes に書けるのは、対象ブロックが実際に持っている属性だけです。定義されていない名前を書いても無視されるので、指定したい属性名が分からないときは、エディターで対象のブロックを選び、コードエディター表示に切り替えてブロックコメントの JSON を見るのが手っ取り早い確認方法です。

scope で表示される場所を切り替える

scope は、そのバリエーションをエディターのどこに出すかを配列で指定するプロパティです。指定できる値は3つあります。

表示される場所
'inserter'挿入ツール(+ボタンやスラッシュコマンド)の一覧に、独立した項目として並ぶ
'block'ブロック側がバリエーションを絞り込んで使う。カラムブロックのように、挿入直後にレイアウトを選ばせるプレースホルダー用
'transform'ブロックツールバーの変換メニューに候補として並ぶ

scope を省略した場合は 'block''inserter' を指定したのと同じ扱いになります。つまり、何も書かなければ挿入ツールには出てきます。逆に「変換メニューにだけ出したい」「挿入ツールには出さずプレースホルダーの選択肢としてだけ使いたい」といった場合に、明示的に絞り込むのが scope の役割です。

src/variations.js
import { registerBlockVariation } from '@wordpress/blocks';

// 挿入ツールと変換メニューの両方に出す
registerBlockVariation( 'core/group', {
    name: 'mytheme/notice',
    title: 'お知らせボックス',
    icon: 'megaphone',
    attributes: { className: 'is-notice-box' },
    scope: [ 'inserter', 'transform' ],
} );

innerBlocks で中身をあらかじめ組み立てておく

バリエーションが本領を発揮するのは innerBlocks を使うときです。これはブロックテンプレートと同じ形式で、[ ブロック名, 属性, 内側のブロック ] という配列を並べます。ネストしたい場合は3番目の要素にさらに同じ形の配列を入れます。

src/variations.js
import { registerBlockVariation } from '@wordpress/blocks';

registerBlockVariation( 'core/group', {
    name: 'mytheme/cta-card',
    title: 'CTAカード',
    description: '見出し・本文・ボタンをまとめたカードを挿入します。',
    icon: 'index-card',
    attributes: {
        className: 'is-cta-card',
    },
    innerBlocks: [
        [ 'core/heading', { level: 3, content: '見出しを入力' } ],
        [ 'core/paragraph', { placeholder: '説明文を入力' } ],
        [
            'core/buttons',
            {},
            [
                [ 'core/button', { text: '詳しく見る' } ],
            ],
        ],
    ],
    scope: [ 'inserter' ],
} );

これで「CTAカード」を選ぶと、見出し・段落・ボタンが入った状態のグループブロックが挿入されます。段落に placeholder を指定しておくと、本文が空のときに薄いグレーの案内文が出るので、何を書けばよいかが編集する人に伝わります。content を指定した場合はその文字列が実際のテキストとして入るので、書き換えてもらう前提の文言に使います。

ここで挿入されるのは、あくまで普通のブロックの集まりです。あとから中の要素を消したり増やしたりしても壊れません。「構成を固定したい」のではなく「毎回同じ組み立てをする手間を省きたい」という用途に向いた機能だと考えてください。

isActive で「今どのバリエーションか」を判定させる

バリエーションから挿入したブロックは、保存された時点では単なる core/group です。そのため、記事を開き直すとエディターはそれを「お知らせボックス」だと認識できず、ブロック名やアイコンは元のグループブロックのまま表示されます。これを解決するのが isActive です。

isActive には、ブロックの現在の属性とバリエーションの属性を受け取って真偽値を返す関数を渡します。true を返すと、エディターはそのブロックをこのバリエーションとして扱い、ブロックのタイトルやアイコンをバリエーションのものに切り替えます。

src/variations.js
import { registerBlockVariation } from '@wordpress/blocks';

registerBlockVariation( 'core/group', {
    name: 'mytheme/notice',
    title: 'お知らせボックス',
    icon: 'megaphone',
    attributes: { className: 'is-notice-box' },
    // 第1引数が編集中のブロックの属性、第2引数がこのバリエーションの attributes
    isActive: ( blockAttributes, variationAttributes ) =>
        blockAttributes.className === variationAttributes.className,
} );

ブロックの属性すべてを機械的に比べていない点が重要です。core/group には余白や配置など多くの属性があり、編集する人が自由に変えていきます。判定に使うのは「そのバリエーションであることを示す目印になる属性」だけに絞るのが基本です。上の例では className がその目印になっています。

属性名の配列で書く短縮形

「特定の属性が一致していればよい」という単純な判定なら、比較したい属性名を文字列の配列で渡せます。列挙した属性がすべて一致したときにアクティブと判定されるので、関数版と同じことをより短く書けます。

src/variations.js
registerBlockVariation( 'core/group', {
    name: 'mytheme/notice',
    title: 'お知らせボックス',
    icon: 'megaphone',
    attributes: { className: 'is-notice-box' },
    // className が変わっていなければ、このバリエーションとみなす
    isActive: [ 'className' ],
} );

コアの埋め込みブロックも同じ考え方で、動画サービスごとのバリエーションを providerNameSlug という属性1つで見分けています。だから YouTube の埋め込みを開き直しても、ブロック名がきちんと「YouTube」と表示されるわけです。判定の目印になる属性を1つ決めておく、というのがバリエーション設計のコツになります。

使わないバリエーションを取り除く

逆に、コアが用意しているバリエーションのうち、そのサイトでは使わないものを一覧から消したいこともあります。埋め込みブロックには多くのサービスが登録されているので、使うものだけに絞ると挿入ツールがすっきりします。これには unregisterBlockVariation() を使い、ブロック名とバリエーション名の2つを渡します。

src/variations.js
import { unregisterBlockVariation } from '@wordpress/blocks';
import domReady from '@wordpress/dom-ready';

// ブロックの登録が終わってから解除する
domReady( () => {
    unregisterBlockVariation( 'core/embed', 'tiktok' );
    unregisterBlockVariation( 'core/embed', 'reddit' );
} );

第2引数に渡すのは、表示名ではなく登録時の name です。埋め込みブロックの場合はサービスのスラッグがそのままバリエーション名になっています。名前が分からないときは、ブラウザの開発者ツールのコンソールで wp.blocks.getBlockVariations( 'core/embed' ) を実行すると、登録済みのバリエーションが配列で返ってくるので、そこから name を確認できます。

解除の処理を domReady() で包んでいるのは、対象のブロックがまだ登録されていないタイミングで実行してしまう競合を避けるためです。ここを省くと、環境によって「消えたり消えなかったり」という不安定な動きになります。

追加したバリエーションが挿入ツールに出てこないとき

コードを書いたのに挿入ツールで見つからない、という場合は、次の順に確認していくと原因を絞り込めます。

scope の指定で挿入ツールから外れている

一番多いのが scope の書き間違いです。scope: [ 'block' ] だけを指定すると、そのバリエーションはブロック側のプレースホルダー用という扱いになり、挿入ツールの一覧には並びません。同じく scope: [ 'transform' ] なら変換メニューにしか出てきません。挿入ツールに出したいなら 'inserter' を含めるか、scope ごと省略します。省略時は 'block''inserter' の両方が有効になるので、迷ったらまず外してみるのが手軽な切り分けになります。

ブロック名やスクリプトの読み込みを間違えている

第1引数は group ではなく core/group のように、名前空間を含めたフルネームで書きます。存在しないブロック名を渡してもエラーにはならず、静かに何も起きないだけなので気付きにくいところです。

スクリプト側では、読み込みフックが enqueue_block_editor_assets になっているかを確認します。wp_enqueue_scripts はフロント表示用のフックなので、そこで読み込んでも編集画面には届きません。また依存関係に wp-blocks を入れ忘れると、自分のスクリプトのほうが先に走って wp.blocks が未定義になり、コンソールにエラーが出ます。ブラウザの開発者ツールでコンソールを開き、エラーが出ていないか、そもそも JS ファイルが読み込まれているかを見てみてください。

name が他のバリエーションと重複している

同じブロックに対して同じ name で二重に登録すると、あとから登録したほうの内容で置き換わります。コアや使用中のプラグインが登録している名前と偶然かぶると、意図しない内容に上書きされたり、逆に自分の定義が上書きされたりします。前述の wp.blocks.getBlockVariations() で既存の名前を確認し、mytheme/ のような接頭辞を付けて衝突を避けましょう。

挿入したあとにバリエーション名が表示されないとき

挿入直後は「お知らせボックス」と表示されていたのに、記事を保存して開き直すと「グループ」に戻っている――これは isActive を指定していないときに必ず起こる挙動で、バグではありません。

保存される HTML にはバリエーション名は記録されず、あくまで元のブロックとして保存されます。エディターは読み込み時に属性を見てバリエーションを推測するしかなく、その判定ロジックを与えるのが isActive です。ブロックのタイトルやアイコンを保持したい、変換メニューで現在の状態を正しく表示したい、という場合は必ず指定してください。

isActive を書いたのに切り替わらない場合は、判定に使っている属性が編集の過程で変わっていないかを疑います。たとえば className を目印にしていると、編集する人がサイドバーの「追加 CSS クラス」を書き換えた時点で一致しなくなります。判定には、通常の編集操作で触られにくい属性を選ぶのが安全です。また、複数のバリエーションで同じ条件を返してしまうと、最初に一致したものが選ばれてしまうので、条件どうしが重ならないように設計します。

まとめ

registerBlockVariation() は、既存のブロックに「設定済みの状態」を名前とアイコン付きで登録し、別のブロックのように選べるようにする関数です。attributes で初期の属性値を、innerBlocks で内側の構成をまとめて用意でき、scope で挿入ツール・プレースホルダー・変換メニューのどこに出すかを制御します。保存後もエディターにバリエーションだと認識させたいときは isActive を忘れずに指定し、判定の目印になる属性を1つ決めておくのがポイントです。不要なコアのバリエーションは unregisterBlockVariation() で整理できます。新しいブロックを作らずに編集画面を使いやすくできるので、複数人で更新するサイトほど効果の大きい仕組みです。

参考ページ