2026年5月20日

2026年5月20日

WordPressプラグインでカスタムブロックを作成する方法

はじめに

GutenbergのカスタムブロックはJavaScript(React)またはPHP(Dynamic Block)で作成できます。PHPのDynamic Blockは既存のPHP知識を活かして動的コンテンツをブロックとして提供できます。

症状・原因

  • Gutenbergエディターに独自のブロックを追加したい
  • 最新投稿・カウントダウン・CTAなどの動的コンテンツをブロック化したい
  • block.jsonを使ったモダンなブロック登録方法を知りたい
  • WP-CLIのスキャフォールドでブロックの雛形を生成したい

解決手順

ステップ1:WP-CLIでブロックの雛形を生成する

# カスタムブロックの雛形を自動生成
wp scaffold block my-cta \
  --title="CTAブロック" \
  --category=common \
  --plugin=my-plugin

# 生成されるファイル:
# blocks/my-cta/
# ├── block.json          # ブロックのメタデータ
# ├── index.js            # エディター側のJS
# ├── editor.css          # エディター用CSS
# ├── style.css           # フロントエンド用CSS
# └── render.php          # PHPレンダリング(Dynamic Block)

ステップ2:block.jsonを作成する

{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 3,
    "name": "myplugin/cta-block",
    "version": "1.0.0",
    "title": "CTAブロック",
    "category": "text",
    "description": "コール・トゥ・アクションブロック",
    "supports": {
        "html": false,
        "align": ["wide", "full"]
    },
    "attributes": {
        "heading": {
            "type": "string",
            "default": "お問い合わせはこちら"
        },
        "buttonText": {
            "type": "string",
            "default": "お問い合わせ"
        },
        "buttonUrl": {
            "type": "string",
            "default": "/contact/"
        },
        "backgroundColor": {
            "type": "string",
            "default": "#0073aa"
        }
    },
    "textdomain": "myplugin",
    "editorScript": "file:./index.js",
    "editorStyle": "file:./editor.css",
    "style": "file:./style.css",
    "render": "file:./render.php"
}

ステップ3:PHPでDynamic Blockを登録する

// プラグインファイル
add_action('init', function(): void {
    // block.json からブロックを登録(推奨)
    register_block_type(__DIR__ . '/blocks/cta-block');
});
// blocks/cta-block/render.php — ブロックのHTML出力
// $attributes: block.jsonで定義した属性値
// $content: インナーブロックのコンテンツ
// $block: WP_Block インスタンス

$heading    = esc_html($attributes['heading'] ?? 'お問い合わせはこちら');
$btn_text   = esc_html($attributes['buttonText'] ?? 'お問い合わせ');
$btn_url    = esc_url($attributes['buttonUrl'] ?? '/contact/');
$bg_color   = esc_attr($attributes['backgroundColor'] ?? '#0073aa');
$wrapper    = get_block_wrapper_attributes(['style' => "background-color:{$bg_color}"]);
?>
<div <?php echo $wrapper; ?>>
    <h2 class="cta-heading"><?php echo $heading; ?></h2>
    <a href="<?php echo $btn_url; ?>" class="cta-button"><?php echo $btn_text; ?></a>
</div>

ステップ4:JavaScriptでエディター側のUIを作る

// blocks/cta-block/index.js
import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, InspectorControls, RichText } from '@wordpress/block-editor';
import { PanelBody, TextControl, ColorPicker } from '@wordpress/components';
import metadata from './block.json';

registerBlockType(metadata.name, {
    edit({ attributes, setAttributes }) {
        const { heading, buttonText, buttonUrl, backgroundColor } = attributes;
        const blockProps = useBlockProps({
            style: { backgroundColor }
        });

        return (
            <>
                <InspectorControls>
                    <PanelBody title="ボタン設定">
                        <TextControl label="ボタンURL" value={buttonUrl}
                            onChange={v => setAttributes({ buttonUrl: v })} />
                        <ColorPicker color={backgroundColor}
                            onChange={v => setAttributes({ backgroundColor: v })} />
                    </PanelBody>
                </InspectorControls>
                <div {...blockProps}>
                    <RichText tagName="h2" value={heading}
                        onChange={v => setAttributes({ heading: v })}
                        placeholder="見出しを入力..." />
                    <RichText tagName="a" value={buttonText}
                        onChange={v => setAttributes({ buttonText: v })}
                        placeholder="ボタンテキスト..." />
                </div>
            </>
        );
    },
    save: () => null, // Dynamic Blockはsaveでnullを返す
});

ステップ5:WP-CLIでブロックを確認する

# 登録済みブロックを確認
wp eval "print_r(array_keys(WP_Block_Type_Registry::get_instance()->get_all_registered()));" \
  | grep myplugin

# ブロックのメタデータを確認
wp eval "var_dump(WP_Block_Type_Registry::get_instance()->get_registered('myplugin/cta-block'));"

# ブロックを使用している投稿を検索
wp post list --format=ids | xargs -I{} wp post get {} --field=post_content | \
  grep -l 'wp:myplugin/cta-block'

ステップ6:ビルド環境を整える

# @wordpress/scripts を使ったビルド環境
npm init -y
npm install --save-dev @wordpress/scripts

# package.json に追加
# "scripts": {
#   "build": "wp-scripts build",
#   "start": "wp-scripts start"
# }

npm run build   # 本番用ビルド(src/ → build/)
npm run start   # 開発サーバー起動(ホットリロード)

注意事項

  • Dynamic Block(save: () => null)はサーバーサイドでレンダリングするため、キャッシュに注意してください
  • block.json"render": "file:./render.php" を使うとJSのsave関数が不要になります(WordPress 6.1以降)
  • get_block_wrapper_attributes() を使うと classNamestyle 属性をGutenbergから自動適用できます

まとめ

block.json でブロックのメタデータを定義し、register_block_type(__DIR__ . '/blocks/cta-block') で登録します。PHPの render.php でDynamic Blockとして実装すると、React不要でサーバーサイドの動的コンテンツをGutenbergブロック化できます。

お気軽にご相談ください

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