2026年5月20日
2026年5月20日
WordPressのカスタムブロックをプラグインで作る方法(create-block・block.json・render.php)
ブロックエディター(Gutenberg)のブロックは、プラグインで追加できます。いまの標準的な作り方は、ブロックの情報を block.json に書き、エディターでの見た目を JavaScript(React)で、公開ページの HTML を PHP の render.php で作る方法です。PHP で出力するブロックを「ダイナミックブロック」と呼びます。
この記事では、見出しとボタンを並べた「CTA ブロック」を作ります。手順とコードは、2026年11月時点の WordPress 7.1、Node.js 22、@wordpress/create-block の最新版で、ビルドと表示まで確かめました。
用意するもの
- Node.js と npm(ブロックの JavaScript をビルドするため。この記事は Node.js 22 で確認)
- WordPress が動くローカル環境(作ったプラグインを入れて確かめるため)
なお、WP-CLI の wp scaffold block コマンドは非推奨になっています(wp help scaffold block にも、公式の @wordpress/create-block を使うよう書かれています)。この記事では create-block を使います。
1. create-block で雛形を作る
wp-content/plugins フォルダーで次のコマンドを実行します。
cd wp-content/plugins
npx @wordpress/create-block@latest my-cta --variant dynamic --namespace myplugin --title "CTA Block"
| オプション | 意味 |
|---|---|
my-cta |
プラグインのフォルダー名(ブロック名の後半にもなる) |
--variant dynamic |
PHP(render.php)で出力するダイナミックブロックの雛形にする |
--namespace myplugin |
ブロック名の前半。ブロック名は myplugin/my-cta になる |
--title |
ブロックの表示名 |
必要なパッケージのインストールと最初のビルドまで自動で行われ、次のファイルができます(主なもの)。
my-cta/
├── my-cta.php # プラグイン本体(ブロックを登録する)
├── package.json # ビルドのコマンド
├── src/my-cta/
│ ├── block.json # ブロックの情報
│ ├── index.js # ブロックの登録(JS)
│ ├── edit.js # エディターでの表示と操作
│ ├── render.php # 公開ページの HTML
│ ├── style.scss # 公開ページとエディター共通の CSS
│ ├── editor.scss # エディターだけの CSS
│ └── view.js # 公開ページで動かす JS(使わなければ削除してよい)
└── build/ # ビルド結果(WordPress が読むのはこちら)
編集するのは src の中のファイルです。build はビルドのたびに作り直されます。
2. プラグイン本体でブロックを登録する
生成された my-cta.php は、次のように(ヘッダーとコメントは一部省略) build フォルダーのブロックをまとめて登録します。
<?php
/**
* Plugin Name: CTA Block
* Requires at least: 6.8
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
function myplugin_my_cta_block_init() {
wp_register_block_types_from_metadata_collection( __DIR__ . '/build', __DIR__ . '/build/blocks-manifest.php' );
}
add_action( 'init', 'myplugin_my_cta_block_init' );
wp_register_block_types_from_metadata_collection() は WordPress 6.8 で追加された関数で、ビルド時に作られる blocks-manifest.php を使って、複数のブロックを効率よく登録します。ブロックが1つだけなら、従来の書き方 register_block_type( __DIR__ . '/build/my-cta' ); でも登録できます。
3. block.json で属性と機能を決める
src/my-cta/block.json を次のように書き換えます。
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "myplugin/my-cta",
"version": "0.1.0",
"title": "CTAブロック",
"category": "widgets",
"icon": "megaphone",
"description": "見出しとボタンを並べた、お問い合わせへの誘導ブロック",
"attributes": {
"heading": {
"type": "string",
"default": "お気軽にご相談ください"
},
"buttonText": {
"type": "string",
"default": "お問い合わせ"
},
"buttonUrl": {
"type": "string",
"default": ""
}
},
"supports": {
"html": false,
"align": [ "wide", "full" ],
"color": {
"background": true,
"text": true
},
"spacing": {
"padding": true
}
},
"textdomain": "my-cta",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"render": "file:./render.php"
}
主な項目の意味です。
attributes: ブロックが持つ値です。ここでは見出し・ボタンの文字・リンク先 URL の3つです。値は投稿本文のブロックのコメント(<!-- wp:myplugin/my-cta {...} /-->)に保存されます。既定値のままの属性は保存されず、表示時にdefaultが使われます。supports: WordPress 本体の機能をブロックに付けます。colorを有効にすると、背景色と文字色の設定欄がエディターに出て、選んだ色のクラスやスタイルは次のget_block_wrapper_attributes()が自動で付けます。色の属性を自分で作る必要はありません。render: 公開ページの HTML を作る PHP ファイルです(WordPress 6.1 で追加)。これを指定すると、JavaScript 側で保存用の HTML を作る必要がなくなります。editorScriptなどのfile:./:build内のファイルを指します。ビルド後のファイル名(index.js、style-index.cssなど)で書きます。
view.js を使わない場合は、src/my-cta/view.js を削除し、block.json から viewScript の行も消します。
4. render.php で公開ページの HTML を作る
src/my-cta/render.php を次のように書きます。
<?php
/**
* 公開側の HTML を出力する。
* $attributes(ブロックの属性)、$content(内側のブロック)、$block(WP_Block)が使える。
*/
$heading = $attributes['heading'] ?? '';
$button_text = $attributes['buttonText'] ?? '';
$button_url = esc_url( $attributes['buttonUrl'] ?? '' ); // 危険な URL は空になる
?>
<div <?php echo get_block_wrapper_attributes(); ?>>
<?php if ( '' !== $heading ) : ?>
<p class="wp-block-myplugin-my-cta__heading"><?php echo wp_kses_post( $heading ); ?></p>
<?php endif; ?>
<?php if ( '' !== $button_url && '' !== $button_text ) : ?>
<a class="wp-block-myplugin-my-cta__button" href="<?php echo $button_url; ?>">
<?php echo esc_html( $button_text ); ?>
</a>
<?php endif; ?>
</div>
get_block_wrapper_attributes()は、ブロックのクラス(wp-block-myplugin-my-cta)と、supportsで付けた色や余白、配置のクラス・スタイルをまとめて出力します。外側の要素にはこれを付けます。- 見出しはエディターで太字やリンクを付けられるので
wp_kses_post()で許可されたタグだけを残し、ボタンの文字はesc_html()でエスケープします。 - URL は先に
esc_url()を通します。javascript:で始まるような URL は空になるので、その場合はボタンを出しません。
試しに、背景色に黒・文字色に白を選んだブロックは、次の HTML になりました(空白は整理しています)。
<div class="wp-block-myplugin-my-cta has-text-color has-white-color has-background has-black-background-color">
<p class="wp-block-myplugin-my-cta__heading">お気軽にご相談ください</p>
<a class="wp-block-myplugin-my-cta__button" href="https://example.com/contact/">お問い合わせ</a>
</div>
5. edit.js でエディターの表示と操作を作る
src/my-cta/edit.js を次のように書きます。見出しはブロックの中で直接編集し、ボタンの文字と URL は右側の設定サイドバーで入力します。
import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls, RichText } from '@wordpress/block-editor';
import { PanelBody, TextControl } from '@wordpress/components';
import './editor.scss';
export default function Edit( { attributes, setAttributes } ) {
const { heading, buttonText, buttonUrl } = attributes;
return (
<>
<InspectorControls>
<PanelBody title={ __( 'ボタンの設定', 'my-cta' ) }>
<TextControl
__next40pxDefaultSize
__nextHasNoMarginBottom
label={ __( 'ボタンの文字', 'my-cta' ) }
value={ buttonText }
onChange={ ( value ) => setAttributes( { buttonText: value } ) }
/>
<TextControl
__next40pxDefaultSize
__nextHasNoMarginBottom
type="url"
label={ __( 'ボタンのリンク先 URL', 'my-cta' ) }
value={ buttonUrl }
onChange={ ( value ) => setAttributes( { buttonUrl: value } ) }
/>
</PanelBody>
</InspectorControls>
<div { ...useBlockProps() }>
<RichText
tagName="p"
className="wp-block-myplugin-my-cta__heading"
value={ heading }
onChange={ ( value ) => setAttributes( { heading: value } ) }
placeholder={ __( '見出しを入力', 'my-cta' ) }
/>
<span className="wp-block-myplugin-my-cta__button">
{ buttonText }
</span>
</div>
</>
);
}
useBlockProps()は、エディター側で外側の要素に付ける属性です。PHP のget_block_wrapper_attributes()に当たり、色や配置の設定がエディターの表示にも反映されます。InspectorControlsの中身は、右側の設定サイドバーに表示されます。@wordpress/componentsは、ビルド時に WordPress 本体のwp.componentsを使うように変換されるので、追加でインストールしなくてもビルドできました。
src/my-cta/index.js は雛形のままで使えます。ダイナミックブロックなので save を書かず、保存されるのはブロックのコメント(属性)だけです。
import { registerBlockType } from '@wordpress/blocks';
import './style.scss';
import Edit from './edit';
import metadata from './block.json';
registerBlockType( metadata.name, {
edit: Edit,
} );
6. CSS を書く
src/my-cta/style.scss は公開ページとエディターの両方に読み込まれます。
.wp-block-myplugin-my-cta {
padding: 2rem;
text-align: center;
&__heading {
margin: 0 0 1rem;
font-size: 1.25rem;
font-weight: bold;
}
&__button {
display: inline-block;
padding: 0.75em 1.5em;
border-radius: 4px;
background: #1d2327;
color: #fff;
text-decoration: none;
}
}
エディターだけに付けたい見た目(枠線など)は editor.scss に書きます。
7. ビルドして有効化する
cd my-cta
npm run build # src をビルドして build に出力する
npm start # 開発中: ファイルを保存するたびに自動でビルドし直す
ビルドしたら、「プラグイン」画面で「CTA Block」を有効化します。投稿の編集画面でブロックを追加し、「CTAブロック」を検索すると表示されます。
配布用の ZIP ファイルは npm run plugin-zip で作れます。本番サイトに置くのは my-cta.php と build フォルダーで、node_modules と src は不要です。
WP-CLI で確かめる
# ブロックが登録されているか
wp eval 'var_dump( WP_Block_Type_Registry::get_instance()->is_registered( "myplugin/my-cta" ) );'
# このブロックを使っている投稿・固定ページを探す
wp post list --post_type=post,page --s='wp:myplugin/my-cta' --fields=ID,post_title
うまく表示されないとき
- ブロックが一覧に出ない:
npm run buildを実行したか、build/my-cta/block.jsonがあるかを確かめます。srcだけを編集してビルドしていないと、WordPress には反映されません。 - 公開ページに何も出ない:
block.jsonのrenderがfile:./render.phpになっているか、build/my-cta/render.phpがあるかを確かめます。PHP のエラーはWP_DEBUG_LOGを有効にしてログで確認します。 - 色の設定が反映されない: 外側の要素に
get_block_wrapper_attributes()(PHP)とuseBlockProps()(JS)を付けているか確かめます。 - ページキャッシュ: ダイナミックブロックの出力は表示のたびに PHP で作られますが、キャッシュ系のプラグインを使っていると、ブロックを直しても古い HTML が表示されることがあります。