初心者向けWordPress Gutenbergブロック開発入門【自作ブロックの作り方】

PHP

はじめに

WordPressでは、記事やページの編集体験を大きく変えた「Gutenberg(グーテンベルク)ブロックエディタ」が標準機能として採用されています。
これにより、見出し・画像・ボタンなどの要素を「ブロック」として直感的に配置・編集できるようになりました。

Gutenberg(ブロックエディタ)とは何か

Gutenbergは、WordPress 5.0以降で導入された新しいエディタで、ページを「ブロック(Block)」単位で構築する仕組みです。
見出しブロック、画像ブロック、ボタンブロックなどをドラッグ&ドロップで自由に組み合わせることができ、コーディングなしでもデザイン性の高いページを作成できます。
いわば「ノーコードでレイアウトを作るための編集画面」と言えます。

旧エディタ(Classic Editor)との違い

従来のClassic Editorは、1つの大きなテキストエリアにHTMLやショートコードを書いて編集するスタイルでした。
一方、Gutenbergではコンテンツを部品化(ブロック化)して管理するため、視覚的な操作が可能で、より直感的に編集が行えます。
その結果、デザイナーや非エンジニアでも見たままの形でページを構築できる点が大きな違いです。

なぜオリジナルブロックを作る必要があるのか

標準ブロックでも多くのことができますが、企業サイトやメディア運営では「自社デザインを統一したい」「頻繁に使うレイアウトを簡単に呼び出したい」というニーズがあります。
そうした場合に便利なのが「オリジナルGutenbergブロック」の開発です。

たとえば以下のようなケースで役立ちます。

  • サイト全体で統一したデザインの「ボタン」や「カード」を使いたい
  • 複数の投稿で繰り返し使う「お知らせ」「CTA」などをテンプレート化したい
  • クライアントやライターが簡単にページを編集できるようにしたい

こうした目的で独自ブロックを作成することで、デザインの統一性・運用効率・再利用性を高めることができます。

開発環境の準備

Gutenbergブロックの開発を始めるには、次の2つが用意できていれば問題ありません。

  • WordPress 5.0 以降が導入されていること
  • Node.js と npm がインストールされていること

私は、WordPress は Docker で構築し、Node.js はローカル環境に導入しています。
この組み合わせで問題なくブロック開発が可能です。

Docker構成例

以下の docker-compose.yml で WordPress 環境を立ち上げています。
MariaDB・MailHog(メールテスト用)も同時に起動するシンプルな構成です。

services:
  db:
    image: mariadb:11.3
    command: >
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
    environment:
      MARIADB_DATABASE: wordpress
      MARIADB_USER: wordpress
      MARIADB_PASSWORD: wordpress
      MARIADB_ROOT_PASSWORD: root
    volumes:
      - ./db_data:/var/lib/mysql

  wordpress:
    image: wordpress:php8.2-apache
    depends_on:
      - db
      - mailhog 
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_CONFIG_EXTRA: |
        define( 'WP_ENVIRONMENT_TYPE', 'local' );
    volumes:
      - ./wordpress_data:/var/www/html
  mailhog:
    image: mailhog/mailhog:v1.0.1
    ports:
      - "8025:8025"
      - "1025:1025"
  • WordPress にアクセスするURLは → http://localhost:8080
  • MailHog の管理画面は → http://localhost:8025
  • WordPress のデータは ./wordpress_data に永続化
  • プラグインは ./wordpress_data/wp-content/plugins/ 配下に配置します

この環境であれば、ローカルの Node.js を使って @wordpress/scripts を実行し、
Gutenberg ブロックをビルド・開発することが可能です。

最小構成の Gutenberg ブロックを作る

ここでは、「Hello World」ブロックを例に、Gutenberg ブロック開発の最小構成を紹介します。
実際に動作するブロックを作りながら、基本構造と仕組みを理解していきましょう。

フォルダ構成

まず、WordPress のプラグインフォルダに以下のような構成を作ります。

/wp-content/plugins/my-gutenberg-block/
├─ block.json              ← ブロック定義ファイル
├─package.json             ← ブロック定義ファイル
├─ src/
│  └─ index.js             ← ブロック本体(エントリーポイント)
├─ build/                  ← ビルド結果(自動生成)
└─ my-gutenberg-block.php  ← プラグイン本体(PHP)

src 内のファイルを @wordpress/scripts が自動でビルドし、
build/ に出力します。WordPress はこの出力を読み込んでブロックを表示します。

npm 初期化

cd ./wordpress_data/wp-content/plugins/my-gutenberg-block
npm init -y

これで package.json が生成されます。

Gutenberg 開発ツールをインストール

npm install @wordpress/scripts --save-dev

package.json にスクリプトを追加

エディタで開いて、以下のように追記してください

{
  "name": "my-gutenberg-block",
  "version": "1.0.0",
  "private": true,
  "devDependencies": {
    "@wordpress/scripts": "^30.0.0"
  },
  "scripts": {
    "start": "wp-scripts start",
    "build": "wp-scripts build"
  }
}

block.json(ブロックの定義ファイル)

Gutenbergブロックの設定を行うファイルです。
ブロック名・タイトル・カテゴリ・読み込むスクリプトを記述します。

{
  "apiVersion": 3,
  "name": "myplugin/hello-block",
  "title": "Hello Block",
  "category": "widgets",
  "icon": "smiley",
  "description": "最小構成の Hello World ブロック",
  "editorScript": "file:./build/index.js"
}
  • "name" は「namespace/block-name」形式(例:myplugin/hello-block
  • "editorScript" はエディタで読み込む JS(build/ の出力)
  • WordPress がこのファイルを自動で認識し、アセットを登録してくれます

src/index.js(エントリーポイント)

@wordpress/blocksregisterBlockType() を使ってブロックを登録します。
edit() がエディタ画面での見た目、save() が保存後の表示内容です。

import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';

registerBlockType('myplugin/hello-block', {
  title: __('Hello Block', 'myplugin'),
  icon: 'smiley',
  category: 'widgets',

  edit() {
    const blockProps = useBlockProps();
    return <p {...blockProps}>Hello from the editor!</p>;
  },

  save() {
    const blockProps = useBlockProps.save();
    return <p {...blockProps}>Hello from the frontend!</p>;
  },
});
  • JSX が使えるのは @wordpress/scripts が Babel を内蔵しているため
  • edit() はリアルタイムで編集画面に反映される
  • save() は保存時に静的HTMLとして出力される

my-gutenberg-block.php(プラグイン本体)

WordPress にこのブロックを登録するためのプラグインファイルです。
register_block_type() にプラグインのディレクトリを渡すだけで、
block.json を自動的に読み取ってくれます。

<?php
/**
 * Plugin Name: My Gutenberg Block
 * Description: 最小構成の Gutenberg ブロック
 * Version: 1.0.0
 * Author: Your Name
 */

defined( 'ABSPATH' ) || exit;

add_action( 'init', function () {
    register_block_type( __DIR__ );
});

ビルドと有効化

準備ができたら、次のコマンドでビルドします。

npm run build

これで build/ フォルダが自動生成され、WordPress に認識されるようになります。
その後、管理画面にアクセスして以下の手順を行いましょう。

  1. 「プラグイン」メニューを開く
  2. 「My Gutenberg Block」を有効化
  3. 投稿や固定ページを開いて「Hello Block」を追加

すると、エディタ上に
“Hello from the editor!” が表示されます。


プレビューまたは公開ページでは
“Hello from the frontend!” が確認できます

ブロックのカスタマイズ

ここからは、ブロックに「テキスト編集」「背景色・文字色の変更」など、
実際に編集できる機能を追加していきます。

attributes でデータを持たせる

Gutenberg では、ブロックが持つデータ(文字や設定値)を attributes(属性) として管理します。
ブロックが保存されるとき、attributes の内容は HTML に埋め込まれます。

たとえば「タイトルテキスト」をブロック内に保存するには、
block.json に以下のように追記します。

{
  "apiVersion": 3,
  "name": "myplugin/custom-block",
  "title": "Custom Block",
  "category": "widgets",
  "icon": "smiley",
  "description": "編集可能なテキストを持つブロック",
  "attributes": {
    "content": {
      "type": "string",
      "source": "html",
      "selector": "p"
    }
  },
  "editorScript": "file:./build/index.js"
}
  • "content" は属性名(自由に命名可)
  • "type": "string" は文字列データを表す
  • "selector": "p"<p> タグの内容を保存するという意味です

<RichText> コンポーネントで編集可能にする

Gutenberg の <RichText> は、ブロック内で文字を直接編集できる便利なコンポーネントです。
edit() 内で入力内容を反映し、save() 側で HTML に出力します。

import { registerBlockType } from '@wordpress/blocks';
import { RichText } from '@wordpress/block-editor';

registerBlockType('myplugin/custom-block', {
  title: 'Custom Block',
  icon: 'smiley',
  category: 'widgets',
  attributes: {
    content: { type: 'string', source: 'html', selector: 'p' },
  },

  // 編集画面
  edit({ attributes, setAttributes }) {
    const { content } = attributes;
    return (
      <RichText
        tagName="p"
        value={content}
        onChange={(newContent) => setAttributes({ content: newContent })}
        placeholder="ここにテキストを入力..."
      />
    );
  },

  // 保存(フロント側)
  save({ attributes }) {
    return <RichText.Content tagName="p" value={attributes.content} />;
  },
});

背景色や文字色の変更(InspectorControls)

InspectorControls を使うと、ブロックの右サイドバーに設定パネルを追加できます。
これで色の変更などが可能になります。

import { registerBlockType } from '@wordpress/blocks';
import { RichText, InspectorControls, PanelColorSettings } from '@wordpress/block-editor';
import { PanelBody } from '@wordpress/components';

registerBlockType('myplugin/styled-block', {
  title: 'Styled Block',
  icon: 'admin-customizer',
  category: 'widgets',
  attributes: {
    content: { type: 'string', source: 'html', selector: 'p' },
    textColor: { type: 'string', default: '#000000' },
    bgColor: { type: 'string', default: '#ffffff' },
  },

  edit({ attributes, setAttributes }) {
    const { content, textColor, bgColor } = attributes;

    return (
      <>
        {/* 設定パネル */}
        <InspectorControls>
          <PanelBody title="色設定" initialOpen={true}>
            <PanelColorSettings
              title="色設定"
              colorSettings={[
                {
                  label: '文字色',
                  value: textColor,
                  onChange: (color) => setAttributes({ textColor: color }),
                },
                {
                  label: '背景色',
                  value: bgColor,
                  onChange: (color) => setAttributes({ bgColor: color }),
                },
              ]}
            />
          </PanelBody>
        </InspectorControls>

        {/* 編集画面 */}
        <RichText
          tagName="p"
          value={content}
          onChange={(newContent) => setAttributes({ content: newContent })}
          placeholder="テキストを入力..."
          style={{ color: textColor, backgroundColor: bgColor, padding: '10px' }}
        />
      </>
    );
  },

  save({ attributes }) {
    const { content, textColor, bgColor } = attributes;
    return (
      <RichText.Content
        tagName="p"
        value={content}
        style={{ color: textColor, backgroundColor: bgColor, padding: '10px' }}
      />
    );
  },
});
  • InspectorControls:サイドパネルを追加するためのラッパー
  • PanelColorSettings:WordPress 標準のカラーピッカー
  • attributes に色の値を保存することで、リロード後も設定を保持

アイコンやメディアを追加する例

さらに、画像やアイコンをブロック内に追加したい場合は
MediaUploadIcon コンポーネントを使います。

import { registerBlockType } from '@wordpress/blocks';   //  必須
import { MediaUpload, MediaUploadCheck, RichText, useBlockProps } from '@wordpress/block-editor';
import { Button } from '@wordpress/components';

registerBlockType('myplugin/image-block', {
  title: 'Image Block',
  icon: 'format-image',
  category: 'widgets',
  attributes: {
    content: { type: 'string', source: 'html', selector: 'p' },
    imageUrl: { type: 'string', default: '' },
  },

  edit({ attributes, setAttributes }) {
    const { content, imageUrl } = attributes;
    const blockProps = useBlockProps(); // 選択/削除の安定化

    return (
      <div {...blockProps}>
        <MediaUploadCheck>
          <MediaUpload
            onSelect={(media) => setAttributes({ imageUrl: media?.sizes?.full?.url || media.url })}
            allowedTypes={['image']}
            render={({ open }) => (
              <Button onClick={open} variant="secondary">
                {imageUrl ? '画像を変更' : '画像を選択'}
              </Button>
            )}
          />
        </MediaUploadCheck>

        {imageUrl && <img src={imageUrl} alt="" style={{ width: '100%', marginTop: 10 }} />}

        <RichText
          tagName="p"
          value={content}
          onChange={(v) => setAttributes({ content: v })}
          placeholder="キャプションを入力..."
        />
      </div>
    );
  },

  save({ attributes }) {
    const { content, imageUrl } = attributes;
    const blockProps = useBlockProps.save();

    return (
      <div {...blockProps}>
        {imageUrl && <img src={imageUrl} alt="" />}
        <RichText.Content tagName="p" value={content} />
      </div>
    );
  },
});
  • MediaUpload:画像アップロード・選択を行うコンポーネント
  • MediaUploadCheck:権限チェック(ログイン中ユーザーのみ使用可)
  • allowedTypes で画像のみ選択可能に設定

スタイル(CSS)の適用

エディタ用とフロント用の違い

  • エディタ用(Editor Styles):ブロックエディタ内の見た目だけに効く。編集体験を整える目的。
  • フロント用(Front Styles):公開ページでの見た目に効く。サイト訪問者が見るデザイン。

同じ見た目にしたい場合は両方へ同一スタイルを配布、編集時だけ補助的な枠線/余白を足す、が定石。

editor.css と style.css の使い分け

my-gutenberg-block/
├─ src/
│  ├─ index.js         ← ブロック登録のJS
│  ├─ style.scss       ← フロント & エディタ共通
│  └─ editor.scss      ← エディタ専用(編集画面だけ)
├─ build/
├─ block.json
└─ my-gutenberg-block.php
  • src/style.scss → ビルド後 build/style-index.css(フロントにも読ませる)
  • src/editor.scss → ビルド後 build/index.css(エディタ専用に読ませる)

block.json で紐づける

{
  "apiVersion": 3,
  "name": "myplugin/image-block",
  "title": "Image Block",
  "category": "media",
  "icon": "format-image",
  "description": "画像 + キャプションのシンプルなブロック",
  "editorScript": "file:./build/index.js",
  "style": "file:./build/style-index.css", // フロント & エディタ共通
  "editorStyle": "file:./build/index.css", // エディタ専用
  "attributes": {
    "content": { "type": "string", "source": "html", "selector": "p" },
    "imageUrl": { "type": "string", "default": "" }
  },
  "supports": { "html": false }
}

src/index.js でSCSSをインポート(@wordpress/scriptsが束ねてくれます)

import './style.scss';
import './editor.scss';
// … registerBlockType(...)

反映されないときは npm run build(または npm run start)を実行。

典型スタイル例

src/style.scss(公開ページにも効く共通見た目)

.my-image-block {
  img {
    display: block;
    width: 100%;
    border-radius: 12px;
  }
  p {
    margin-top: .5rem;
    color: #333;
    line-height: 1.6;
  }
}

src/editor.scss(編集画面だけの補助)

.my-image-block {
  outline: 1px dashed #bbb;
  padding: .5rem;
  background: #fafafa;
}

src/index.js

import { registerBlockType } from '@wordpress/blocks';
import { MediaUpload, MediaUploadCheck, RichText, useBlockProps } from '@wordpress/block-editor';
import { Button } from '@wordpress/components';

// スタイル読込(@wordpress/scripts が SASS→CSS→build に束ねる)
import './style.scss';   // -> build/style-index.css(フロント & エディタ)
import './editor.scss';  // -> build/index.css(エディタのみ)

registerBlockType('myplugin/image-block', {
  title: 'Image Block',
  icon: 'format-image',
  category: 'media',
  attributes: {
    content: { type: 'string', source: 'html', selector: 'p' },
    imageUrl: { type: 'string', default: '' },
  },

  edit({ attributes, setAttributes }) {
    const { content, imageUrl } = attributes;
    // ルート要素にクラスを付与(スタイルが当てやすくなる)
    const blockProps = useBlockProps({ className: 'my-image-block' });

    return (
      <div {...blockProps}>
        <MediaUploadCheck>
          <MediaUpload
            onSelect={(m) => setAttributes({ imageUrl: m?.sizes?.full?.url || m.url })}
            allowedTypes={['image']}
            render={({ open }) => (
              <Button onClick={open} variant="secondary">
                {imageUrl ? '画像を変更' : '画像を選択'}
              </Button>
            )}
          />
        </MediaUploadCheck>

        {imageUrl && <img src={imageUrl} alt="" style={{ marginTop: 10 }} />}

        <RichText
          tagName="p"
          value={content}
          onChange={(v) => setAttributes({ content: v })}
          placeholder="キャプションを入力..."
        />
      </div>
    );
  },

  save({ attributes }) {
    const { content, imageUrl } = attributes;
    const blockProps = useBlockProps.save({ className: 'my-image-block' });

    return (
      <div {...blockProps}>
        {imageUrl && <img src={imageUrl} alt="" />}
        <RichText.Content tagName="p" value={content} />
      </div>
    );
  },
});

ルート要素に useBlockProps({ className: 'my-image-block' }) を付与しておくと当てやすいです。

  • 編集画面:点線アウトライン+薄い背景+余白が効いている
  • 公開ページ:点線や補助背景は出ず、丸角画像+段落スタイルのみ

再利用性を高めるベストプラクティス

再利用ブロック(Reusable Block)との違い

WordPress には「再利用ブロック(Reusable Block)」という機能がありますが、
これは 編集画面上でユーザーが作成・保存するもの であり、
開発者がコードとして再利用するものではありません

項目再利用ブロックカスタムブロック(コード)
作成方法エディタ上で保存JS / PHP で定義
目的同じ内容を複数記事で共有同じデザイン・機能を複数箇所で再利用
更新方法記事に挿入後も同期更新されるプラグイン更新で全体反映
管理場所データベース(wp_block)ファイル(プラグイン内)

つまり、開発者目線で「再利用しやすい構造にしたい」なら、
共通ロジックやUIをモジュール化することが重要です。

複数ブロックをまとめた「ブロックパターン」の考え方

ブロックパターン(Block Pattern)とは、
複数のブロックを組み合わせて1つのテンプレートとして再利用できる仕組みです。

たとえば以下のように「画像 + 見出し + ボタン」を1パターンにまとめることで、
ユーザーが1クリックでレイアウトを呼び出せるようになります。

register_block_pattern(
  'myplugin/hero-section',
  [
    'title'       => 'ヒーローセクション',
    'description' => '大きな見出しとボタン付きのレイアウト',
    'content'     => '
      <!-- wp:image {"sizeSlug":"large"} /-->
      <!-- wp:heading -->ようこそ!<!-- /wp:heading -->
      <!-- wp:buttons -->
        <!-- wp:button {"backgroundColor":"vivid-cyan-blue"} -->
          <a class="wp-block-button__link">詳細を見る</a>
        <!-- /wp:button -->
      <!-- /wp:buttons -->
    ',
  ]
);
  • パターンは PHP 側で register_block_pattern() で登録。
  • JSONファイルによる登録も可能(WordPress 6.0以降)。
  • デザイナーがレイアウトを再利用したい場合に最適。

複数ブロックを1プラグイン内に整理するディレクトリ構造例

複数のブロックを1つのプラグインにまとめたい場合、
以下のようにディレクトリを分けて整理するのがベストプラクティスです。

my-gutenberg-block/
├─ blocks/
│  ├─ image-block/
│  │  ├─ block.json
│  │  ├─ src/
│  │  │  ├─ index.js
│  │  │  ├─ style.scss
│  │  │  └─ editor.scss
│  │  └─ build/
│  ├─ callout-block/
│  │  ├─ block.json
│  │  ├─ src/
│  │  │  ├─ index.js
│  │  │  ├─ style.scss
│  │  │  └─ editor.scss
│  │  └─ build/
│  └─ ...
├─ patterns/
│  ├─ hero-section.php
│  ├─ pricing-table.php
│  └─ ...
├─ package.json
├─ my-gutenberg-block.php
└─ webpack.config.js(任意)
  • blocks/ … 各ブロックをフォルダ単位で分割。
    block.json に依存関係・スタイルを記載すれば自動登録可能。
  • patterns/ … ブロックパターンをまとめる(登録コード or JSON)。
  • my-gutenberg-block.phpregister_block_type() で一括登録するスクリプト。

複数ブロックをまとめて登録するコード例

<?php
/**
 * Plugin Name: My Gutenberg Block Collection
 * Description: 複数のオリジナルブロックをまとめたコレクション
 * Version: 1.0.0
 */

defined('ABSPATH') || exit;

// blocksディレクトリ内のblock.jsonをすべて登録
add_action('init', function () {
  $dir = __DIR__ . '/blocks';
  foreach (glob("$dir/*/block.json") as $file) {
    register_block_type(dirname($file));
  }

  // パターン登録
  foreach (glob(__DIR__ . '/patterns/*.php') as $pattern) {
    require_once $pattern;
  }
});

こうしておくことで、新しいブロックを blocks/ に追加するだけで
自動的に認識・登録されるため、長期的にメンテナンスしやすい構造になります。

オリジナルデザインブロックを作成

block.json

{
  "apiVersion": 3,
  "name": "myplugin/card-block",
  "title": "Simple Card",
  "category": "design",
  "icon": "index-card",
  "description": "タイトル・画像・説明文の3要素をもつシンプルなカード",
  "editorScript": "file:./build/index.js",
  "style": "file:./build/style-index.css",
  "editorStyle": "file:./build/index.css",
  "attributes": {
    "title":   { "type": "string", "source": "html", "selector": "h3" },
    "content": { "type": "string", "source": "html", "selector": "p"  },
    "imageId": { "type": "number" },
    "imageUrl":{ "type": "string", "default": "" }
  },
  "supports": { "html": false }
}

my-gutenberg-block.php

<?php
/**
 * Plugin Name: My Gutenberg Block
 * Description: シンプルカードのオリジナルブロック
 * Version: 1.0.0
 */
defined('ABSPATH') || exit;

add_action('init', function () {
  register_block_type(__DIR__); // block.json 基準でJS/CSSも自動登録
});

src/style.scss(フロント & エディタ共通)

.my-card {
  border: 1px solid #e5e7eb; /* slate-200 */
  border-radius: 14px;
  background: #fff;
  overflow: hidden;

  .my-card__image {
    display: block;
    width: 100%;
    aspect-ratio: 16/9;
    object-fit: cover;
  }

  .my-card__body {
    padding: 12px 14px;
  }

  h3 {
    margin: 0 0 6px 0;
    font-size: 1.05rem;
    line-height: 1.3;
    color: #0f172a; /* slate-900 */
  }

  p {
    margin: 0;
    color: #475569; /* slate-600 */
    line-height: 1.6;
  }
}

src/editor.scss(エディタ専用)

/* 編集時だけの補助線・余白 */
.my-card {
  outline: 1px dashed #cbd5e1; /* slate-300 */
}
.wp-block[data-type="myplugin/card-block"] .components-placeholder {
  margin: 8px 14px;
}

src/index.js(編集&保存ロジック)

import { registerBlockType } from '@wordpress/blocks';
import { MediaUpload, MediaUploadCheck, RichText, useBlockProps } from '@wordpress/block-editor';
import { Button } from '@wordpress/components';

import './style.scss';
import './editor.scss';

registerBlockType('myplugin/card-block', {
  title: 'Simple Card',
  icon: 'index-card',
  category: 'design',
  attributes: {
    title: { type: 'string', source: 'html', selector: 'h3' },
    content: { type: 'string', source: 'html', selector: 'p' },
    imageId: { type: 'number' },
    imageUrl: { type: 'string', default: '' },
  },

  edit({ attributes, setAttributes }) {
    const { title, content, imageId, imageUrl } = attributes;
    const blockProps = useBlockProps({ className: 'my-card' });

    return (
      <div {...blockProps}>
        {/* 画像 */}
        <div>
          {imageUrl ? (
            <img className="my-card__image" src={imageUrl} alt="" />
          ) : null}

          <MediaUploadCheck>
            <MediaUpload
              value={imageId}
              onSelect={(m) =>
                setAttributes({
                  imageId: m.id,
                  imageUrl: m?.sizes?.large?.url || m?.sizes?.full?.url || m.url,
                })
              }
              allowedTypes={['image']}
              render={({ open }) => (
                <div className="components-placeholder is-large">
                  <Button onClick={open} variant="secondary">
                    {imageUrl ? '画像を変更' : '画像を選択'}
                  </Button>
                  {imageUrl && (
                    <Button
                      onClick={() => setAttributes({ imageId: undefined, imageUrl: '' })}
                      variant="secondary"
                      style={{ marginLeft: 8 }}
                    >
                      画像をクリア
                    </Button>
                  )}
                </div>
              )}
            />
          </MediaUploadCheck>
        </div>

        {/* 本文 */}
        <div className="my-card__body">
          <RichText
            tagName="h3"
            value={title}
            onChange={(v) => setAttributes({ title: v })}
            placeholder="タイトルを入力…"
          />
          <RichText
            tagName="p"
            value={content}
            onChange={(v) => setAttributes({ content: v })}
            placeholder="説明文を入力…"
          />
        </div>
      </div>
    );
  },

  save({ attributes }) {
    const { title, content, imageUrl } = attributes;
    const blockProps = useBlockProps.save({ className: 'my-card' });

    return (
      <div {...blockProps}>
        {imageUrl && <img className="my-card__image" src={imageUrl} alt="" />}
        <div className="my-card__body">
          <RichText.Content tagName="h3" value={title} />
          <RichText.Content tagName="p" value={content} />
        </div>
      </div>
    );
  },
});

エディタで編集 → フロントへ反映の流れ

  1. 配置&ビルド
    上記ファイルを配置 → プラグイン直下で npm run build
  2. 有効化
    WP 管理画面 → プラグイン → My Gutenberg Block を有効化
  3. 編集(エディタ)
    • 「+」から Simple Card を追加
    • 「画像を選択」でアップロード or ライブラリから選択
    • タイトルと説明文を入力(RichText
  4. 保存/プレビュー
    • 保存すると、imageUrl/h3/p静的HTML として書き出されます
    • フロントでは style.scss の見た目だけが効き、editor.scss の補助線は表示されません

まとめ

Gutenbergブロックは、独自ブロック/パターン化/スタイル分離(editor用とfront用)で“統一デザイン×編集しやすさ×再利用性”を実現できます。
開発は block.jsonregisterBlockType@wordpress/scripts を核に、attributesRichTextInspectorControlsMediaUploadで実用機能を段階的に拡張します。構成は blocks/patterns/ に整理し、自動登録&ビルドで長期運用を楽にしましょう。

本記事が参考になったら幸いです。

コメント

タイトルとURLをコピーしました