1. ホーム
  2. WordPress

【WordPress】create-block でカスタムブロックのひな形を作る方法|@wordpress/scripts のビルド環境を解説

Share

ブロックエディター(Gutenberg)に自分だけのブロックを追加したい、と思っても、いざ始めようとすると「どのファイルをどこに置けばいいのか」「JSX はどうやって動かすのか」で手が止まりがちです。この最初のハードルを一気に下げてくれるのが、WordPress 公式のひな形生成ツール @wordpress/create-block です。この記事では、npx @wordpress/create-block でプラグインのひな形を作り、@wordpress/scripts でビルドして、実際にエディターの一覧へ自分のブロックを出すところまでを解説します。WordPress 6 系・Block API version 3 を前提にしています。

カスタムブロックにビルド環境が必要な理由

カスタムブロックの編集画面は React で作られており、公式ドキュメントのコード例も <p>...</p> のような JSX(JavaScript の中に HTML に似た記法を書ける構文)で書かれています。JSX はブラウザがそのまま解釈できる文法ではないため、素の JavaScript へ変換する処理が必要です。

さらにブロック開発では import { registerBlockType } from '@wordpress/blocks'; のように ES モジュールimport を使い、機能ごとに用意された @wordpress/* パッケージを読み込みます。これらのパッケージは WordPress 本体が読み込み済みのスクリプトを参照する形にまとめる必要があり、SCSS で書いたスタイルも CSS に変換しなければなりません。

つまりブロック開発には、JSX の変換・モジュールのバンドル・SCSS のコンパイルといった一連のビルドが欠かせません。これを自分で webpack や Babel から設定するのは大変ですが、WordPress は必要な設定を最初から済ませた @wordpress/scripts というパッケージを公式に配布しています。そして、その @wordpress/scripts を組み込んだプラグインのひな形を一発で作ってくれるのが @wordpress/create-block です。設定ファイルを書かずにブロック開発を始められる、公式の出発点だと考えてください。

create-block でひな形を作る

create-block はインストールせずに npx でそのまま実行できます。あらかじめ Node.js と npm を用意し、WordPress のプラグインディレクトリ(wp-content/plugins)に移動してから実行してください。コマンドの最後に渡した名前でディレクトリが作られ、その中にプラグイン一式が生成されます。

ターミナル
# プラグインディレクトリへ移動する
cd /path/to/wordpress/wp-content/plugins

# my-block というスラッグでプラグインのひな形を作る
npx @wordpress/create-block my-block

# 作られたディレクトリに入る
cd my-block

実行するとひな形のコピーに続いて npm install が自動で走り、@wordpress/scripts などの開発用パッケージが node_modules に入ります。回線やマシンにもよりますが、数分かかることもあるので終わるまで待ちましょう。ここで渡した my-blockブロックのスラッグで、ディレクトリ名・プラグインのメインファイル名・ブロック名の後半部分に使われます。

なお、プラグインディレクトリ以外の場所で作っても構いませんが、その場合は生成されたディレクトリごと wp-content/plugins に移動しないと WordPress がプラグインとして認識しません。最初からプラグインディレクトリで実行しておくほうが確実です。

対話形式ではなくオプションで指定する

スラッグを省略して npx @wordpress/create-block だけを実行すると、ブロック名や説明、カテゴリーなどを順に聞いてくる対話モードになります。毎回入力するのが面倒なときは、コマンドの引数としてまとめて渡せます。

ターミナル
npx @wordpress/create-block my-block \
  --namespace="webool" \
  --title="お知らせボックス" \
  --short-description="お知らせを目立たせて表示するブロックです。" \
  --category="widgets"

ここで指定した値は src/block.jsonmy-block.php のコメントに書き込まれます。よく使うオプションは次のとおりです。

オプション役割
--namespaceブロック名の前半(名前空間)。webool を指定すると webool/my-block になる。省略時は create-block
--titleブロック挿入ツールに表示される名前
--short-descriptionブロックの説明文
--categoryブロック挿入ツールでの分類。text / media / design / widgets / theme / embed から選ぶ
--variantひな形の種類。static(初期値)と dynamic がある
--no-pluginプラグイン一式ではなく、ブロックのファイルだけを生成する(既存プラグインやテーマに組み込むとき)

動的ブロックのひな形にする

初期値の static は、エディターで編集した内容をそのまま HTML として投稿本文に保存する静的ブロックのひな形です。これに対して、表示のたびに PHP で HTML を組み立てたい場合は --variant=dynamic を付けます。

ターミナル
# 動的ブロック(サーバー側で HTML を組み立てる)のひな形
npx @wordpress/create-block my-block --variant=dynamic

こちらで生成されるひな形には src/render.php が含まれ、block.json にその PHP ファイルを指す render の指定が入ります。フロント側の HTML は保存された本文ではなく、表示のたびに render.php が出力する形になります。最新の投稿一覧のように、内容が更新され続けるブロックを作りたいときはこちらを選びます。まずはブロック開発の流れをつかむ目的なら、初期値の静的ブロックで十分です。

生成されるファイルの構成

静的ブロックのひな形を作ると、my-block ディレクトリの中に次のようなファイルが並びます。それぞれの役割を押さえておくと、どこを編集すればいいのかが見えてきます。

ファイル / ディレクトリ役割
my-block.phpプラグイン本体。先頭のコメントがプラグイン情報になり、init フックで register_block_type() を呼んでブロックを WordPress に登録する
src/block.jsonブロックの設定ファイル。ブロック名・表示名・カテゴリー・アイコン・読み込むスクリプトやスタイルなどをまとめて宣言する。ブロック定義の中心となるファイル
src/index.jsビルドの入口。block.json を読み込み、registerBlockType()editsave を渡してブラウザ側でブロックを登録する
src/edit.jsエディター上での見た目と操作を担当する React コンポーネント
src/save.js投稿本文に保存される HTML を返す関数。静的ブロックの出力を決める(dynamic のひな形では代わりに render.php が使われる)
src/editor.scssエディターでのみ適用されるスタイル。edit.js から読み込まれる
src/style.scssエディターとフロントの両方に適用されるスタイル
build/ビルド結果の出力先。WordPress が実際に読み込むのはこのディレクトリの中身
package.json依存パッケージと npm start などのコマンド定義。@wordpress/scripts が開発用の依存として入っている
node_modules/インストールされた開発用パッケージ。配布物には含めない
readme.txtWordPress プラグインディレクトリ形式の説明ファイル

ポイントは、自分が書くのは src の中だけで、build は生成物なので直接編集しないという点です。build を手で書き換えても、次のビルドで上書きされて消えてしまいます。なお、生成されるファイルの細かな顔ぶれは create-block のバージョンによって多少変わります(.editorconfig.gitignore、フロント用の view.js などが加わることがあります)。手元で生成されたものを確認しながら読み進めてください。

プラグイン本体の PHP がブロックを登録する

生成された my-block.php は、ごく短いファイルです。プラグインとして認識されるためのヘッダーコメントと、ブロックを登録する関数だけで構成されています。

my-block.php
<?php
/**
 * Plugin Name:       My Block
 * Description:       Example block scaffolded with Create Block tool.
 * Version:           0.1.0
 * Requires at least: 6.7
 * Requires PHP:      7.4
 * Author:            The WordPress Contributors
 * License:           GPL-2.0-or-later
 * Text Domain:       my-block
 */

// 直接アクセスされたときは何もしない
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * build ディレクトリの block.json を読ませてブロックを登録する
 */
function create_block_my_block_block_init() {
    register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'create_block_my_block_block_init' );

注目したいのは register_block_type( __DIR__ . '/build' ) の部分です。この関数にはブロック名を直接書く方法もありますが、ここではディレクトリのパスを渡しています。パスを渡すと WordPress はその中の block.json を読み込み、そこに書かれたブロック名・スクリプト・スタイルの情報をまとめて登録してくれます。JavaScript 側で wp_enqueue_script() を書く必要がないのは、この block.json 経由の登録のおかげです。

渡しているのが src ではなく build である点も重要です。ビルド時に block.jsonbuild へコピーされ、ファイルの参照先もビルド後のファイル名に合わせて解決されます。WordPress が見にいくのはあくまで build の中身であり、src は開発用のソースにすぎません。

また、登録は init フックの中で行います。ブロックの登録タイミングとして WordPress が想定しているのが init なので、ここは変えずに使いましょう。関数名の create_block_my_block_block_init は他プラグインと衝突しないよう名前空間代わりの接頭辞が付いた形で、そのままにしておいて問題ありません。

@wordpress/scripts のコマンドでビルドする

ひな形を作った直後の状態では、まだ build ディレクトリがありません。package.json に定義されたコマンドを実行して、src の中身を build へ変換する必要があります。用意されているコマンドは次のとおりです。

コマンド実行される内容
npm startwp-scripts start。ソースの変更を監視して自動で再ビルドする。開発中に動かしっぱなしにするコマンド
npm run buildwp-scripts build。圧縮された本番用のファイルを一度だけ生成する。配布前に必ず実行する
npm run formatwp-scripts format。WordPress のコーディング規約に沿ってコードを自動整形する
npm run lint:jswp-scripts lint-js。JavaScript の書き方をチェックする
npm run lint:csswp-scripts lint-style。SCSS / CSS の書き方をチェックする
npm run plugin-zipwp-scripts plugin-zip。配布用の ZIP を作る。node_modulessrc を除いた形でまとめられる

まずは開発用の監視ビルドを起動してみましょう。プラグインのディレクトリで次を実行します。

ターミナル
# src を監視して、保存のたびに build を作り直す
npm start

このコマンドは実行したまま常駐します。src/edit.js などを編集して保存すると自動でビルドが走るので、ブラウザを再読み込みするだけで変更を確認できます。開発を終えるときは Ctrl + C で止めてください。

ビルドが終わると build ディレクトリに、バンドルされた index.js、コンパイル済みの CSS、コピーされた block.json、そして index.asset.php が生成されます。この index.asset.php は、スクリプトが依存している @wordpress/* パッケージの一覧とバージョン文字列を PHP の配列として書き出したファイルです。WordPress はこれを読んで必要なスクリプトを先に読み込み、ファイルが更新されたときだけキャッシュが切れるようにしてくれます。手で書く必要はありません。

公開や配布の前には、必ず npm run build を実行しておきます。開発用ビルドは動作確認向けの出力なので、そのまま配布するとファイルサイズが無駄に大きくなります。build ディレクトリはプラグインの動作に必要な成果物なので、配布物には必ず含めてください。逆に node_modules は配布に不要です。

edit.js と save.js を読み解く

ひな形の中身で最初に触ることになるのが edit.jssave.js です。まずはこの二つを結び付けている index.js から見てみます。

src/index.js
import { registerBlockType } from '@wordpress/blocks';

// フロントとエディターの両方に適用されるスタイル
import './style.scss';

import Edit from './edit';
import save from './save';
import metadata from './block.json';

// block.json の name(例: create-block/my-block)でブロックを登録する
registerBlockType( metadata.name, {
    edit: Edit,
    save,
} );

block.json をそのまま import して、その name をブロック名として使っているのが分かります。ブロック名を PHP 側と JavaScript 側で二重に書かずに済む、うまい作りになっています。

次に edit.js です。ここが、エディターでブロックを選んだときに表示される中身になります。

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

// エディターでだけ適用されるスタイル
import './editor.scss';

export default function Edit() {
    return (
        <p { ...useBlockProps() }>
            { __( 'My Block – hello from the editor!', 'my-block' ) }
        </p>
    );
}

そして save.js は、投稿を保存したときに本文へ書き出される HTML を返します。

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

export default function save() {
    return (
        <p { ...useBlockProps.save() }>
            { 'My Block – hello from the saved content!' }
        </p>
    );
}

useBlockProps が付けてくれるもの

どちらのファイルにも出てくる useBlockProps は、ブロックの一番外側の要素に付けるべき属性をまとめて返す関数です。返ってきたオブジェクトを { ...useBlockProps() } のようにスプレッド構文で展開し、外側の要素に渡します。

返される属性には、wp-block-create-block-my-block のようなブロック固有のクラス名や、利用者がサイドバーで設定した色・文字サイズ・余白などのクラスとインラインスタイルが含まれます。エディター側の useBlockProps() はこれに加えて、ブロックをクリックで選択したりドラッグで並べ替えたりするための属性やイベントハンドラーも返します。エディターでブロックが「ブロックらしく」振る舞うのは、この関数の戻り値を渡しているからです。

保存側で useBlockProps.save() と別の呼び方をしているのは、保存される HTML には編集用のイベントハンドラーが不要で、クラス名やスタイルといったフロントに残すべき属性だけを返す必要があるためです。呼び分けを間違えると、エディターの内部的な属性が本文に混ざったり、逆にフロントで必要なクラスが欠けたりします。

この二つの呼び分けは必ずセットで覚えておいてください。edit では useBlockProps()save では useBlockProps.save()。まずは edit.jssave.js の文言を書き換えて保存し、エディターとフロントの表示が変わることを確かめてみると、二つのファイルの役割の違いが実感できます。

ブロックがエディターの一覧に出てこないとき

手順どおりに進めたつもりでも、ブロック挿入ツールで検索して自分のブロックが見つからないことがあります。原因はだいたい決まっているので、上から順に確認していきましょう。

ビルドをしていない

最も多いのがこれです。create-block はひな形を作るだけで、build ディレクトリまでは作りません。register_block_type()build の中の block.json を読もうとするので、ビルドしていない状態ではそもそも読むべきファイルが存在せず、ブロックは登録されません。

プラグインのディレクトリに build があるか、その中に block.jsonindex.js があるかを確認してください。無ければ npm startnpm run build を実行します。npm start を動かしていたつもりでも、エラーで途中停止していることがあるので、ターミナルの出力も合わせて見ておきましょう。

プラグインを有効化していない

wp-content/plugins にファイルを置いただけでは、WordPress はプラグインを読み込みません。管理画面の「プラグイン」一覧に生成したプラグインが出ているかを確認し、「有効化」を押します。

一覧に名前すら出てこない場合は、置き場所を間違えている可能性があります。wp-content/plugins/my-block/my-block.php のように、プラグインディレクトリ直下のフォルダーの中にメインの PHP ファイルがある構成かを見直してください。別の場所で create-block を実行して、移動を忘れているというのもよくあるパターンです。

ブロック名が他とぶつかっている

block.jsonname は、サイト全体で一意でなければなりません。create-block の初期値は名前空間が create-block なので、同じ手順で複数のブロックを作って同じスラッグを付けてしまうと、create-block/my-block が重複します。先に登録されたほうが残り、後から登録しようとしたブロックは登録に失敗します。

対策はシンプルで、--namespace オプションで自分のサイトやプロジェクトに合った名前空間を指定することです。すでに作ってしまったあとなら、src/block.jsonname を書き換えてからビルドし直します。名前を変えたブロックを使った投稿がすでにあると、そちらは「このブロックには対応するブロックがありません」という表示になるので、開発の早い段階で決めておくのが安全です。

古いファイルがキャッシュされている

ビルドも有効化も済んでいるのに反映されないときは、ブラウザやサーバー側が古い JavaScript を握っている可能性があります。まずはスーパーリロード(Windows なら Ctrl + Shift + R、Mac なら Command + Shift + R)を試してください。キャッシュ系のプラグインや CDN を使っているなら、そのキャッシュも消しておきます。

それでも直らないときは、ブラウザの開発者ツールでコンソールを開き、JavaScript のエラーが出ていないかを見ます。edit.js の書き間違いでエラーが起きていると、その時点で処理が止まり、registerBlockType() まで到達せずにブロックが登録されないことがあります。エラーメッセージには止まった場所が出ているので、そこを手がかりに src を見直しましょう。

まとめ

カスタムブロックは JSX や ES モジュールを使うためビルドが前提になりますが、npx @wordpress/create-block my-blockwp-content/plugins で実行すれば、@wordpress/scripts を組み込んだプラグイン一式が一度に手に入ります。名前空間やタイトルはコマンドのオプションで指定でき、--variant=dynamic を付ければ render.php を持つ動的ブロックのひな形になります。

編集するのは src の中だけで、npm start の監視ビルドが結果を build に出力し、my-block.phpregister_block_type( __DIR__ . '/build' ) がその block.json を読んでブロックを登録します。エディターの見た目は edit.js、保存される HTML は save.js が決め、どちらも外側の要素に useBlockProps() / useBlockProps.save() の戻り値を渡すのが約束事です。ブロックが一覧に出てこないときは、ビルドの有無・プラグインの有効化・ブロック名の重複・キャッシュの順に確認してください。ここまで動けば、あとは edit.js を書き換えていくだけで自分のブロックを育てていけます。

参考ページ