2026年8月9日

2026年8月9日

WordPressのGutenbergブロック開発入門|create-blockで作る最初のカスタムブロック

Gutenberg(ブロックエディター)用のカスタムブロックは、公式のひな形ツール @wordpress/create-block を使うと、ビルド環境と最小限のブロックを含んだプラグインを数分で用意できます。あとは block.json で設定を書き、edit.js でエディター上の見た目、save.js か render.php で公開ページの出力を作る、という流れです。この記事では、開発環境の準備からひな形の作成、ファイルの役割、属性と設定パネルの追加、静的ブロックと動的ブロックの違い、つまずきやすい「ブロックの検証エラー」まで、最初の1つを作り終えるのに必要なことを順に解説します。

始める前に用意するもの

  • Node.js と npm:ビルドツールが Node.js で動きます。LTS 版を入れておくと無難です。対応バージョンはツールの更新で変わるため(2026年10月現在)、最新の要件は @wordpress/create-block と @wordpress/scripts のドキュメントで確認してください。
  • ローカルの WordPress 環境:Local などのローカル開発ツール、Docker を使う @wordpress/env(wp-env)、ブラウザ上で動く WordPress Playground などから選びます。本番サイトで直接試すのは避けます。
  • JavaScript(ES2015以降)と React の基礎:ブロックのエディター側は React のコンポーネントとして書きます。JSX の書き方と、props で値を受け取る考え方がわかれば始められます。

ひな形を作る

プラグインを置きたいフォルダ(ローカル環境の wp-content/plugins/)で次を実行します。

cd wp-content/plugins
npx @wordpress/create-block@latest my-notice-block
cd my-notice-block
npm start

対話形式で質問されることもありますが、まずは既定値のままで構いません。npm start はファイルの変更を監視して自動でビルドし続けるコマンドです。公開用の最適化したファイルを作るときは npm run build を使います。

管理画面のプラグイン一覧に「My Notice Block」が現れるので有効化し、投稿の編集画面でブロックを追加すると、ひな形のブロックが表示されます。ここまで動けば環境は整っています。

生成されるファイルの役割

生成されるフォルダ構成は create-block のバージョンによって変わりますが、中心になるのは次のファイルです。

  • block.json:ブロックの名前・表示名・カテゴリー・属性・対応機能、読み込むスクリプトやスタイルを書く設定ファイル。PHP 側と JS 側の両方がここを読みます
  • index.js:ブロックを登録する入口。block.json と edit・save を結び付けます
  • edit.js:エディター内での表示と操作
  • save.js:保存時に投稿本文へ書き込む HTML(静的ブロックの場合)
  • style.scss / editor.scss:フロントとエディターの両方に効くスタイルと、エディターだけのスタイル
  • プラグインのメインPHPファイル:init フックでブロックを登録します

src/ の中身を編集すると build/ にビルド結果が出力され、WordPress は build/ 側を読み込みます。build/ を直接編集しても、次のビルドで上書きされます。

PHP 側の登録は、基本的に次の形です(ひな形が複数ブロックをまとめて登録する別の関数を使っている場合もあります)。

<?php
add_action( 'init', function () {
	register_block_type( __DIR__ . '/build' ); // block.json があるフォルダを指定
} );

block.json を書く

お知らせ用の枠を表示するブロックを例に、block.json を整えます。

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "my-plugin/notice",
	"version": "0.1.0",
	"title": "お知らせボックス",
	"category": "text",
	"icon": "info",
	"description": "色付きの枠でお知らせを表示します。",
	"attributes": {
		"message": { "type": "string", "source": "html", "selector": "p" },
		"showIcon": { "type": "boolean", "default": true }
	},
	"supports": {
		"html": false,
		"color": { "background": true, "text": true },
		"spacing": { "padding": true }
	},
	"textdomain": "my-notice-block",
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css"
}
  • name:名前空間/ブロック名 の形で、サイト内で一意にします。公開後に変えると、既存の投稿のブロックが認識されなくなります。
  • apiVersion:新しく作るブロックは 3 にします。エディターが iframe 内で表示される前提の書き方で、WordPress 6.3 以降で使えます。
  • attributes:ブロックが保存するデータです。source と selector を指定すると、値を保存した HTML から読み取ります。指定しない属性は、ブロックのコメント区切りの中に JSON として保存されます。
  • supports:色や余白など、コアが用意する設定を有効にします。自分でコントロールを作らなくても、サイドバーに設定欄が追加されます。
  • editorScript / style など:file:./ はこの block.json からの相対パスです。

edit.js でエディター側を作る

import { __ } from '@wordpress/i18n';
import { useBlockProps, RichText, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, ToggleControl } from '@wordpress/components';

export default function Edit( { attributes, setAttributes } ) {
	const { message, showIcon } = attributes;
	const blockProps = useBlockProps( { className: 'my-notice' } );

	return (
		<>
			<InspectorControls>
				<PanelBody title={ __( '表示設定', 'my-notice-block' ) }>
					<ToggleControl
						label={ __( 'アイコンを表示', 'my-notice-block' ) }
						checked={ showIcon }
						onChange={ ( value ) => setAttributes( { showIcon: value } ) }
					/>
				</PanelBody>
			</InspectorControls>
			<div { ...blockProps }>
				{ showIcon && <span className="my-notice__icon" aria-hidden="true">i</span> }
				<RichText
					tagName="p"
					value={ message }
					onChange={ ( value ) => setAttributes( { message: value } ) }
					placeholder={ __( 'お知らせを入力…', 'my-notice-block' ) }
				/>
			</div>
		</>
	);
}

useBlockProps() が返す値は、ブロックの外枠の要素に展開します。これを忘れると、ブロックを選択できない、supports で有効にした色や余白が反映されない、といった症状が出ます。値の変更は setAttributes() だけで行い、attributes を直接書き換えないことも React の作法として大切です。

静的ブロックと動的ブロック

公開ページの出力の作り方は2通りあります。

静的ブロックは save.js で HTML を返し、その HTML が投稿本文に保存されます。表示時に PHP の処理が要らないので軽く、プラグインを停止しても HTML は残ります。

import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function save( { attributes } ) {
	const { message, showIcon } = attributes;
	return (
		<div { ...useBlockProps.save( { className: 'my-notice' } ) }>
			{ showIcon && <span className="my-notice__icon" aria-hidden="true">i</span> }
			<RichText.Content tagName="p" value={ message } />
		</div>
	);
}

動的ブロックは表示のたびに PHP で HTML を作ります。最新記事の一覧やログイン状態で変わる内容など、保存時点で HTML を決められないものに向いています。block.json に "render": "file:./render.php" を追加し、save は null を返すか省略します。create-block では --variant dynamic を付けると、この形のひな形を作れます。

<?php
// render.php:$attributes・$content・$block が使える
$message = isset( $attributes['message'] ) ? $attributes['message'] : '';
?>
<div <?php echo get_block_wrapper_attributes( array( 'class' => 'my-notice' ) ); ?>>
	<p><?php echo wp_kses_post( $message ); ?></p>
</div>

動的ブロックでは、属性の値を出力する前に esc_html() や wp_kses_post() でエスケープします。属性は投稿を編集できる人なら書き換えられる値なので、信頼できる入力として扱わないようにします。なお動的ブロックで message を HTML から読み取る source 指定は使えないため、その場合は block.json の属性から source と selector を外します。

つまずきやすい点

「ブロックの検証エラー」が出る

静的ブロックの save.js を変更すると、変更前に保存された投稿を開いたときに「このブロックには想定されていないか無効なコンテンツが含まれています」という趣旨のメッセージが出ます(文言はバージョンで異なります)。エディターは保存済みの HTML と、今の save() が返す HTML を比べて、違えば無効と判断するためです。

開発中なら投稿を作り直せば済みますが、公開後は deprecated(以前の save の形を残しておく仕組み)を用意して移行するか、最初から動的ブロックにしておきます。出力の構造が今後変わりそうなブロックは、動的ブロックのほうが運用しやすくなります。

ブロックが一覧に出ない・スタイルが当たらない

可能性の高い順に、npm start または npm run build が実行されていて build/ にファイルがあるか、プラグインが有効か、register_block_type() に渡したパスに block.json があるか、block.json の JSON に構文エラーが無いか、を確認します。ブラウザの開発者ツールのコンソールにエラーが出ていれば、それが手がかりになります。

本番への反映

本番に入れるのは npm run build で作ったファイルです。node_modules はアップロードしません。npm run plugin-zip を使うと配布用の ZIP を作れます。反映前にはサイトのバックアップを取り、ステージング環境で既存の投稿が崩れないことを確認してください。

まとめ

  • npx @wordpress/create-block@latest でひな形を作り、npm start で監視ビルドしながら開発する
  • block.json に名前・属性・supports・読み込むファイルを書き、PHP は register_block_type() で登録する。新規のブロックは apiVersion 3
  • edit.js は useBlockProps() を外枠に展開し、値の変更は setAttributes() で行う
  • 出力は save.js の静的ブロックか、render.php の動的ブロックかを選ぶ。動的ブロックの出力はエスケープする
  • 静的ブロックの save を変えると検証エラーになるため、公開後は deprecated か動的ブロックで対応する

お気軽にご相談ください

お見積りへ お問い合わせへ
▲