mcpField
W
wp-block-development

wp-block-development

github.com/jorgerosal開発11360 回インストール21 週間前に更新
リポジトリ

wp-block-development について

WordPress ブロックエディター開発向けのコードレビュースキルで、PHP と JavaScript/React の実装を確認します。ファイル、行番号、重大度ごとに問題を整理し、BAD/GOOD のコード例を示します。

主な機能

  1. 01block.json スキーマと属性の検証
  2. 02React エディターコンポーネントの確認
  3. 03PHP サーバーサイドレンダリングの監査
  4. 04ブロックの廃止と移行の確認
  5. 05Interactivity API の利用確認
  6. 06重大度別のレビュー報告

活用シーン

  1. 01単一・複数ブロックプラグインのレビュー
  2. 02ブロック検証エラーの調査
  3. 03動的ブロックのレンダリング確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jorgerosal/wordpress-skills --skill wp-block-development

インストール後、Claude Code で/wp-block-developmentを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
block-json-guide.md
dynamic-blocks-guide.md
editor-patterns.md
interactivity-api-guide.md

詳細

WordPress ブロック開発レビュースキル

概要

WordPress 6.x 以降のブロックエディター(Gutenberg)向けに、体系的なブロック開発レビューを行います。基本原則: WordPress のブロックは、エディター用の React コンポーネント(edit 関数)と、フロントエンド用の静的 HTML(save 関数)またはサーバーサイド PHP(render_callback/render ファイル)による二重アーキテクチャのパターンに従います。block.json が信頼できる唯一の情報源です。レビューでは、block.json のスキーマ、エディターのパターン(React/JSX)、サーバーサイドレンダリング(PHP)、属性の処理、非推奨機能の管理、Interactivity API の使用状況を検証します。検出事項はファイルごとにまとめ(実際のパスに基づき、PHP ファイルと JS/JSX ファイルを混在させて記載)、行番号、重大度ラベル(CRITICAL/WARNING/INFO)、BAD/GOOD のコード例を示します。

注: このスキルでは、PHP と JavaScript/React の両方のコードをレビューします。PHP は WordPress PHP Coding Standards(括弧内にはスペース、[] ではなく array()、Yoda 条件式)に従います。JavaScript/JSX は WordPress JS coding standards(タブによるインデント、JSDoc コメント、変数/関数には camelCase、コンポーネントには PascalCase)に従います。

使用する場面

次の場合に使用します:

  • ブロックプラグインのコードレビュー(単一ブロック、複数ブロック、ブロックライブラリ)
  • block.json のスキーマ検証とフィールド確認
  • エディターコンポーネントのレビュー(edit/save 関数、React/JSX のパターン)
  • レンダーコールバックまたはレンダーファイルの監査(サーバーサイド PHP)
  • InnerBlocks パターンのレビュー(入れ子のブロック、テンプレート、templateLock)
  • ブロックの非推奨機能の確認(save 関数の移行)
  • Interactivity API ディレクティブのレビュー(WP 6.5 以降のフロントエンド操作)
  • ブロック属性スキーマの検証(type、source、selector、default)
  • @wordpress/scripts のビルド設定の確認
  • ブロックの検証エラーの調査
  • useBlockProps、RichText、InspectorControls、BlockControls の使用状況

次の場合には使用しないでください:

  • theme.json の設定(利用可能な場合は wp-theme-development を使用)
  • 一般的な React アプリケーションのレビュー(これはブロックエディター専用です)
  • WooCommerce ブロックの拡張(利用可能な場合は wp-woocommerce-dev を使用)
  • セキュリティのみの監査(包括的なセキュリティ分析には wp-security-review を使用)
  • プラグインアーキテクチャの監査(プラグイン構造の確認には wp-plugin-development を使用)
  • パフォーマンスのみの監査(wp-performance-review を使用)

コードレビューのワークフロー

体系的なブロックレビューを行うため、次の 7 つの手順に従います。

  1. ブロックの種類とコンテキストを特定する

    • 単一ブロックのプラグイン → block.json が 1 つで、シンプルな構成
    • 複数ブロックのプラグイン → src/block-one/、src/block-two/ に複数のブロック
    • ブロックライブラリ/コレクション → パッケージとして公開されるため、名前空間が重要
    • テーマブロック → functions.php で登録され、読み込みコンテキストが異なる
  2. block.json のスキーマを検証する(BLK-02、BLK-06、BLK-08、BLK-10)

    • apiVersion は 3 である必要があります(WP 6.3 以降)。1 または 2 の場合は、アップグレード方法を案内して WARNING として報告します。
    • name は「namespace/block-name」形式(小文字、英字、数字、ハイフン)である必要があります。
    • title と category は必須です。
    • attributes:type、source、selector、default の値を検証します。type の不一致を報告します。
    • supports:color、spacing、typography、align、anchor、html
    • editorScript、script、viewScript、viewScriptModule:「file:./path」形式を検証します。
    • style、editorStyle:パスを検証します。
    • render:動的ブロックでは「file:./render.php」を指定します。
    • 検証用に $schema フィールドを推奨します。
  3. edit 関数を確認する(BLK-05、BLK-20)

    • useBlockProps() を呼び出し、ラッパー要素に展開する必要があります。
    • インポート方法:@wordpress/* パッケージ(GOOD)と window.wp.*(BAD — レガシー)
    • サイドバー設定には InspectorControls、ツールバーには BlockControls を使用します。
    • RichText を適切に使用します(tagName、value、onChange、allowedFormats)。
    • allowedBlocks と template のプロパティを指定して InnerBlocks を使用します。
    • @wordpress/data の useSelect/useDispatch を使用します(複数のセレクターは 1 回の useSelect 呼び出しにまとめます)。
    • i18n:ユーザーに表示するすべての文字列を、text domain とともに @wordpress/i18n の __() で囲みます。
  4. 保存関数またはレンダーコールバックを確認

    • 静的ブロック: useBlockProps.save() を呼び出す必要があります。リッチテキストには RichText.Content、ネストされたブロックには InnerBlocks.Content を使用します
    • 動的ブロック: save は null を返します(ネストされたブロックを使用する場合は InnerBlocks.Content を返します。BLK-14 重大)
    • 保存関数は決定的でなければなりません。ランダムな値、Date.now()、副作用は使用しません
    • レンダーコールバック/render.php: ラッパーには get_block_wrapper_attributes() を使用し、すべての出力をエスケープします(esc_html、esc_attr、esc_url、wp_kses_post。ただし、InnerBlocks の $content には適用しません。BLK-21)。先頭に defined( 'ABSPATH' ) || exit; を記述します
  5. 重大なパターンをスキャン

    • apiVersion がない、または 3 ではなく 1/2 を使用している
    • JS/JSX で @wordpress/* のインポートではなく window.wp.* を使用している
    • 保存関数に useBlockProps.save() がない(apiVersion 3)
    • レンダーコールバックで $content パラメーターに wp_kses_post() を使用している(埋め込みが壊れます)
    • InnerBlocks を使用する動的ブロックで、save が null を返している(InnerBlocks.Content がない)
    • source: 'meta' を指定した属性(非推奨。useEntityProp を使用します)
    • 属性の型/source の組み合わせが無効
    • PHP に register_block_type() の呼び出しがない
  6. 警告パターンを確認

    • block.json に supports フィールドがない
    • edit 関数に useBlockProps() がない
    • JS/JSX または PHP で、文字列が __() で囲まれていない
    • render.php に get_block_wrapper_attributes() がない
    • PHP のレンダーファイルに defined( 'ABSPATH' ) のチェックがない
    • 保存関数に副作用がある(Math.random、Date.now)
    • block.json に $schema フィールドがない
    • useSelect を複数回個別に呼び出している(パフォーマンス上のアンチパターン)
  7. 情報として改善点を記録

    • block.json のレンダーファイルではなく、PHP で render_callback を使用している
    • block.json に viewScript/viewScriptModule がない(フロントエンド JS がない)
    • apiVersion 2(3 へのアップグレードを提案)
    • block.json に keywords がない
    • 自動挿入の機会にブロックフックを使用していない

以下の出力形式で報告します。セキュリティ上の懸念(エスケープされていないレンダー出力、Interactivity API の state に含まれるユーザー入力)が見つかった場合は、次の注記を追加します。「セキュリティ上の問題が検出されました。包括的なセキュリティ分析を行うには、/wp-sec-review を実行してください。」プラグインのアーキテクチャ上の問題(init フックでの登録、ABSPATH チェックの欠落)が見つかった場合は、次の注記を追加します。「プラグインのアーキテクチャ上の問題が検出されました。包括的なプラグインレビューを行うには、/wp-plugin-review を実行してください。」

ソースとビルドのレビュー: コードパターンの確認には src/ ファイルを使用します(開発者の意図)。build/ ディレクトリがない、または古い場合は、その旨を指摘します(index.asset.php のタイムスタンプと src/ の更新時刻を確認)。build/ ファイルのコード品質はレビューしないでください。これらはコンパイル済みの出力です。

ファイルタイプ別の確認項目

block.json (BLK-02, BLK-06, BLK-08, BLK-10)

apiVersion フィールド:

  • CRITICAL:apiVersion がない → ブロックが正しく登録されません
  • WARNING:apiVersion が 1 または 2 → iframe 分離のため、3 にアップグレードしてください(WP 6.3+)
  • パターン:"apiVersion": 3

name フィールド:

  • CRITICAL:name がない → ブロックが登録されません
  • CRITICAL:形式が無効("namespace/block-name" ではない)→ 登録に失敗します
  • パターン:"name": "my-plugin/my-block"(小文字、ハイフン、英字、数字)

attributes フィールド:

  • CRITICAL:型が無効(string/number/boolean/object/array/integer/null ではない)→ 検証に失敗します
  • CRITICAL:source:'meta' → 非推奨です。代わりに useEntityProp フックを使用してください
  • WARNING:type が source のデータ型と一致しない → 属性が正しく設定されません
  • パターン:type、source、selector、default の組み合わせを検証します
  • ソース:attribute、text、html、query(meta は非推奨)

supports フィールド:

  • WARNING:supports がない → ユーザーが色、余白、タイポグラフィをカスタマイズできません
  • INFO:一般的な supports(color、spacing、typography、align、anchor)を追加できます
  • パターン:各サポートタイプの設定をネストしたオブジェクト

editorScript/script/viewScript/viewScriptModule フィールド:

  • WARNING:パス形式が無効 → アセットが読み込まれません
  • パターン:"file:./index.js"(block.json の場所からの相対パス)
  • 注:Interactivity API には viewScriptModule を使用します(WP 6.5+)

render フィールド:

  • INFO:動的ブロックでは render_callback の代わりに render ファイルを使用できます
  • パターン:"file:./render.php"(block.json の場所からの相対パス)

$schema フィールド:

  • INFO:$schema がない → IDE でスキーマを検証できません
  • パターン:"$schema": "https://schemas.wp.org/trunk/block.json"
Edit 関数 / edit.js (BLK-05, BLK-20)

useBlockProps の使用:

  • CRITICAL:useBlockProps() が呼び出されていない → エディターでブロックが正しく表示されません
  • CRITICAL:useBlockProps の結果がラッパーに展開されていない → ブロックのクラスや属性が不足します
  • パターン:const blockProps = useBlockProps(); の後に <div { ...blockProps }>

インポートのパターン:

  • WARNING:window.wp.* グローバルへのアクセス → レガシーなパターンであり、最新のビルドで問題が発生します
  • パターン:推奨:import { useBlockProps } from '@wordpress/block-editor'; 非推奨:const { useBlockProps } = window.wp.blockEditor;

InspectorControls と BlockControls:

  • INFO:InspectorControls で設定サイドバーを追加できます
  • INFO:BlockControls でツールバーコントロールを追加できます
  • パターン:PanelBody/ToggleControl/SelectControl には InspectorControls、AlignmentToolbar/ToolbarGroup には BlockControls を使用します

RichText の使用:

  • WARNING:tagName を指定せずに RichText を使用 → 正しく表示されない可能性があります
  • WARNING:value/onChange を指定せずに RichText を使用 → 制御コンポーネントになりません
  • パターン:<RichText tagName="p" value={ attributes.content } onChange={ ( content ) => setAttributes( { content } ) } />

InnerBlocks の使用:

  • INFO:ネストを制限するため、allowedBlocks の使用を検討してください
  • INFO:デフォルトのブロック構造を定義するため、template の使用を検討してください
  • パターン:<InnerBlocks allowedBlocks={ [ 'core/paragraph' ] } template={ [ [ 'core/heading' ] ] } />

useSelect/useDispatch のパフォーマンス:

  • WARNING:useSelect を個別に複数回呼び出す → ブロック数が多い場合、パフォーマンスが低下します
  • パターン:複数の値を読み取る場合は、セレクターを単一の useSelect にまとめます

国際化:

  • WARNING:__() を使わないハードコード文字列 → 翻訳できません
  • パターン:ユーザーに表示するすべての文字列に __( 'Text', 'text-domain' ) を使用します
保存関数/save.js(BLK-05、BLK-07)

静的ブロック(save が JSX を返す場合):

  • CRITICAL:useBlockProps.save() がない → ブロックの検証エラー(apiVersion 3)
  • WARNING:RichText.Content を使わずに RichText を使用 → リッチテキストが正しく保存されません
  • WARNING:InnerBlocks.Content を使わずに InnerBlocks を使用 → ネストされたブロックが保存されません
  • パターン:const blockProps = useBlockProps.save(); を記述してから、<div { ...blockProps }>

動的ブロック(save が null または InnerBlocks.Content を返す場合):

  • CRITICAL:InnerBlocks を含む動的ブロックで save が null を返す → ネストされたブロックが失われます(BLK-14)
  • パターン:ブロックで InnerBlocks を使用する場合、動的ブロックであっても save は必ず <InnerBlocks.Content /> を返す必要があります

決定論的な保存:

  • WARNING:save で Math.random() または Date.now() を使用 → 再保存時にブロックの検証エラーが発生します
  • WARNING:save で副作用が発生 → 動作が予測不能になります
  • パターン:同一の属性に対して、save は常に同一のマークアップを返す必要があります
レンダリングコールバック/render.php(BLK-11)

ABSPATH のチェック:

  • WARNING:defined( 'ABSPATH' ) || exit; がない → ファイルへの直接アクセスが可能になります
  • パターン:<?php の直後の最初の行に ABSPATH のチェックを記述します
  • 相互参照:セキュリティ対策の詳細については、wp-security-review を参照してください

get_block_wrapper_attributes():

  • WARNING:get_block_wrapper_attributes() の代わりにクラスを手動で連結 → ブロックのサポート機能が適用されません
  • パターン:$wrapper_attributes = get_block_wrapper_attributes(); を記述してから、<div <?php echo $wrapper_attributes; ?>>

出力のエスケープ:

  • CRITICAL:エスケープされていない出力 → XSS の脆弱性(CWE-79)
  • CRITICAL:InnerBlocks の $content に wp_kses_post() を使用 → 埋め込みが壊れます(BLK-21)
  • パターン:テキストには esc_html()、属性には esc_attr()、URL には esc_url()、信頼できる HTML には wp_kses_post() を使用します(ただし、InnerBlocks の $content には使用しません)
  • 相互参照:包括的なエスケープパターンについては、wp-security-review を参照してください

関数のパラメーター:

  • $attributes:ブロック属性の配列
  • $content:InnerBlocks の HTML(InnerBlocks を使用する場合)
  • $block:コンテキストやその他のメタデータを含む WP_Block インスタンス
  • パターン:動的ブロックの機能をすべて活用するには、3 つのパラメーターをすべて使用します
プラグインのメインファイル/plugin.php

register_block_type():

  • CRITICAL:register_block_type() がない → ブロックが登録されません
  • WARNING:'init' にフックされていない → 登録のタイミングが早すぎる可能性があります
  • パターン:add_action( 'init', 'callback' ); を記述してから、register_block_type( __DIR__ . '/build/block-name' );

複数ブロックの登録:

  • WARNING:複数ブロックのプラグインで register_block_type() が 1 つだけ → ほかのブロックが登録されません
  • パターン:各ブロックの build ディレクトリに対して register_block_type() を呼び出します

プラグインヘッダーと ABSPATH:

  • 相互参照:プラグインヘッダーの要件と ABSPATH のチェックについては、wp-plugin-development を参照してください
ブロックの非推奨化(BLK-09)

deprecated 配列:

  • CRITICAL:非推奨化を設定せずに保存関数を変更 → 既存コンテンツでブロックの検証エラーが発生します
  • WARNING:非推奨化のエントリーに apiVersion がない → 非推奨化が一致しない可能性があります
  • パターン:バージョンごとに save と attributes を含む deprecated 配列を設定します

migrate 関数:

  • INFO:属性スキーマの変更に migrate 関数を追加できます
  • パターン:migrate( attributes ) { return { ...attributes, newField: 'default' }; }

順序:

  • WARNING:非推奨化の順序が古いものからになっている → WordPress は新しいものから確認するため、パフォーマンスの問題が発生します
  • パターン:配列では新しい非推奨化を最初に記述します
Interactivity API ファイル(BLK-12)

WP 6.5+ バージョンマーカー:

  • INFO:Interactivity API には WordPress 6.5+ が必要です → バージョンチェックまたはプラグイン要件を追加します
  • パターン:プラグインヘッダーで Requires at least: 6.5 を確認します

render.php のディレクティブ:

  • data-wp-interactive="namespace" → Interactivity API のスコープに必須です
  • wp_interactivity_state() → サーバー側の状態を初期化します
  • wp_interactivity_config() → サーバー側の設定を行います
  • data-wp-context → ネストされた要素のコンテキストプロバイダーです
  • ディレクティブ:data-wp-bind、data-wp-on、data-wp-class、data-wp-style、data-wp-text、data-wp-watch、data-wp-init、data-wp-each

view.js(フロントエンドストア):

  • WARNING:window.wp.interactivity からインポートしています → レガシーパターンです。@wordpress/interactivity を使用してください
  • パターン:import { store } from '@wordpress/interactivity'; の後に store( 'namespace', { actions, state } ); を記述します

主な違い:

  • Interactivity API = フロントエンド専用(view.js、render.php のディレクティブ)
  • エディターでは引き続き React を使用します(edit.js)
  • フロントエンドの状態管理とエディターコンポーネントの状態を混同しないでください

セキュリティ上の関連事項:

  • WARNING:wp_interactivity_state() でユーザー入力をサニタイズせずに使用しています → XSS のリスクがあります
  • 関連項目:入力のサニタイズパターンについては wp-security-review を参照してください
ブロックコンテキスト(BLK-16)

providesContext(親ブロック):

  • パターン:親の block.json に "providesContext": { "myPlugin/keyName": "attributeName" } を記述します
  • コンテキストキーには名前空間を付けます:「myPlugin/keyName」形式を使用します

usesContext(子ブロック):

  • パターン:子の block.json に "usesContext": [ "myPlugin/keyName" ] を記述します
  • edit でのアクセス方法:function Edit( { context } ) { const value = context['myPlugin/keyName']; }
表層レベルのチェック

ブロック変換(BLK-13 一部):

  • INFO:他のブロックとの相互変換用に transforms を追加できます
  • パターン:ブロック登録時に from/to 配列を指定します

ブロックバリエーション(BLK-13):

  • INFO:プリセット設定用にバリエーションを追加できます
  • パターン:variation picker、isDefault、scope プロパティ

ブロックスタイル:

  • INFO:block.json または PHP でスタイルバリエーションを登録できます
  • パターン:block.json の styles 配列、または PHP の register_block_style()

ブロックパターン(BLK-18):

  • パターン:register_block_pattern() の構造、カテゴリー、キーワード
  • 注:パターンは複数ブロックのレイアウトです。単一ブロックのプリセットであるバリエーションとは異なります

ブロックフック(BLK-19):

  • INFO:自動挿入に blockHooks を使用できます(WP 6.4+)
  • CRITICAL:ブロックフックは動的ブロック(save が null を返す)でのみ動作します
  • パターン:block.json の blockHooks プロパティ

Block Bindings API(BLK-17):

  • INFO:動的な属性接続にバインディングを使用できます(WP 6.5+)
  • パターン:表層レベルの検出のみ

@wordpress/scripts のビルド設定:

  • WARNING:@wordpress/scripts がありません → ビルドツールチェーンがありません
  • WARNING:package.json に build/start スクリプトがありません → ブロックをコンパイルできません
  • パターン:package.json で "scripts": { "build": "wp-scripts build", "start": "wp-scripts start" } を確認します

テンプレートロック:

  • INFO:固定レイアウトには InnerBlocks で templateLock を使用できます
  • パターン:<InnerBlocks templateLock="all" /> はブロックの追加、削除、並べ替えを防止します

すばやく検出するための検索パターン(BLK-22)

ブロックをすばやくスキャンするには、以下の rg コマンドを使用します。重要度別に整理されています。PHP と JS/JSX の両方のファイルが対象です。

CRITICAL パターン
# block.json without apiVersion 3
rg -l --iglob 'block.json' . | xargs -I{} sh -c "rg -q '\"apiVersion\"\\s*:\\s*3' '{}' || echo '{}'"

# JS/JSX files with window.wp.* instead of @wordpress/* imports
rg -n "window\.wp\." . -g '*.{js,jsx}'

# save function without useBlockProps.save() in JSX files (manual candidate list)
rg -n "function save|const save\s*=|save:\s*\(" . -g '*.{js,jsx}'

# render callback using wp_kses_post on $content parameter (breaks embeds)
rg -n "wp_kses_post\s*\(\s*\$content\s*\)" . -g '*.php'

# Dynamic block with InnerBlocks but save returns null
# Manual check: if edit.js uses InnerBlocks, save.js should include InnerBlocks.Content.
rg -n "InnerBlocks" . -g '*.{js,jsx}'
rg -n "return\s+null" . -g '*.{js,jsx}'

# Attribute with source: 'meta' (deprecated)
rg -n "\"source\"\s*:\s*\"meta\"" . -g 'block.json'

# Missing register_block_type() call in plugin bootstrap files
rg -n "register_block_type\s*\(" . -g '*.php'
WARNING パターン
# block.json missing supports field
rg -l --iglob 'block.json' . | xargs -I{} sh -c "rg -q '\"supports\"' '{}' || echo '{}'"

# edit function without useBlockProps() in JS/JSX files (manual candidate list)
rg -n "function Edit|export default function Edit|const Edit\s*=" . -g '*.{js,jsx}'

# Hardcoded strings not wrapped in __() in JS/JSX files
rg -n "title\s*:\s*['\"][A-Z]" . -g '*.{js,jsx}'

# render.php without get_block_wrapper_attributes()
rg -l --iglob 'render.php' . | xargs -I{} sh -c "rg -q 'get_block_wrapper_attributes' '{}' || echo '{}'"

# PHP render files without defined( 'ABSPATH' ) check
rg -l --iglob 'render.php' . | xargs -I{} sh -c "rg -q 'defined.*ABSPATH' '{}' || echo '{}'"

# save function with side effects (Math.random, Date.now)
rg -n "Math\.random|Date\.now|new Date\(" . -g 'save.js'

# Missing block.json $schema field
rg -l --iglob 'block.json' . | xargs -I{} sh -c "rg -q '\"\\$schema\"' '{}' || echo '{}'"

# useSelect with multiple separate calls (performance anti-pattern)
# Manual check: inspect files with repeated useSelect() calls.
rg -n "useSelect\s*\(" . -g '*.{js,jsx}'
INFO パターン
# Using render_callback in PHP instead of render file in block.json
grep -rn "render_callback" --include="*.php" .

# Missing viewScript/viewScriptModule in block.json (no frontend JS)
grep -L "viewScript\|viewScriptModule" --include="block.json" .

# apiVersion 2 (suggest upgrade to 3)
grep -rn "\"apiVersion\": 2" --include="block.json" .

# Missing keywords in block.json
grep -L "\"keywords\"" --include="block.json" .

# Not using block hooks for auto-insertion opportunities
# (Manual check: Review block purpose for auto-insertion potential)

注: JavaScript の grep パターンには、PHP のパターンとは異なる正規表現が必要です。JS ファイルには --include="*.js" --include="*.jsx"、PHP ファイルには --include="*.php" を使用します。

ブロックコンテキストの検出

ブロックの分布と読み込みコンテキストに基づいた、コンテキスト対応のレビュー注記です。

単一ブロックのプラグイン

構成: ルートまたは src/ に block.json が 1 つあり、ビルド出力も 1 つです レビュー時の調整: 標準的なレビューで、特別な考慮事項はありません パターン: プラグインフォルダーに index.js、edit.js、save.js を含む src/ ディレクトリが 1 つあります

複数ブロックのプラグイン

構成: src/block-one/、src/block-two/ などに複数のブロックがあり、それぞれに block.json がある レビュー時の調整:

  • src/shared/ または src/components/ に共有コンポーネントがあるか確認します
  • すべてのブロックで命名規則が一貫しているか確認します
  • ビルド設定がすべてのブロックに対応しているか確認します(複数のエントリーポイントまたはワイルドカード)
  • 各ブロックのビルドディレクトリに対して register_block_type() が呼び出されているか確認します パターン: プラグインフォルダーに複数の src/*/block.json ファイルが含まれます
ブロックライブラリ/コレクション

構成: 複数のブロックを含む npm パッケージまたは WordPress.org プラグインとして公開されます レビュー時の調整:

  • 名前空間は非常に重要です(すべてのブロックで一貫した名前空間を使用する必要があります)
  • 命名が一貫しているか確認します:「namespace/block-one」、「namespace/block-two」
  • すべてのブロックが同じ名前空間にあるか確認します
  • package.json に、ビルドエントリーポイントを指す「main」フィールドが必要です パターン: package.json に「name」フィールドがあり、npm または WordPress.org に公開されます
テーマブロック

構成: functions.php で登録され、ブロックファイルは /blocks/ または /inc/blocks/ にあります レビュー時の調整:

  • 読み込みコンテキストが異なります(テーマの有効化とプラグインの有効化)
  • ブロックが theme.json の設定(色、間隔、タイポグラフィ)に依存する場合があります
  • theme.json との連携について簡単に触れ、詳細はフェーズ 4(テーマ開発)に委ねます
  • ブロックが 'init' または 'after_setup_theme' フックで登録されているか確認します パターン: functions.php に register_block_type() があり、テーマのサブディレクトリにブロックがあります

クイックリファレンス:ブロック開発パターン(BLK-23)

懸念事項別に整理した、よく使われるブロックパターンです。すべての例で WordPress のコーディング標準を使用しています(PHP:括弧内のスペース、[] ではなく array()、ヨーダ条件式。JS:タブによるインデント、camelCase、コンポーネントには PascalCase)。

block.json スキーマ

すべてのフィールドに注釈を付けた完全なスキーマ(apiVersion 3):

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "my-plugin/my-block",
	"title": "My Block",
	"category": "widgets",
	"icon": "smiley",
	"description": "A custom block example",
	"keywords": [ "custom", "example" ],
	"version": "1.0.0",
	"textdomain": "my-plugin",
	"attributes": {
		"content": {
			"type": "string",
			"source": "html",
			"selector": "p",
			"default": ""
		},
		"showImage": {
			"type": "boolean",
			"default": false
		}
	},
	"supports": {
		"html": false,
		"color": {
			"background": true,
			"text": true
		},
		"spacing": {
			"margin": true,
			"padding": true
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true
		},
		"align": [ "wide", "full" ],
		"anchor": true
	},
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css",
	"viewScriptModule": "file:./view.js"
}
ブロックの登録

PHP + JS の登録パターン:

❌ BAD:ABSPATH チェックがなく、init にフックされていません

<?php
function my_plugin_register_block() {
	register_block_type( __DIR__ . '/build/my-block' );
}
my_plugin_register_block(); // Runs immediately, not on init

✅ GOOD:ABSPATH と init フックを含む完全な登録

<?php
defined( 'ABSPATH' ) || exit;

function my_plugin_register_blocks() {
	register_block_type( __DIR__ . '/build/my-block' );
}
add_action( 'init', 'my_plugin_register_blocks' );

✅ GOOD:複数ブロックの登録

<?php
defined( 'ABSPATH' ) || exit;

function my_plugin_register_blocks() {
	register_block_type( __DIR__ . '/build/block-one' );
	register_block_type( __DIR__ . '/build/block-two' );
	register_block_type( __DIR__ . '/build/block-three' );
}
add_action( 'init', 'my_plugin_register_blocks' );
静的ブロックパターン

useBlockProps を使って編集し、useBlockProps.save、RichText + RichText.Content を使って保存します:

❌ BAD:編集と保存で useBlockProps がありません

// edit.js
export default function Edit( { attributes, setAttributes } ) {
	return (
		<div className="my-block">
			<input
				value={ attributes.content }
				onChange={ ( e ) => setAttributes( { content: e.target.value } ) }
			/>
		</div>
	);
}

// save.js
export default function save( { attributes } ) {
	return (
		<div className="my-block">
			<p>{ attributes.content }</p>
		</div>
	);
}

✅ GOOD:useBlockProps と RichText を使った完全な静的ブロック

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

export default function Edit( { attributes, setAttributes } ) {
	const blockProps = useBlockProps();

	return (
		<div { ...blockProps }>
			<RichText
				tagName="p"
				value={ attributes.content }
				onChange={ ( content ) => setAttributes( { content } ) }
				placeholder="Enter content..."
			/>
		</div>
	);
}

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

export default function save( { attributes } ) {
	const blockProps = useBlockProps.save();

	return (
		<div { ...blockProps }>
			<RichText.Content tagName="p" value={ attributes.content } />
		</div>
	);
}
動的ブロックパターン

useBlockProps を使って編集し、保存では null(または InnerBlocks.Content)を返します。render.php では get_block_wrapper_attributes とエスケープを使います:

❌ BAD:ラッパー属性がなく、出力がエスケープされていない render コールバック

<?php
function my_plugin_render_callback( $attributes ) {
	return '<div><p>' . $attributes['content'] . '</p></div>';
}

✅ GOOD:適切なエスケープを含む完全な動的ブロック

<?php
// render.php
defined( 'ABSPATH' ) || exit;

$wrapper_attributes = get_block_wrapper_attributes();
?>
<div <?php echo $wrapper_attributes; ?>>
	<p><?php echo esc_html( $attributes['content'] ); ?></p>
</div>
// save.js - Dynamic blocks return null
export default function save() {
	return null;
}

✅ GOOD:render ファイルを指定して登録された動的ブロック

<?php
// plugin.php
defined( 'ABSPATH' ) || exit;

function my_plugin_register_blocks() {
	register_block_type( __DIR__ . '/build/my-block' );
	// render file specified in block.json "render": "file:./render.php"
}
add_action( 'init', 'my_plugin_register_blocks' );
InnerBlocks パターン

allowedBlocks、template、templateLock、および save 内の InnerBlocks.Content(動的ブロックの場合も同様):

❌ BAD:InnerBlocks を使用しているのに save が null を返す動的ブロック

// edit.js
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';

export default function Edit() {
	const blockProps = useBlockProps();
	return (
		<div { ...blockProps }>
			<InnerBlocks />
		</div>
	);
}

// save.js - CRITICAL: Nested blocks will be lost!
export default function save() {
	return null;
}

✅ GOOD:ネストされたコンテンツを保存する InnerBlocks 付きの動的ブロック

// edit.js
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';

export default function Edit() {
	const blockProps = useBlockProps();
	const ALLOWED_BLOCKS = [ 'core/paragraph', 'core/image', 'core/heading' ];
	const TEMPLATE = [
		[ 'core/heading', { placeholder: 'Card Title' } ],
		[ 'core/paragraph', { placeholder: 'Card content...' } ],
	];

	return (
		<div { ...blockProps }>
			<InnerBlocks
				allowedBlocks={ ALLOWED_BLOCKS }
				template={ TEMPLATE }
				templateLock={ false }
			/>
		</div>
	);
}

// save.js - MUST save InnerBlocks.Content even for dynamic blocks
import { InnerBlocks } from '@wordpress/block-editor';

export default function save() {
	return <InnerBlocks.Content />;
}

✅ GOOD:InnerBlocks の HTML に $content パラメーターを使う render.php

<?php
// render.php
defined( 'ABSPATH' ) || exit;

$wrapper_attributes = get_block_wrapper_attributes();
?>
<div <?php echo $wrapper_attributes; ?>>
	<h3><?php echo esc_html( $attributes['title'] ); ?></h3>
	<?php echo $content; // InnerBlocks HTML - DO NOT use wp_kses_post() ?>
</div>
useBlockProps

edit(useBlockProps())と save(useBlockProps.save())でカスタムプロパティをマージします:

❌ BAD:useBlockProps がありません

export default function Edit() {
	return <div className="my-block">Content</div>;
}

function save() {
	return <div className="my-block">Content</div>;
}

✅ GOOD:カスタムプロパティをマージした useBlockProps

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

export default function Edit( { attributes } ) {
	const blockProps = useBlockProps( {
		className: 'my-custom-class',
		style: { backgroundColor: attributes.bgColor },
	} );

	return <div { ...blockProps }>Content</div>;
}

function save( { attributes } ) {
	const blockProps = useBlockProps.save( {
		className: 'my-custom-class',
		style: { backgroundColor: attributes.bgColor },
	} );

	return <div { ...blockProps }>Content</div>;
}
属性

type/source/selector/default のパターンと、属性の型の一致:

❌ BAD:型の不一致、デフォルト値なし、非推奨の source

{
	"attributes": {
		"count": {
			"type": "number",
			"source": "text",
			"selector": ".count"
		},
		"metaValue": {
			"type": "string",
			"source": "meta",
			"meta": "my_meta_key"
		}
	}
}

✅ GOOD:型と source の適切な組み合わせ、デフォルト値、最新のパターン

{
	"attributes": {
		"content": {
			"type": "string",
			"source": "html",
			"selector": "p",
			"default": ""
		},
		"count": {
			"type": "number",
			"source": "attribute",
			"selector": ".count",
			"attribute": "data-count",
			"default": 0
		},
		"url": {
			"type": "string",
			"source": "attribute",
			"selector": "a",
			"attribute": "href",
			"default": ""
		},
		"items": {
			"type": "array",
			"source": "query",
			"selector": "li",
			"query": {
				"text": {
					"type": "string",
					"source": "text"
				}
			},
			"default": []
		}
	}
}

✅ GOOD:useEntityProp を使ったメタ属性(非推奨の source ではありません)

import { useEntityProp } from '@wordpress/core-data';

export default function Edit() {
	const [ meta, setMeta ] = useEntityProp( 'postType', 'post', 'meta' );
	const value = meta.my_meta_key;

	const updateMeta = ( newValue ) => {
		setMeta( { ...meta, my_meta_key: newValue } );
	};

	// Use value and updateMeta in component
}
ブロックコントロール

サイドバーには InspectorControls、ツールバーには BlockControls、PanelBody、ToggleControl、SelectControl を使います:

❌ BAD:ブロックのマークアップに設定がハードコードされ、サイドバーコントロールがありません

export default function Edit( { attributes, setAttributes } ) {
	return (
		<div>
			<label>
				Show Image:
				<input
					type="checkbox"
					checked={ attributes.showImage }
					onChange={ ( e ) => setAttributes( { showImage: e.target.checked } ) }
				/>
			</label>
		</div>
	);
}

✅ GOOD:サイドバーには InspectorControls、ツールバーには BlockControls

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

export default function Edit( { attributes, setAttributes } ) {
	const blockProps = useBlockProps();

	return (
		<>
			<BlockControls>
				<AlignmentToolbar
					value={ attributes.align }
					onChange={ ( align ) => setAttributes( { align } ) }
				/>
			</BlockControls>

			<InspectorControls>
				<PanelBody title={ __( 'Settings', 'my-plugin' ) }>
					<ToggleControl
						label={ __( 'Show featured image', 'my-plugin' ) }
						checked={ attributes.showImage }
						onChange={ ( showImage ) => setAttributes( { showImage } ) }
					/>
					<SelectControl
						label={ __( 'Display style', 'my-plugin' ) }
						value={ attributes.style }
						options={ [
							{ label: 'Default', value: 'default' },
							{ label: 'Card', value: 'card' },
							{ label: 'List', value: 'list' },
						] }
						onChange={ ( style ) => setAttributes( { style } ) }
					/>
				</PanelBody>
			</InspectorControls>

			<div { ...blockProps }>
				{/* Block content */}
			</div>
		</>
	);
}
ブロックの非推奨化

deprecated 配列、save 関数と属性の移行、エントリー内の apiVersion、新しい順:

❌ BAD:非推奨化せずに save 関数を変更

// Changed save markup - existing blocks will show validation error
function save( { attributes } ) {
	const blockProps = useBlockProps.save();
	return <div { ...blockProps }>{ attributes.content }</div>;
}

✅ GOOD:古い save 関数の非推奨化エントリー

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

const deprecated = [
	{
		// Version 2: Added useBlockProps (newest deprecation first)
		apiVersion: 2,
		attributes: {
			content: { type: 'string' },
		},
		save( { attributes } ) {
			return <div className="my-block">{ attributes.content }</div>;
		},
	},
	{
		// Version 1: Original block
		apiVersion: 2,
		attributes: {
			content: { type: 'string' },
		},
		save( { attributes } ) {
			return <p>{ attributes.content }</p>;
		},
		migrate( attributes ) {
			// Transform old attributes to new schema
			return {
				...attributes,
				newField: 'default',
			};
		},
	},
];

// Current version
function save( { attributes } ) {
	const blockProps = useBlockProps.save();
	return <div { ...blockProps }>{ attributes.content }</div>;
}

export default {
	edit: Edit,
	save,
	deprecated,
};
Interactivity API

data-wp-interactive、data-wp-bind、data-wp-on、store()、wp_interactivity_state()、フロントエンド専用であることを強調:

❌ BAD:フロントエンドのインタラクションにカスタム JavaScript を使用

<?php
// render.php
?>
<div class="my-block">
	<button id="toggle-button">Toggle</button>
	<div id="content" style="display: none;">Hidden content</div>
</div>
<script>
	document.getElementById('toggle-button').addEventListener('click', function() {
		var content = document.getElementById('content');
		content.style.display = content.style.display === 'none' ? 'block' : 'none';
	});
</script>

✅ GOOD:ディレクティブを使用した Interactivity API(WP 6.5+)

<?php
// render.php
defined( 'ABSPATH' ) || exit;

wp_interactivity_state( 'myPlugin', array(
	'isOpen' => false,
) );

$wrapper_attributes = get_block_wrapper_attributes();
?>
<div
	<?php echo $wrapper_attributes; ?>
	data-wp-interactive="myPlugin"
	data-wp-context='{ "id": "<?php echo esc_attr( uniqid() ); ?>" }'
>
	<button data-wp-on--click="actions.toggle">
		<?php esc_html_e( 'Toggle', 'my-plugin' ); ?>
	</button>
	<div data-wp-bind--hidden="!state.isOpen">
		<p><?php esc_html_e( 'Hidden content', 'my-plugin' ); ?></p>
	</div>
</div>
// view.js - Frontend store (NOT editor code)
import { store } from '@wordpress/interactivity';

store( 'myPlugin', {
	state: {
		isOpen: false,
	},
	actions: {
		toggle: ( { state } ) => {
			state.isOpen = ! state.isOpen;
		},
	},
} );

block.json の設定:

{
	"viewScriptModule": "file:./view.js"
}

注: Interactivity API はフロントエンド専用です。エディターでは引き続き React(edit.js)を使用します。

インポートパターン

@wordpress/* パッケージのインポートと window.wp.* によるレガシーアクセス:

❌ BAD:window.wp. グローバルアクセス(レガシー)*

const { registerBlockType } = window.wp.blocks;
const { useBlockProps } = window.wp.blockEditor;
const { __ } = window.wp.i18n;

✅ GOOD:@wordpress/ パッケージのインポート(モダン)*

import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';
ブロックサポート

block.json 内の color、spacing、typography、align、anchor:

❌ BAD:supports フィールドがない

{
	"name": "my-plugin/my-block",
	"title": "My Block"
}

✅ GOOD:完全な supports 設定

{
	"name": "my-plugin/my-block",
	"title": "My Block",
	"supports": {
		"html": false,
		"color": {
			"background": true,
			"text": true,
			"gradients": true,
			"link": true
		},
		"spacing": {
			"margin": true,
			"padding": true,
			"blockGap": true
		},
		"typography": {
			"fontSize": true,
			"lineHeight": true,
			"fontFamily": true,
			"fontWeight": true
		},
		"align": [ "wide", "full" ],
		"anchor": true
	}
}
ブロックバリエーション

attributes と innerBlocks を含む variation オブジェクト:

import { registerBlockVariation } from '@wordpress/blocks';

registerBlockVariation( 'core/columns', {
	name: 'three-columns-equal',
	title: 'Three Columns (Equal)',
	description: 'Three columns with equal width',
	icon: 'columns',
	isDefault: false,
	scope: [ 'block' ],
	attributes: {
		columns: 3,
	},
	innerBlocks: [
		[ 'core/column' ],
		[ 'core/column' ],
		[ 'core/column' ],
	],
} );
ブロック変換

from/to パターン:

import { createBlock } from '@wordpress/blocks';

export default {
	edit: Edit,
	save,
	transforms: {
		from: [
			{
				type: 'block',
				blocks: [ 'core/paragraph' ],
				transform: ( { content } ) => {
					return createBlock( 'my-plugin/my-block', {
						content,
					} );
				},
			},
		],
		to: [
			{
				type: 'block',
				blocks: [ 'core/paragraph' ],
				transform: ( { content } ) => {
					return createBlock( 'core/paragraph', {
						content,
					} );
				},
			},
		],
	},
};
ブロックコンテキスト

providesContext/usesContext:

// Parent block.json
{
	"providesContext": {
		"myPlugin/userId": "userId",
		"myPlugin/userName": "userName"
	},
	"attributes": {
		"userId": { "type": "number" },
		"userName": { "type": "string" }
	}
}
// Child block.json
{
	"usesContext": [ "myPlugin/userId", "myPlugin/userName" ]
}
// Child edit.js
export default function Edit( { context } ) {
	const userId = context['myPlugin/userId'];
	const userName = context['myPlugin/userName'];

	return (
		<div>
			<p>User: { userName } ({ userId })</p>
		</div>
	);
}
ブロックフック

動的ブロックのみで使用する blockHooks:

❌ BAD:静的ブロックでブロックフックを使用

{
	"blockHooks": {
		"core/post-content": "after"
	}
}
// save.js - Static save = block hooks won't work
function save() {
	return <div>Content</div>;
}

✅ GOOD:動的ブロックでブロックフックを使用

{
	"blockHooks": {
		"core/post-content": "after"
	},
	"render": "file:./render.php"
}
// save.js - Dynamic block (null save) = block hooks work
function save() {
	return null;
}
@wordpress/scripts

package.json の scripts 設定:

❌ BAD:ビルドスクリプトがない

{
	"scripts": {
		"test": "echo \"No build toolchain configured\""
	}
}

✅ GOOD:完全な @wordpress/scripts 設定

{
	"scripts": {
		"build": "wp-scripts build",
		"start": "wp-scripts start",
		"lint:js": "wp-scripts lint-js",
		"format": "wp-scripts format",
		"packages-update": "wp-scripts packages-update"
	},
	"devDependencies": {
		"@wordpress/scripts": "^27.0.0"
	}
}

重大度の定義(BLK-24)

重大度定義例
CRITICALブロックがレンダリングされない、エディターがクラッシュする、またはブロックの検証エラーが発生するapiVersion がない、または移行パスなしで apiVersion 1/2 を使用している、save の検証エラーを引き起こす無効な属性型、非推奨化エントリーなしで save 関数が一致しない、apiVersion 3 のブロックに useBlockProps.save() がない、edit の InnerBlocks に対して save が null(InnerBlocks.Content ではない)を返す、InnerBlocks の $content パラメーターに wp_kses_post() を使用している、モダンなビルドを破損させる window.wp.* アクセス、register_block_type() の呼び出しがない、非推奨の source:'meta' 属性パターン
WARNINGブロックは動作するものの、品質や互換性に問題がある、または標準外のパターンを使用している非推奨 API の使用(重大な問題はないが apiVersion 1/2 を使用)、ブロックサポート(color、spacing、typography)がない、save 関数の変更に対する非推奨化ハンドラーがない、JS/JSX または PHP 内に i18n を使用していないハードコード文字列がある、useSelect の呼び出しが複数に分かれている(パフォーマンスの問題)、render.php に get_block_wrapper_attributes() がない、PHP ファイルに defined( 'ABSPATH' ) がない、副作用のある save 関数(Math.random、Date.now)
INFOベストプラクティスの改善、または最適化の機会render_callback 関数の代わりに render PHP ファイルを使用できる、フロントエンドのインタラクションに viewScript/viewScriptModule がない、block.json の $schema フィールドを使用していない、apiVersion 2(3 へのアップグレードが可能)、block.json に keywords がない、自動挿入にブロックフックを活用できる、よく使うプリセット用のブロックバリエーションを追加できる、固定された InnerBlocks レイアウトにテンプレートロックがない

出力形式(BLK-24)

ファイルごとに指摘事項をまとめて報告してください(PHP ファイルと JS/JSX ファイルは、実際のファイルパスに従って混在させます)。行番号と重大度ラベルを付け、各指摘事項には BAD/GOOD のコードペアを使用してください。

# WordPress Block Review: my-block-plugin

## FILE: src/index.js

### Line 3: WARNING - Legacy global access
window.wp.* access is legacy pattern. Use @wordpress/* package imports for modern build toolchain.

❌ **BAD:**
```javascript
const { registerBlockType } = window.wp.blocks;

✅ GOOD:

import { registerBlockType } from '@wordpress/blocks';

FILE: src/edit.js

Line 12: CRITICAL - useBlockProps がない

edit 関数で useBlockProps() が呼び出されていません。エディターでブロックが正しくレンダリングされません。

❌ BAD:

export default function Edit() {
	return <div className="my-block">Content</div>;
}

✅ GOOD:

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

export default function Edit() {
	const blockProps = useBlockProps();
	return <div { ...blockProps }>Content</div>;
}

FILE: src/save.js

Line 5: CRITICAL - useBlockProps.save() がない

apiVersion 3 のブロックには useBlockProps.save() が必要です。ブロックの検証エラーが発生します。

❌ BAD:

function save() {
	return <div className="my-block">Content</div>;
}

✅ GOOD:

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

function save() {
	const blockProps = useBlockProps.save();
	return <div { ...blockProps }>Content</div>;
}

FILE: render.php

Line 15: CRITICAL - InnerBlocks コンテンツでの wp_kses_post

$content に wp_kses_post() を使用すると、埋め込みブロックと oEmbed の処理が壊れます。InnerBlocks のコンテンツはすでにサニタイズされています。

❌ BAD:

<?php echo wp_kses_post( $content ); ?>

✅ GOOD:

<?php echo $content; // InnerBlocks already sanitized ?>
Line 1: WARNING - ABSPATH チェックの不足

直接アクセスを防ぐため、ファイルの先頭に ABSPATH チェックを追加してください。

❌ BAD:

<?php
$wrapper_attributes = get_block_wrapper_attributes();

✅ GOOD:

<?php
defined( 'ABSPATH' ) || exit;

$wrapper_attributes = get_block_wrapper_attributes();

FILE: block.json

Line 2: WARNING - apiVersion 2(アップグレード可能)

apiVersion 2 は引き続き動作しますが、iframe エディターの分離のため、3 へのアップグレードを推奨します(WP 6.3 以降)。

❌ BAD:

{
	"apiVersion": 2
}

✅ GOOD:

{
	"apiVersion": 3
}
Line 10: INFO - $schema フィールドの不足

IDE の検証サポートのため、$schema フィールドを追加してください。

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	...
}

SUMMARY

問題の合計: 7

  • CRITICAL: 3(修正必須 — ブロックが正しくレンダリングされません)
  • WARNING: 3(品質/互換性の問題)
  • INFO: 1(ベストプラクティスの改善)

ブロック検証のリスク: HIGH — useBlockProps.save() がないと、検証エラーが発生します セキュリティに関する注意: ABSPATH チェックの不足が検出されました。包括的なセキュリティ分析を行うには、/wp-sec-review を実行してください。 プラグインに関する注意: ブロックの登録が検出されました。プラグインのアーキテクチャをレビューするには、/wp-plugin-review を実行してください。


## Common Mistakes (BLK-25)

Patterns that look like issues but are NOT problems:

| Pattern | Why It's NOT a Problem | Context |
|---------|------------------------|---------|
| **Dynamic block save() returning null** | Server-side PHP renders output. save() doesn't need to return markup. | Correct for render_callback or render file usage |
| **InnerBlocks.Content without useBlockProps wrapper** | Valid for dynamic blocks that only need to persist nested blocks. | Dynamic blocks can return bare InnerBlocks.Content in save() |
| **viewScript not needed** | Block has no frontend JavaScript behavior. | Editor-only blocks or static HTML blocks don't need viewScript |
| **render_callback without return** | Valid if callback echoes output (though return is preferred). | WordPress handles both echo and return patterns |
| **Missing style/editorStyle in block.json** | Block uses theme defaults or has no custom styling. | Not all blocks need custom styles |
| **apiVersion 2 blocks** | Still work in WordPress 6.x+, just missing iframe isolation features. | Upgrade recommended but not critical |
| **Block without supports** | Valid for simple blocks that don't need color/spacing/typography. | Intentional for minimal blocks |
| **save() function with className in wrapper** | apiVersion 2 auto-injects classes. apiVersion 3 requires useBlockProps. | apiVersion-dependent behavior, not a bug |
| **window.wp.* in browser console** | Expected for debugging. Only @wordpress/* imports in source code matter. | Console access fine, source imports should use packages |
| **Interactivity API not used** | Blocks with no frontend interaction don't need Interactivity API. | Editor-only or static blocks work without frontend JS |
| **No block.json deprecation for attribute additions** | Adding new optional attributes doesn't break existing blocks. | Only save() markup changes need deprecation |
| **InnerBlocks without template** | Free-form nesting is valid. Template is optional. | Intentional when users should choose any blocks |

## Version Compatibility Reference

Quick reference for WordPress version requirements:

| Feature | WordPress Version | Notes |
|---------|-------------------|-------|
| block.json metadata support | 5.8+ | Single source of truth for block registration |
| apiVersion 2 | 5.6+ | Automatic wrapper class injection in save() |
| apiVersion 3 | 6.3+ | Iframe editor isolation, manual wrapper handling required |
| InspectorControls group prop | 6.2+ | Settings/Appearance tabs in sidebar |
| Block Hooks API | 6.4+ | Auto-insertion, dynamic blocks only |
| Interactivity API | 6.5+ | data-wp-* directives, viewScriptModule |
| viewScriptModule field | 6.5+ | ES module support for Interactivity API |
| Block Bindings API | 6.5+ | Dynamic attribute connections |
| useEntityProp hook | 5.9+ | Replacement for deprecated source:'meta' |

## Deep-Dive References

For advanced block development patterns, load these companion reference documents:

| Task | Reference to Load |
|------|-------------------|
| block.json schema validation, field-by-field reference, attribute type/source/selector patterns | `references/block-json-guide.md` |
| React/JSX editor component patterns, useBlockProps, RichText, InspectorControls, BlockControls, useSelect/useDispatch | `references/editor-patterns.md` |
| Server-side rendering, render_callback vs render file, get_block_wrapper_attributes, output escaping, $attributes/$content/$block parameters | `references/dynamic-blocks-guide.md` |
| Interactivity API directives (data-wp-*), wp_interactivity_state(), store() patterns, frontend state management | `references/interactivity-api-guide.md` |

**Note:** Reference docs provide deep-dive content. This SKILL.md is self-sufficient for standard block reviews.

**Security crossover:** When encountering security-relevant patterns (unescaped render output, user input in Interactivity API state, missing ABSPATH checks), this skill provides brief reminders but defers to wp-security-review for comprehensive security analysis. For detailed security patterns, use `/wp-sec-review` command.

**Plugin crossover:** When encountering plugin-level patterns (register_block_type() on init hook, ABSPATH checks, plugin headers), this skill provides brief mentions but defers to wp-plugin-development for plugin architecture depth. For detailed plugin architecture review, use `/wp-plugin-review` command.

コメント