mcpField
H
hyva-cms-custom-field

hyva-cms-custom-field

github.com/hyva-themes開発85755 回インストール13 週間前に更新
リポジトリ

hyva-cms-custom-field について

Hyvä CMS のエディター入力を拡張するカスタムフィールド型やハンドラーを作る開発者向けのスキルです。基本フィールド、インライン、モーダル型を選び、テンプレート作成と登録を進めます。

主な機能

  1. 01基本、インライン、モーダル型に対応
  2. 02フィールドとハンドラーのテンプレート生成
  3. 03カスタムフィールド型の登録
  4. 04モーダル型のレイアウト登録
  5. 05フィールドの使用例を提示

活用シーン

  1. 01エディターへのカラーピッカー追加
  2. 02商品選択またはリンク設定モーダルの作成
  3. 03カスタム入力のバリデーション実装

インストール

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

$npx skills add https://github.com/hyva-themes/hyva-ai-tools --skill hyva-cms-custom-field

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

同梱ファイル

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

assets/templates/
basic-field.phtml.tpl
inline-handler.phtml.tpl
modal-field.phtml.tpl
modal-handler.phtml.tpl
references/
built-in-handlers.md
handler-communication.md
handler-patterns.md
template-requirements.md

詳細

Hyvä CMS カスタムフィールドタイプ作成ツール

概要

このスキルでは、Hyvä CMS コンポーネント向けのカスタムフィールドタイプとフィールドハンドラーの作成方法を説明します。カスタムフィールドタイプを使用すると、CMS エディターインターフェースに、組み込みフィールドタイプ(テキスト、テキストエリア、セレクトなど)を拡張した専用の入力コントロールを追加できます。

カスタムフィールドには 2 種類あります:

  1. 基本カスタムフィールドタイプ:データを直接入力するカスタム入力コントロール(日付範囲、カラーピッカー、カスタムバリデーションなど)
  2. フィールドハンドラー:複雑な操作に対応した拡張 UI(画像付き商品セレクター、検索可能なドロップダウン、リンク設定モーダルなど)

コマンドの実行: 開発環境内で実行する必要があるコマンド(例:bin/magento)には、hyva-exec-shell-cmd スキルを使用して環境を検出し、適切なコマンドラッパーを特定してください。

ワークフロー

ステップ 1:モジュールの選択

プロンプトでまだ指定されていない場合は、カスタムフィールドタイプを作成する場所を決定します。

オプション A:新しいモジュール

hyva-create-module スキルを次の設定で使用します:

  • dependencies:["Hyva_CmsBase", "Hyva_CmsLiveviewEditor"]
  • composer_require:{"hyva-themes/commerce-module-cms": "^1.0"}

オプション B:既存のモジュール

モジュールに必要な依存関係があることを確認します:

  • etc/module.xml に Hyva_CmsBase と Hyva_CmsLiveviewEditor が含まれている
  • composer.json に hyva-themes/commerce-module-cms が含まれている

不足している依存関係があれば追加します。

ステップ 2:フィールドタイプの詳細

カスタムフィールドタイプに関する情報を収集します:

  1. フィールドタイプ名(date_range、product_selector、color_picker などの小文字の識別子)
  2. 目的(どのようなデータを収集するか)
  3. UI パターン:
    • 基本フィールド:バリデーション付きのシンプルな入力(日付ピッカー、パターン入力、拡張テキストフィールド)
    • インラインハンドラー:フィールド領域内の拡張コントロール(検索可能なドロップダウン、カラーピッカー)
    • モーダルハンドラー:複雑な選択用の個別ダイアログ(商品セレクター、リンクビルダー、メディアギャラリー)
  4. データ構造(単純な文字列、JSON オブジェクト、配列など)
  5. バリデーション要件(パターン、必須、カスタムルールなど)
ステップ 3:実装パターンの選択

ステップ 2 で特定した UI パターンに基づいて選択します:

パターン A:基本カスタムフィールドタイプ

カスタム HTML5 バリデーションや専用の入力コントロールを使うシンプルな入力向けです:

  • フィールド用テンプレートファイル 1 つ
  • 個別のハンドラーモーダルなし
  • 例:日付範囲セレクター、カスタムパターンバリデーション、スライダー入力

パターン B:インラインフィールドハンドラー

フィールド領域内に表示される拡張コントロール向けです:

  • Alpine.js コンポーネントを含むテンプレートファイル 1 つ
  • 個別のハンドラーモーダルなし
  • 例:検索可能なセレクトドロップダウン、スウォッチ付きカラーピッカー

パターン C:モーダルベースのフィールドハンドラー

より広いスペースを必要とする複雑な選択インターフェース向けです:

  • フィールドテンプレート(選択内容と起動ボタンを表示)
  • ハンドラーモーダルテンプレート(UI 全体を含む個別ダイアログ)
  • ハンドラーを登録するレイアウト XML
  • 例:商品セレクター、リンク設定、メディアギャラリー

各タイプの詳しい実装パターンとコード例については、references/handler-patterns.md を参照してください。

ステップ 4:フィールドテンプレートの生成

フィールドテンプレートを view/adminhtml/templates/field-types/[field-type-name].phtml に作成します。

テンプレートに必要な要素:

  1. 適切な ID を持つフィールドコンテナー:field-container-{uid}_{fieldName}
  2. 名前が {uid}_{fieldName} の入力要素
  3. バリデーションメッセージ用コンテナー:validation-messages-{uid}_{fieldName}
  4. 値の変更時に呼び出す updateWireField() または updateField()
  5. $magewire->errors を使ったエラー状態の処理
  6. 重要: フィールド値には null 合体演算子を使用します:$block->getData('value') ?? ''(型キャストは使用しないでください)

assets/templates/ にある適切なテンプレートを使用します:

  • basic-field.phtml.tpl - 基本カスタムフィールドタイプ
  • inline-handler.phtml.tpl - インライン拡張コントロール
  • modal-field.phtml.tpl - モーダルハンドラーのフィールドテンプレート

テンプレートの詳しい要件とパターンについては、references/template-requirements.md を参照してください。

ステップ 5:ハンドラーモーダルを生成する(必要な場合)

モーダルベースのハンドラーの場合のみ、view/adminhtml/templates/handlers/[handler-name]-handler.phtml にハンドラーテンプレートを作成します。

ハンドラーモーダルの構造:

  1. Alpine.js コンポーネントと open:flex クラス(静的な flex ではありません)を持つ <dialog> 要素
  2. フィールドテンプレートからの初期化イベントをリッスンする
  3. 選択 UI(検索、フィルター、グリッドなど)を実装する
  4. 保存時に editor-change イベントをディスパッチする

出発点として assets/templates/modal-handler.phtml.tpl を使用してください。

イベントプロトコルとデータ交換パターンについては、references/handler-communication.md を参照してください。

ステップ 6:フィールドタイプを登録する

etc/adminhtml/di.xml に登録を追加します。

<type name="Hyva\CmsLiveviewEditor\Model\CustomField">
    <arguments>
        <argument name="customTypes" xsi:type="array">
            <item name="[field_type_name]" xsi:type="string">
                [Vendor]_[Module]::field-types/[field-type-name].phtml
            </item>
        </argument>
    </arguments>
</type>
ステップ 7:ハンドラーモーダルを登録する(必要な場合)

モーダルベースのハンドラーの場合のみ、view/adminhtml/layout/liveview_editor.xml を作成または更新します。

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="before.body.end">
            <block name="[handler_name]_handler"
                   template="[Vendor]_[Module]::handlers/[handler-name]-handler.phtml"/>
        </referenceContainer>
    </body>
</page>

注: インラインハンドラーにはレイアウト XML の登録は不要です。

ステップ 8:使用例

components.json でカスタムフィールドタイプを使用する例を示します。

{
    "my_component": {
        "label": "My Component",
        "content": {
            "[field_name]": {
                "type": "custom_type",
                "custom_type": "[field_type_name]",
                "label": "Field Label",
                "attributes": {
                    "required": true,
                    "pattern": ".*"
                }
            }
        }
    }
}

リソース

references/template-requirements.md

カスタムフィールドタイプのテンプレート要件に関する完全なリファレンスです。

  • 必須のマークアップパターンと要素 ID
  • フィールドコンテナーの構造
  • バリデーションメッセージコンテナー
  • フィールド値の更新方法(updateWireField と updateField)
  • HTML5 バリデーション属性
  • エラー状態の処理

CMS エディターと適切に連携できるよう、フィールドテンプレートを実装する際にこのファイルをお読みください。

references/handler-patterns.md

3 種類すべてのカスタムフィールドタイプの実装パターンです。

  • 基本的なカスタムフィールドタイプ(シンプルな入力)
  • インラインフィールドハンドラー(拡張コントロール)
  • モーダルベースのフィールドハンドラー(ダイアログでの選択)

各パターンには、以下が含まれます。

  • 完全なコード例
  • 各パターンを使用する場面
  • Alpine.js コンポーネントの構造
  • データフローと状態管理

実装パターンを選択し、テンプレートコードを書く際にこのファイルをお読みください。

references/handler-communication.md

フィールドハンドラーのイベントプロトコルとデータ交換について説明します。

  • 初期化イベントの構造
  • 保存イベントの構造
  • フィールド値のエンコードとデコード
  • エラー処理パターン
  • よくある落とし穴と解決策

通信プロトコルを理解するため、ハンドラーモーダルを実装する際にこのファイルをお読みください。

references/built-in-handlers.md

Hyvä CMS の組み込みフィールドハンドラーに関するリファレンスです。

  • Product Handler(モーダルベース、画像グリッドでの選択)
  • Link Handler(モーダルベース、複数タイプのリンク設定)
  • Searchable Select(インラインの拡張ドロップダウン)

それぞれに以下が含まれます。

  • Hyvä CMS モジュール内の場所
  • 主な機能とパターン
  • 使用例
  • パターンを確認するためのコード

実装例やコピーできるパターンを探す際に、このファイルをお読みください。

assets/templates/basic-field.phtml.tpl

カスタムバリデーションまたは入力コントロールを備えた基本的なカスタムフィールドタイプ用のテンプレートです。

プレースホルダー:

  • {{FIELD_TYPE_NAME}} - カスタムフィールドタイプの識別子
  • {{FIELD_INPUTS}} - 入力要素の HTML
  • {{VALIDATION_LOGIC}} - カスタムバリデーション用 JavaScript(任意)
assets/templates/inline-handler.phtml.tpl

インラインの拡張コントロール(検索可能なドロップダウン、カラーピッカーなど)用のテンプレートです。

プレースホルダー:

  • {{HANDLER_NAME}} - Alpine.js コンポーネント名
  • {{HANDLER_LOGIC}} - Alpine.js コンポーネントの実装
  • {{HANDLER_UI}} - 拡張コントロールの HTML
assets/templates/modal-field.phtml.tpl

モーダルベースのハンドラー用フィールドテンプレート(トリガーボタン+非表示入力)です。

プレースホルダー:

  • {{EVENT_NAME}} - ディスパッチするカスタムイベント名
  • {{BUTTON_LABEL}} - ボタンのテキスト
  • {{DISPLAY_VALUE}} - 現在選択されている項目の表示
assets/templates/modal-handler.phtml.tpl

モーダルベースの選択インターフェース用ハンドラーモーダルテンプレートです。

プレースホルダー:

  • {{HANDLER_NAME}} - Alpine.js コンポーネント名
  • {{MODAL_TITLE}} - ダイアログのヘッダーテキスト
  • {{SELECTION_UI}} - 選択インターフェースの HTML
  • {{SAVE_LOGIC}} - 保存ボタンのロジック

重要なガイドライン

コア要件
  1. テンプレート要件:すべてのカスタムフィールドタイプは、必須のマークアップパターン(コンテナー ID、入力名、検証メッセージ)に従う必要があります
  2. ハンドラーの登録:モーダルハンドラーにはレイアウト XML への登録が必要ですが、インラインハンドラーには必要ありません
  3. 検証:自動検証のため、$filteredAttributes を使用して HTML5 の検証属性を適用してください
  4. Alpine コンポーネント:カスタム Alpine コンポーネントを使用する場合は、入力フィールドをコンポーネントの外に配置し、バニラ JS で更新してください
  5. 組み込みの例:実績のあるパターンについては、Hyva_CmsLiveviewEditor::page/js/ の組み込みハンドラーを参照してください
コードベースに基づく正確なパターン

組み込みの Hyvä CMS ハンドラー実装に基づきます。

  1. イベント命名規則:toggle-{type}-select パターンを使用します

    • ✅ 正しい例:toggle-product-select、toggle-link-select、toggle-category-select
    • ❌ 誤った例:toggle-product-handler、toggle-link-handler
  2. ハンドラー関数の命名:init{Type}Select() パターンを使用します

    • ✅ 例:initProductSelect()、initLinkSelect()、initCategorySelect()
  3. フィールド値の更新方法:

    • updateWireField を使用(デフォルト):Product、Link、Category のハンドラー
      • Magewire によるサーバー側の検証を即座に実行します
      • コンポーネントの状態を同期したままにします
    • updateField を使用(専用):Image ハンドラー、デバウンス入力(color、range)
      • サーバーへのラウンドトリップなしでプレビューを更新します
      • 検証は保存時まで保留します
  4. JSON エンコードのパターン:複雑なデータ(配列、オブジェクト)はすべて JSON エンコードする必要があります

    // Field template
    value="<?= $escaper->escapeHtmlAttr(json_encode($fieldValue)) ?>"
    
    // Handler initialization
    const data = JSON.parse(fieldValue);
    
    // @change handler
    @change="updateWireField(..., JSON.parse($event.target.value))"
    
  5. Livewire との互換性のための wire:ignore:検索可能なセレクトでは wire:ignore ラッパーを使用します

    <div wire:ignore>
        <div x-data="initSearchableSelect(...)">
            
        </div>
    </div>
    
  6. ハンドラーファイルの分離:インラインハンドラーであっても、関数を別ファイルに分ける場合があります

    • フィールドテンプレート:liveview/field-types/searchable_select.phtml
    • ハンドラー関数:page/js/searchable-select-handler.phtml
  7. Icons View Model:UI 要素に使用します

    /** @var Icons $icons */
    $icons = $viewModels->require(Icons::class);
    <?= /** @noEscape */ $icons->trashHtml('', 22, 22) ?>
    
  8. FieldTypes View Model:属性のフィルタリングに使用します

    /** @var FieldTypes $fieldTypes */
    $fieldTypes = $viewModels->require(FieldTypes::class);
    $filteredAttributes = $fieldTypes->getDefinedFieldAttributes($attributes);
    // Or for specific attributes:
    $filteredAttributes = $fieldTypes->getAttributesByKeys($attributes, ['required', 'data-required']);
    
  9. 重要:Layout XML の referenceContainer:ハンドラーモーダルには必ず before.body.end コンテナを使用してください

    • ✅ 正しい例:<referenceContainer name="before.body.end">
    • ❌ 誤った例:<referenceContainer name="content">
    • before.body.end コンテナを使うと、ハンドラーモーダルがページの body の末尾に読み込まれます。これは、Alpine.js の初期化とモーダル機能を正常に動作させるために必要です
  10. 重要:フィールド値の型の扱い:フィールド値には型キャストを絶対に使用せず、常に null 合体演算子を使用してください

  • ✅ 正しい例:$fieldValue = $block->getData('value') ?? '';
  • ❌ 誤った例:$fieldValue = (string) $block->getData('value');
  • 値が null の場合、型キャスト (string) は失敗し、PHP エラーが発生します
  • 文字列値には ?? ''、配列値には ?? []、またはデータ型に適したデフォルト値を使用してください
  • 参照先:?? [] パターンを使用している category.phtml などの組み込みフィールドタイプを確認してください
  1. 重要:ダイアログモーダルのクラス:ハンドラーモーダルには、静的な flex クラスではなく open:flex を使用してください
  • ✅ 正しい例:<dialog class="... open:flex flex-col">
  • ❌ 誤った例:<dialog class="... flex flex-col">(モーダルが常に表示されます)
  • open: プレフィックスを付けると、ダイアログが開いているとき(ネイティブ HTML ダイアログの状態)にのみスタイルが適用されます
  • 参照先:open:flex flex-col を使用している category-handler.phtml などの組み込みハンドラーを確認してください
  1. 重要:複雑なデータ型の扱い:JSON/配列データを保存するフィールドでは、配列型と文字列型の両方に対応してください
  • フィールド値は、デコード済みの配列として返される場合と、JSON 文字列として返される場合があります(ストレージ/コンテキストによって異なります)
  • ✅ 正しいパターン:
    $data = ['default' => 'structure'];
    if ($fieldValue) {
        if (is_array($fieldValue)) {
            $data = $fieldValue;  // デコード済み
        } elseif (is_string($fieldValue)) {
            $decoded = json_decode($fieldValue, true);
            if (is_array($decoded)) {
                $data = $decoded;
            }
        }
    }
    
    // hidden input に出力する場合は、必ず JSON 文字列にする
    $fieldValueJson = is_array($fieldValue) ? json_encode($fieldValue) : $fieldValue;
    
  • ❌ 誤り:型を確認せずに json_decode($fieldValue) を使用する(値がすでに配列の場合に失敗します)
  • ❌ 誤り:JSON エンコードせずに配列を value 属性で直接使用する

コメント