Agent Skills by ALSEL
汎用ソフトウェア開発⭐ リポ 3品質スコア 76/100

wp-block-development

WordPress ブロックエディタのコードレビューおよび WordPress 6.x 以降の Gutenberg ブロック開発パターンに対応します。ブロックコードのレビュー、block.json スキーマの監査、エディタコンポーネントの確認、レンダーコールバックの検証、ブロック属性の分析、InnerBlocks の使用確認、ブロック検証エラーの検出、Interactivity API ディレクティブのレビュー時に使用できます。また、「ブロックレビュー」「Gutenberg」「ブロック開発」「ブロックエディタ」「block.json」「useBlockProps」「InnerBlocks」「Interactivity API」「data-wp-bind」「render_callback」「動的ブロック」「静的ブロック」「ブロック廃止予定」「ブロック属性」「ブロックサポート」「@wordpress/scripts」「wp-scripts」「ブロック検証エラー」「save関数」「RichText」「InspectorControls」「BlockControls」などのキーワードが含まれる場合も対応します。block.json スキーマの問題、React/JSX エディタパターン、サーバー側レンダリング、属性処理、フロントエンドインタラクションの問題を検出できます。

description の原文を見る

WordPress block editor code review and Gutenberg block development patterns for WordPress 6.x+. Use when reviewing block code, auditing block.json schema, checking editor components, validating render callbacks, analyzing block attributes, verifying InnerBlocks usage, detecting block validation errors, reviewing Interactivity API directives, or when user mentions "block review", "Gutenberg", "block development", "block editor", "block.json", "useBlockProps", "InnerBlocks", "Interactivity API", "data-wp-bind", "render_callback", "dynamic block", "static block", "block deprecation", "block attributes", "block supports", "@wordpress/scripts", "wp-scripts", "block validation error", "save function", "RichText", "InspectorControls", "BlockControls". Detects issues in block.json schema, React/JSX editor patterns, server-side rendering, attribute handling, and frontend interactions.

SKILL.md 本文

WordPress Block 開発レビュー Skill

概要

WordPress 6.x+ block editor(Gutenberg)の体系的な block 開発レビュー。コア原則: WordPress block は双一元アーキテクチャに従う—エディタ用の 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 コーディング標準(括弧内のスペース、array()[] ではない、Yoda 条件)に従う。JavaScript/JSX は WordPress JS コーディング標準(タブインデント、JSDoc コメント、変数/関数に camelCase、コンポーネントに PascalCase)に従う。

使用時機

使用する場合:

  • Block プラグインコードレビュー(single block、multi-block、block library)
  • block.json スキーマ検証とフィールド確認
  • エディタコンポーネントレビュー(edit/save 関数、React/JSX パターン)
  • Render callback または render ファイル監査(サーバーサイド PHP)
  • InnerBlocks パターンレビュー(ネストされた block、template、templateLock)
  • Block 非推奨化チェック(save 関数マイグレーション)
  • Interactivity API ディレクティブレビュー(WP 6.5+ フロントエンドインタラクション)
  • Block 属性スキーマ検証(type、source、selector、default)
  • @wordpress/scripts ビルド設定チェック
  • Block validation error 調査
  • useBlockProps、RichText、InspectorControls、BlockControls 使用法

使用しない場合:

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

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

block レビューの体系的ワークフロー。7段階を以下に示します:

  1. Block タイプとコンテキストの識別

    • Single block プラグイン → 1 つの block.json、シンプルな構造
    • Multi-block プラグイン → src/block-one/、src/block-two/ の複数 block
    • Block library/collection → パッケージとして公開、名前空間が重要
    • Theme blocks → 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" (動的 block 用)
    • $schema フィールドは検証に推奨
  3. Edit 関数チェック(BLK-05、BLK-20)

    • useBlockProps() は呼び出し必須、ラッパー要素に spread 必須
    • インポートパターン:@wordpress/* パッケージ(GOOD)vs window.wp.*(BAD - レガシー)
    • InspectorControls はサイドバー設定用、BlockControls はツールバー用
    • RichText 適切な使用(tagName、value、onChange、allowedFormats)
    • InnerBlocks は allowedBlocks と template props 付き
    • useSelect/useDispatch は @wordpress/data から(単一 useSelect 呼び出しでセレクタ結合)
    • i18n:すべてのユーザー向け文字列は __() でテキストドメイン付きでラップ(@wordpress/i18n から)
  4. Save 関数または render callback チェック

    • 静的 block: useBlockProps.save() は必須呼び出し、RichText.Content はリッチテキスト用、InnerBlocks.Content はネストされた block 用
    • 動的 block: save は null を返す(またはネストされた block が使用されている場合は InnerBlocks.Content - BLK-14 CRITICAL)
    • Save 関数は決定論的でなければならない - ランダム値なし、Date.now() なし、副作用なし
    • Render callback/render.php: get_block_wrapper_attributes() をラッパーに、すべての出力をエスケープ(esc_html、esc_attr、esc_url、wp_kses_post だが InnerBlocks の $content には NOT - BLK-21)、defined( 'ABSPATH' ) || exit; を最上部に
  5. CRITICAL パターン走査

    • apiVersion がない、または 1/2 ではなく 3 を使用
    • JS/JSX での window.wp.* ではなく @wordpress/* インポート
    • useBlockProps.save() がない save 関数(apiVersion 3)
    • wp_kses_post() を $content パラメータに使用する render callback(embed を破壊)
    • InnerBlocks を使用する動的 block だが save は null を返す(InnerBlocks.Content がない)
    • source: 'meta' の属性(非推奨 - useEntityProp を使用)
    • 無効な属性 type/source 組み合わせ
    • register_block_type() 呼び出しが PHP にない
  6. WARNING パターン チェック

    • block.json に supports フィールドがない
    • useBlockProps() がない edit 関数
    • __() でラップされていないハードコード文字列(JS/JSX または PHP)
    • get_block_wrapper_attributes() がない render.php
    • defined( 'ABSPATH' ) チェックがない PHP render ファイル
    • 副作用がある save 関数(Math.random、Date.now)
    • block.json $schema フィールドが不足
    • 複数の個別呼び出しを使用する useSelect(パフォーマンスアンチパターン)
  7. INFO 改善ノート

    • PHP で render_callback を使用(block.json の render ファイル代わり)
    • block.json に viewScript/viewScriptModule がない(フロントエンド JS なし)
    • apiVersion 2(3 へのアップグレード推奨)
    • block.json に keywords がない
    • 自動挿入機会の block hooks を使用していない

以下の出力形式を使用してレポート。セキュリティ問題が見つかった場合(エスケープされていない render 出力、Interactivity API state のユーザー入力)、注記を追加:"セキュリティ問題が検出されました。包括的なセキュリティ分析のために /wp-sec-review を実行してください。" プラグインアーキテクチャ問題が見つかった場合(init hook 登録、ABSPATH チェック不足)、注記を追加:"プラグインアーキテクチャ問題が検出されました。包括的なプラグインレビューのために /wp-plugin-review を実行してください。"

ソース vs ビルドレビュー: src/ ファイルをレビュー(開発者の意図)。build/ ディレクトリが不足またはスタイルとなっている場合フラグ(build/index.asset.php タイムスタンプを src/ 変更時間と比較)。コード品質用に build/ ファイルをレビューしない - コンパイル出力です。

ファイルタイプ別チェック

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

apiVersion フィールド:

  • CRITICAL:apiVersion がない → Block が正しく登録されない
  • WARNING:apiVersion 1 または 2 → iframe 分離のため 3 へアップグレード(WP 6.3+)
  • パターン:"apiVersion": 3

name フィールド:

  • CRITICAL:name がない → Block が登録されない
  • CRITICAL:無効な形式("namespace/block-name" ではない) → 登録失敗
  • パターン:"name": "my-plugin/my-block"(小文字、ダッシュ、文字、数字)

attributes フィールド:

  • CRITICAL:無効な type(string/number/boolean/object/array/integer/null ではない) → 検証失敗
  • CRITICAL:source:'meta' → 非推奨、useEntityProp hook を代わりに使用
  • WARNING:type が source データタイプと不一致 → 属性が正しく入力されない
  • パターン:type、source、selector、default 組み合わせを検証
  • Sources:attribute、text、html、query(meta は非推奨)

supports フィールド:

  • WARNING:supports がない → ユーザーが color/spacing/typography をカスタマイズできない
  • INFO:共通 supports を追加できます(color、spacing、typography、align、anchor)
  • パターン:各サポートタイプの nested configuration を含むオブジェクト

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

  • WARNING:無効なパス形式 → アセットが読み込まれない
  • パターン:"file:./index.js" は block.json に相対的
  • 注:Interactivity API 用 viewScriptModule(WP 6.5+)

render フィールド:

  • INFO:動的 block は 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() が呼び出されない → Block がエディタで正しく render されない
  • CRITICAL:useBlockProps 結果がラッパーに spread されない → block classes/attributes がない
  • パターン:const blockProps = useBlockProps(); その後 <div { ...blockProps }>

インポートパターン:

  • WARNING:window.wp.* グローバルアクセス → レガシーパターン、モダンビルドを破壊
  • パターン:GOOD:import { useBlockProps } from '@wordpress/block-editor'; BAD:const { useBlockProps } = window.wp.blockEditor;

InspectorControls と BlockControls:

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

RichText 使用法:

  • WARNING:tagName なし RichText → 不正にレンダリングする可能性
  • WARNING:value/onChange なし RichText → コントロール対象外のコンポーネント
  • パターン:<RichText tagName="p" value={ attributes.content } onChange={ ( content ) => setAttributes( { content } ) } />

InnerBlocks 使用法:

  • INFO:allowedBlocks でネストを制限できます
  • INFO:template でデフォルト block 構造を検討
  • パターン:<InnerBlocks allowedBlocks={ [ 'core/paragraph' ] } template={ [ [ 'core/heading' ] ] } />

useSelect/useDispatch パフォーマンス:

  • WARNING:複数の個別 useSelect 呼び出し → 多くの block でパフォーマンス低下
  • パターン:複数値を読み込むときは単一 useSelect でセレクタを結合

国際化:

  • WARNING:__() なしのハードコード文字列 → 翻訳対象外
  • パターン:すべてのユーザー向け文字列に対し __( 'Text', 'text-domain' )

Save 関数 / save.js(BLK-05、BLK-07)

静的 block(save は JSX を返す):

  • CRITICAL:useBlockProps.save() がない → block validation error(apiVersion 3)
  • WARNING:RichText.Content なし RichText → リッチテキストが正しく保存されない
  • WARNING:InnerBlocks.Content なし InnerBlocks → ネストされた block が保存されない
  • パターン:const blockProps = useBlockProps.save(); その後 <div { ...blockProps }>

動的 block(save は null または InnerBlocks.Content を返す):

  • CRITICAL:InnerBlocks を使用する動的 block だが save は null を返す → ネストされた block が失われる(BLK-14)
  • パターン:block が InnerBlocks を使用する場合、save は <InnerBlocks.Content /> を返す必要があります(動的 block の場合も)

決定論的な save:

  • WARNING:save に Math.random() または Date.now() → re-save で block validation error
  • WARNING:save の副作用 → 予測不可能な動作
  • パターン:Save は同一属性で同一マークアップを返す必要があります

Render callback / render.php(BLK-11)

ABSPATH チェック:

  • WARNING:defined( 'ABSPATH' ) || exit; がない → ダイレクトファイルアクセス可能
  • パターン:<?php の後の最初の行は ABSPATH チェック
  • クロスリファレンス:セキュリティの深さは wp-security-review を参照

get_block_wrapper_attributes():

  • WARNING:get_block_wrapper_attributes() 代わりに手動クラス連結 → block supports がない
  • パターン:$wrapper_attributes = get_block_wrapper_attributes(); その後 <div <?php echo $wrapper_attributes; ?>>

出力のエスケーピング:

  • CRITICAL:エスケープされていない出力 → XSS 脆弱性(CWE-79)
  • CRITICAL:InnerBlocks から $content に wp_kses_post() → embed を破壊(BLK-21)
  • パターン:esc_html() はテキスト、esc_attr() は属性、esc_url() は URL、wp_kses_post() は信頼できる HTML(ただし InnerBlocks $content に NOT)
  • クロスリファレンス:包括的なエスケーピングパターンは wp-security-review を参照

関数パラメータ:

  • $attributes:block 属性の配列
  • $content:InnerBlocks HTML(InnerBlocks が使用されている場合)
  • $block:WP_Block インスタンス、context およびその他のメタデータ付き
  • パターン:すべての 3 つのパラメータを使用して完全な動的 block 機能

プラグインメインファイル / plugin.php

register_block_type():

  • CRITICAL:register_block_type() がない → Block が登録されない
  • WARNING:'init' hook にフックされていない → 早すぎる登録の可能性
  • パターン:add_action( 'init', 'callback' ); その後 register_block_type( __DIR__ . '/build/block-name' );

Multi-block 登録:

  • WARNING:multi-block プラグイン用単一 register_block_type() → その他の block が登録されない
  • パターン:各 block の build ディレクトリに対して register_block_type() を呼び出す

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

  • クロスリファレンス:プラグインヘッダー要件と ABSPATH チェックは wp-plugin-development を参照

Block 非推奨化(BLK-09)

deprecated 配列:

  • CRITICAL:非推奨化なしで save 関数が変更 → 既存コンテンツで block validation error
  • 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 → ネストされた要素の 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 を参照

Block context(BLK-16)

providesContext(親 block):

  • パターン:親 block.json:"providesContext": { "myPlugin/keyName": "attributeName" }
  • 名前空間 context キー:"myPlugin/keyName" 形式を使用

usesContext(子 block):

  • パターン:子 block.json:"usesContext": [ "myPlugin/keyName" ]
  • edit でアクセス:function Edit( { context } ) { const value = context['myPlugin/keyName']; }

表面レベルチェック

Block transform(BLK-13 部分的):

  • INFO:他の block との変換を transform で追加できます
  • パターン:block 登録で from/to 配列

Block variations(BLK-13):

  • INFO:プリセット設定の variations を追加できます
  • パターン:variation picker、isDefault、scope プロパティ

Block スタイル:

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

Block パターン(BLK-18):

  • パターン:register_block_pattern() 構造、categories、keywords
  • 注:パターンは multi-block レイアウト、variations(single block プリセット)と異なる

Block hooks(BLK-19):

  • INFO:auto-insertion に blockHooks を使用できます(WP 6.4+)
  • CRITICAL:Block hooks は動的 block でのみ機能(save は null を返す)
  • パターン:block.json に blockHooks プロパティ

Block Bindings API(BLK-17):

  • INFO:動的属性接続に bindings を使用できます(WP 6.5+)
  • パターン:表面レベル検出のみ

@wordpress/scripts ビルド設定:

  • WARNING:@wordpress/scripts がない → ビルドツールチェーンがない
  • WARNING:package.json に build/start スクリプトがない → block をコンパイルできない
  • パターン:package.json で "scripts": { "build": "wp-scripts build", "start": "wp-scripts start" } をチェック

Template lock:

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

クイック検出用検索パターン(BLK-22)

rg コマンドを使用してクイック block スキャン。重要度別に整理。PHP と JS/JSX ファイルの両方をカバー。

CRITICAL パターン

# apiVersion 3 なし block.json
rg -l --iglob 'block.json' . | xargs -I{} sh -c "rg -q '\"apiVersion\"\\s*:\\s*3' '{}' || echo '{}'"

# window.wp.* の代わりに @wordpress/* インポートを使用する JS/JSX ファイル
rg -n "window\.wp\." . -g '*.{js,jsx}'

# useBlockProps.save() なし save 関数(JSX ファイル)(手動候補リスト)
rg -n "function save|const save\s*=|save:\s*\(" . -g '*.{js,jsx}'

# $content パラメータに wp_kses_post を使用する render callback(embed を破壊)
rg -n "wp_kses_post\s*\(\s*\$content\s*\)" . -g '*.php'

# InnerBlocks を使用する動的 block だが save は null を返す
# 手動チェック:edit.js が InnerBlocks を使用する場合、save.js に InnerBlocks.Content を含める。
rg -n "InnerBlocks" . -g '*.{js,jsx}'
rg -n "return\s+null" . -g '*.{js,jsx}'

# source: 'meta' の属性(非推奨)
rg -n "\"source\"\s*:\s*\"meta\"" . -g 'block.json'

# プラグインブートストラップファイルに register_block_type() 呼び出しがない
rg -n "register_block_type\s*\(" . -g '*.php'

WARNING パターン

# block.json に supports フィールドがない
rg -l --iglob 'block.json' . | xargs -I{} sh -c "rg -q '\"supports\"' '{}' || echo '{}'"

# JS/JSX ファイルで useBlockProps() なし edit 関数(手動候補リスト)
rg -n "function Edit|export default function Edit|const Edit\s*=" . -g '*.{js,jsx}'

# __() でラップされていないハードコード文字列(JS/JSX ファイル)
rg -n "title\s*:\s*['\"][A-Z]" . -g '*.{js,jsx}'

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

# defined( 'ABSPATH' ) チェックなし PHP render ファイル
rg -l --iglob 'render.php' . | xargs -I{} sh -c "rg -q 'defined.*ABSPATH' '{}' || echo '{}'"

# save 関数に副作用(Math.random、Date.now)
rg -n "Math\.random|Date\.now|new Date\(" . -g 'save.js'

# block.json $schema フィールド不足
rg -l --iglob 'block.json' . | xargs -I{} sh -c "rg -q '\"\\$schema\"' '{}' || echo '{}'"

# 複数の個別呼び出しを使用する useSelect(パフォーマンスアンチパターン)
# 手動チェック:繰り返される useSelect() 呼び出しを含むファイルを検査。
rg -n "useSelect\s*\(" . -g '*.{js,jsx}'

INFO パターン

# PHP で render_callback を使用(block.json の render ファイル代わり)
grep -rn "render_callback" --include="*.php" .

# block.json に viewScript/viewScriptModule がない(フロントエンド JS なし)
grep -L "viewScript\|viewScriptModule" --include="block.json" .

# apiVersion 2(3 へのアップグレード推奨)
grep -rn "\"apiVersion\": 2" --include="block.json" .

# block.json に keywords がない
grep -L "\"keywords\"" --include="block.json" .

# auto-insertion 機会の block hooks を使用していない
# (手動チェック:auto-insertion ポテンシャルを確認)

注: Grep パターンについては JavaScript と PHP で異なる regex が必要。JS ファイルには --include="*.js" --include="*.jsx" を、PHP ファイルには --include="*.php" を使用してください。

Block Context 検出

ブロック配布とロードコンテキストに基づいた context 認識レビューノート:

Single block プラグイン

構造: ルートまたは src/ に 1 つの block.json、シンプルなビルド出力 レビュー調整: 標準的なレビュー、特別な考慮なし パターン: プラグインフォルダは単一の src/ ディレクトリと index.js、edit.js、save.js を含む

Multi-block プラグイン

構造: src/block-one/、src/block-two/ に複数の block、各々が block.json を持つ レビュー調整:

  • src/shared/ または src/components/ の共有コンポーネントをチェック
  • すべての block にわたって一貫した命名規則を確認
  • ビルド設定がすべての block を処理することを確認(複数のエントリポイントまたはワイルドカード)
  • 各 block の build ディレクトリに対して register_block_type() が呼び出されることを確認 パターン: プラグインフォルダは複数の src/*/block.json ファイルを含む

Block library/collection

構造: npm パッケージまたは WordPress.org プラグインとして公開、複数の block レビュー調整:

  • 名前空間は CRITICAL(すべての block が一貫した名前空間を使用する必要がある)
  • 一貫した命名をチェック:"namespace/block-one"、"namespace/block-two"
  • すべての block が同じ名前空間にあることを確認
  • package.json は "main" フィールドを持つ必要があり、ビルドエントリを指す パターン: package.json が "name" フィールドを持つ、npm または WordPress.org に公開

Theme blocks

構造: functions.php で登録、block ファイルは /blocks/ または /inc/blocks/ レビュー調整:

  • 異なるロードコンテキスト(プラグイン有効化 vs theme 有効化)
  • Block は theme.json 設定(色、スペース、タイポグラフィ)に依存する可能性がある
  • theme.json 統合に簡潔なノート、Phase 4(Theme Development)に深さを延期
  • block が 'init' または 'after_setup_theme' hook に登録されることを確認 パターン: functions.php の register_block_type()、theme サブディレクトリの block

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

懸念別に整理した共通 block パターン。すべての例は WordPress コーディング標準(PHP:括弧内のスペース、array()[] ではない、Yoda 条件;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"
}

Block 登録

PHP + JS 登録パターン:

❌ BAD:ABSPATH チェックなし、init にフックされていない

<?php
function my_plugin_register_block() {
	register_block_type( __DIR__ . '/build/my-block' );
}
my_plugin_register_block(); // すぐに実行、init ではない

✅ GOOD:ABSPATH と init hook を含む完全登録

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

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

✅ GOOD:Multi-block 登録

<?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' );

静的 Block パターン

useBlockProps を使用した edit、useBlockProps.save を使用した save、RichText + RichText.Content:

❌ BAD:edit と save で 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 を使用した完全な静的 block

// 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>
	);
}

動的 Block パターン

useBlockProps を使用した edit、null(または InnerBlocks.Content)を返す save、get_block_wrapper_attributes とエスケーピングを使用した render.php:

❌ BAD:ラッパー属性なし render callback、エスケープされていない出力

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

✅ GOOD:適切なエスケーピングを使用した完全な動的 block

<?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 - 動的 block は null を返す
export default function save() {
	return null;
}

✅ GOOD:render ファイルで登録された動的 block

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

function my_plugin_register_blocks() {
	register_block_type( __DIR__ . '/build/my-block' );
	// render ファイルは block.json "render": "file:./render.php" で指定
}
add_action( 'init', 'my_plugin_register_blocks' );

InnerBlocks パターン

allowedBlocks、template、templateLock、InnerBlocks.Content を save に(動的 block の場合も):

❌ BAD:InnerBlocks を使用する動的 block だが 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:ネストされた block が失われます!
export default function save() {
	return null;
}

✅ GOOD:InnerBlocks を使用する動的 block がネストされたコンテンツを保存

// 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 - 動的 block の場合も InnerBlocks.Content を保存する必要があります
import { InnerBlocks } from '@wordpress/block-editor';

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

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

<?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 - wp_kses_post() を使用しない ?>
</div>

useBlockProps

edit(useBlockProps())と save(useBlockProps.save())、カスタム props をマージ:

❌ BAD:useBlockProps がない

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

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

✅ GOOD:useBlockProps にカスタム props をマージ

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:Type 不一致、no default、非推奨 source

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

✅ GOOD:正しい type/source マッチング、default、モダンパターン

{
	"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 を使用する meta 属性(非推奨 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 } );
	};

	// value と updateMeta をコンポーネントで使用
}

Block コントロール

InspectorControls はサイドバー、BlockControls はツールバー、PanelBody、ToggleControl、SelectControl:

❌ BAD:設定がハードコード、sidebar コントロールなし

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>
		</>
	);
}

Block 非推奨化

deprecated 配列、save + attributes + migrate、エントリの apiVersion、最新から最初:

❌ BAD:非推奨化なしで save 関数が変更

// Save マークアップを変更 - 既存 block は 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:useBlockProps を追加(最新の非推奨化を最初)
		apiVersion: 2,
		attributes: {
			content: { type: 'string' },
		},
		save( { attributes } ) {
			return <div className="my-block">{ attributes.content }</div>;
		},
	},
	{
		// Version 1:オリジナル block
		apiVersion: 2,
		attributes: {
			content: { type: 'string' },
		},
		save( { attributes } ) {
			return <p>{ attributes.content }</p>;
		},
		migrate( attributes ) {
			// 古い属性を新しいスキーマに変換
			return {
				...attributes,
				newField: 'default',
			};
		},
	},
];

// 現在のバージョン
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 と directive(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 - フロントエンドストア(エディタコードではない)
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/* パッケージインポート vs 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 サポート

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
	}
}

Block variations

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' ],
	],
} );

Block トランスフォーム

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,
					} );
				},
			},
		],
	},
};

Block Context

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>
	);
}

Block hooks

blockHooks は動的 block でのみ:

❌ BAD:Block hooks を使用する静的 block

{
	"blockHooks": {
		"core/post-content": "after"
	}
}
// save.js - 静的 save = block hooks は機能しない
function save() {
	return <div>Content</div>;
}

✅ GOOD:Block hooks を使用する動的 block

{
	"blockHooks": {
		"core/post-content": "after"
	},
	"render": "file:./render.php"
}
// save.js - 動的 block(null save)= block hooks は機能する
function save() {
	return null;
}

@wordpress/scripts

package.json スクリプト設定:

❌ 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)

重要度定義
CRITICALBlock が render されない、またはエディタがクラッシュ、またはブロック validation error が発生apiVersion がない、または apiVersion 1/2 をマイグレーションパスなしで使用、save validation error の原因となる無効な属性タイプ、非推奨化エントリのない save 関数不一致、apiVersion 3 block に useBlockProps.save() がない、edit に InnerBlocks があるが save は null を返す(InnerBlocks.Content ではない)、InnerBlocks $content パラメータに wp_kses_post()、window.wp.* アクセスがモダンビルドを破壊、register_block_type() 呼び出しがない、非推奨の source:'meta' 属性パターン
WARNINGBlock は機能するが、品質/互換性の問題がある、またははい非標準パターン非推奨 API 使用法(apiVersion 1/2 重大問題がない場合)、block supports がない(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 がない、auto-insertion 用の block hooks 機会、共通プリセット用の block variations を追加できる、固定 InnerBlocks レイアウトに template lock がない

出力形式(BLK-24)

FILE 別(PHP と JS/JSX ファイルを実ファイルパスで混在)、行番号と重要度ラベル付けで結果をグループ化。各結果に BAD/GOOD コード対を使用。

# WordPress Block レビュー:my-block-plugin

## FILE:src/index.js

### 行 3:WARNING - レガシーグローバルアクセス
window.wp.* アクセスはレガシーパターン。モダンビルドツールチェーン用に @wordpress/* パッケージインポートを使用してください。

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

GOOD:

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

FILE:src/edit.js

行 12:CRITICAL - useBlockProps がない

edit 関数で useBlockProps() が呼び出されない。Block はエディタで正しく render されません。

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

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

apiVersion 3 block には useBlockProps.save() が必須。Block validation error が発生します。

BAD:

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

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
jorgerosal
リポジトリ
jorgerosal/wordpress-skills
ライセンス
MIT
最終更新
2026/4/17

Source: https://github.com/jorgerosal/wordpress-skills / ライセンス: MIT

関連スキル

汎用ソフトウェア開発⭐ リポ 39,967

doubt-driven-development

重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 1,175

apprun-skills

TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。

by yysun
OpenAIソフトウェア開発⭐ リポ 797

desloppify

コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。

by Git-on-my-level
汎用ソフトウェア開発⭐ リポ 39,967

debugging-and-error-recovery

テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

test-driven-development

テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

incremental-implementation

変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。

by addyosmani
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: jorgerosal · jorgerosal/wordpress-skills · ライセンス: MIT