hyva-cms-component について
Magento 2 で Hyvä CMS のカスタムコンポーネントを作成する開発者向けの対話型スキルです。モジュール選択、フィールド設定、テンプレート生成、セットアップ更新を案内します。
主な機能
- 01新規または既存モジュールでの作成
- 02フィールドプリセットとカスタムフィールド
- 03テンプレートバリアントと子コンポーネント設定
- 04コンポーネント JSON と PHTML テンプレート生成
- 05Magento のセットアップ更新
活用シーン
- 01CMS エディターへのコンテンツコンポーネント追加
- 02既存モジュールへのコンポーネント登録
- 03フィールドとテンプレートバリアントを持つコンポーネントの作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ hyva-themes/ hyva-ai-tools --skill hyva-cms-componentインストール後、Claude Code で/hyva-cms-componentを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/templates/component/template.phtml.tplreferences/component-schema.mdcritical-patterns.mdexample-component.mdfield-types.mdtroubleshooting.mdvariant-support.md詳細
Hyvä CMS コンポーネント作成ツール
概要
このスキルでは、Magento 2 用のカスタム Hyvä CMS コンポーネントを対話形式で作成できます。新規モジュールと既存モジュールの両方でコンポーネントを作成でき、よく使われるパターン向けのフィールドプリセットと、setup:upgrade の自動実行に対応しています。
コマンドの実行: 開発環境内で実行する必要があるコマンド(例:bin/magento)には、hyva-exec-shell-cmd スキルを使用して環境を検出し、適切なコマンドラッパーを特定してください。
ワークフロー
ステップ 1:モジュールの選択
プロンプトで指定されていない場合は、コンポーネントの作成先をユーザーに尋ねます。
オプション A:新規モジュール
次の 2 つの値を両方とも尋ねます(確認せずにデフォルト値を仮定しないでください)。
- ベンダー名(例:
Acme)- 必須。デフォルト値はありません。ベンダー名を提案せず、ユーザーに入力を求めてください。 - モジュール名 - デフォルト値として
CmsComponentsを提案し、ユーザーが Enter キーを押して受け入れられるようにします。
次に、hyva-create-module スキルを次の内容で使用します。
dependencies:["Hyva_CmsBase"]composer_require:{"hyva-themes/commerce-module-cms": "^1.0"}
オプション B:既存のモジュール
- モジュールのパスを尋ねます(
app/code/、vendor/、またはカスタムの場所を指定できます)。 etc/module.xmlで、モジュールにHyva_CmsBaseが依存関係として指定されていることを確認します。指定されていない場合は追加します。composer.jsonで、モジュールにhyva-themes/commerce-module-cmsが依存関係として指定されていることを確認します。指定されていない場合は追加します。
ステップ 2:コンポーネントの詳細
コンポーネントの情報を収集します。
-
コンポーネント名(snake_case。例:
feature_card) -
ラベル(エディターでの表示名。例:「Feature Card」)
-
カテゴリ(Layout、Elements、Media、Content、または Other)
-
アイコン - 適切なアイコンを自動的に選択します。
ステップ 4a:すでに使用されているアイコンを特定する
hyva-cms-components-dumpスキルを使用して、現在のすべての CMS コンポーネントを出力します。出力からすべてのicon値を抽出し、既存のコンポーネントで使用されているアイコンの一覧を作成します。ステップ 4b:使用可能な lucide アイコンを見つける
vendor/hyva-themes/magento2-theme-module/src/view/base/web/svg/lucide/内の SVG ファイルを一覧表示し、使用可能なアイコンをすべて確認します。ステップ 4c:最適なアイコンを選択する 使用可能な lucide アイコンのうち、ほかのコンポーネントでまだ使われていないものから、次のように選びます。
- 新しいコンポーネントの目的や意味に最も合った名前のアイコンを選択します。
- 意味も考慮します(例:カート関連には
shopping-cart.svg、画像関連にはimage.svg、グリッドレイアウトにはlayout-grid.svg)。 - 選択したアイコンは
Hyva_Theme::svg/lucide/[icon-name].svgの形式にします。
適切な未使用アイコンが見つからない場合、または lucide ディレクトリが存在しない場合は、
iconプロパティを設定しないでください。
ステップ 3:フィールドの選択
フィールドプリセットを提示するか、カスタムフィールドの作成を案内します。使用可能なプリセットについては、references/field-types.md の「Field Presets」セクションを参照してください(Basic Card、Image Card、CTA Block、Text Block、Feature Item、Testimonial、Accordion Item)。または、カスタムフィールドの定義を許可します。
フィールドタイプの正確な情報源: 使用可能な場合は、プロジェクトの最新の一覧を優先してください。hyva-exec-shell-cmd ラッパーを使って bin/magento hyva:cms:list-fields(コアおよびカスタムのフィールドタイプ)を実行します。このコマンドを使用できない場合に限り、references/field-types.md を参照してください。
カスタムフィールドの場合は、フィールドごとに次の項目を尋ねます。
- フィールド名(snake_case)
- フィールドタイプ(
references/field-types.mdを参照) - ラベル
- デフォルト値(任意)
- 必須かどうか(はい/いいえ)- 注:これは直接のフィールドプロパティではなく、
attributes.requiredとして追加されます。 - 追加属性(
attributesオブジェクトに追加します)
ステップ 4:バリアントのサポート
コンポーネントにテンプレートバリアントが必要かどうかを尋ねます。
- 必要な場合:バリアント名とラベルを収集します(例:default、compact、wide)。設定の詳細は
references/variant-support.mdを参照してください。 - 不要な場合:単一のテンプレートを使用します。
ステップ 5:ファイルの生成
必要なファイルを作成します。
新規モジュールの場合
hyva-create-module スキルによってベースモジュールの構造が作成されます。その後、CMS 固有のディレクトリを追加します。
app/code/[Vendor]/[Module]/
├── registration.php # Created by hyva-create-module
├── composer.json # Created by hyva-create-module
├── etc/
│ ├── module.xml # Created by hyva-create-module
│ └── hyva_cms/
│ └── components.json # Create this
└── view/
└── frontend/
└── templates/
└── elements/
└── [component-name].phtml (or [component-name]/ for variants)
既存のモジュールの場合
作成または更新します:
etc/hyva_cms/components.json(既存ファイルがある場合はマージします)view/frontend/templates/elements/[component-name].phtml
ステップ 6:セットアップを実行する
ファイルの作成後、hyva-exec-shell-cmd スキルによって検出された適切なコマンドラッパーを使用して、bin/magento setup:upgrade を実行します。
ファイル生成の詳細
components.json の構造
{
"[component_name]": {
"label": "[Label]",
"category": "[Category]",
"template": "[Vendor]_[Module]::elements/[component-name].phtml",
"content": {
// Generated fields
},
"design": {
"includes": [
"Hyva_CmsBase::etc/hyva_cms/default_design.json",
"Hyva_CmsBase::etc/hyva_cms/default_design_typography.json"
]
},
"advanced": {
"includes": [
"Hyva_CmsBase::etc/hyva_cms/default_advanced.json"
]
}
}
}
有効なコンポーネントプロパティ
重要: コンポーネントレベルで許可されているプロパティは特定のものに限られます。スキーマの完全なリファレンスについては、references/component-schema.md を参照してください。
主なプロパティ:label(必須)、category、template、icon、children、require_parent、content、design、advanced、disabled、custom_properties。
スキーマエラーの原因となる無効なプロパティ:
hidden- 存在しません。子専用コンポーネントにはrequire_parent: trueを、またはdisabled: trueを使用してください- スキーマリファレンスに記載されていないプロパティ
子要素の設定(重要)
重要: children はルートレベルのコンポーネントプロパティであり、content、design、advanced 内のフィールド型ではありません。
誤り ❌:
{
"my_component": {
"content": {
"items": {
"type": "children",
"label": "Items"
}
}
}
}
正しい ✅:
{
"my_component": {
"label": "My Component",
"children": {
"config": {
"accepts": ["child_component"],
"max_children": 10
}
},
"content": {
"title": {
"type": "text",
"label": "Title"
}
}
}
}
テンプレートでは、カスタムフィールド名ではなく、$block->getData('children') を使って子要素にアクセスしてください。
フィールドの検証(重要)
重要: required などのフィールド検証属性は、フィールドの直接のプロパティではなく、attributes オブジェクト内に配置する必要があります。
誤り ❌:
{
"title": {
"type": "text",
"label": "Title",
"required": true
}
}
正しい ✅:
{
"title": {
"type": "text",
"label": "Title",
"attributes": {
"required": true
}
}
}
attributes に指定するその他の検証属性:
required(ブール値)minlength/maxlength(文字列)min/max(数値用)pattern(正規表現文字列)placeholder(文字列)comment(ヘルプテキスト)- 検証メッセージ用のカスタムデータ属性
子専用コンポーネント
リスト項目のように、他のコンポーネントの子としてのみ使用するコンポーネントには、require_parent: true を使用します:
{
"my_list_item": {
"label": "My List Item",
"category": "Elements",
"require_parent": true,
"template": false,
"content": {
"title": {"type": "text", "label": "Title"}
}
},
"my_list": {
"label": "My List",
"category": "Elements",
"template": "Vendor_Module::elements/my-list.phtml",
"children": {
"config": {
"accepts": ["my_list_item"]
}
}
}
}
template: false の場合、親コンポーネントは子データを直接レンダリングします($block->createChildHtml() は使用しません)。「template: false で子要素をレンダリングする」を参照してください。
PHTML テンプレートの構造
すべてのテンプレートは、次のヘッダーで始める必要があります:
<?php
declare(strict_types=1);
use Hyva\CmsLiveviewEditor\Block\Element;
use Hyva\Theme\Model\ViewModelRegistry;
use Magento\Framework\Escaper;
/** @var Element $block */
/** @var Escaper $escaper */
/** @var ViewModelRegistry $viewModels */
追加要件:
- ルート要素に
$block->getEditorAttrs()を指定します - 編集可能な要素に
$block->getEditorAttrs('field_name')を指定します $escaper->escapeHtml()と$escaper->escapeHtmlAttr()で適切にエスケープします
フィールドタイプ別のテンプレートパターン
テキストフィールド:
$title = $block->getData('title');
// In template:
<?php if ($title): ?>
<h2 <?= /** @noEscape */ $block->getEditorAttrs('title') ?>>
<?= $escaper->escapeHtml($title) ?>
</h2>
<?php endif; ?>
リッチテキスト/HTML フィールド:
$content = $block->getData('content');
// In template (no escaping for richtext):
<?php if ($content): ?>
<div <?= /** @noEscape */ $block->getEditorAttrs('content') ?>>
<?= /** @noEscape */ $content ?>
</div>
<?php endif; ?>
画像フィールド:
画像をレンダリングするには、hyva-render-media-image スキルを使用します。このスキルには、\Hyva\Theme\ViewModel\Media ビューモデルの完全な API リファレンスとコードパターンが含まれています。
画像をレンダリングする際は、次のインポートを追加します。
// Additional imports for templates with images:
use Hyva\Theme\ViewModel\Media;
/** @var Media $mediaViewModel */
$mediaViewModel = $viewModels->require(Media::class);
$block->getData('image') のデータは、getResponsivePictureHtml() に直接渡すことができます。
$image = $block->getData('image');
// In template:
<?php if ($image): ?>
<?= /** @noEscape */ $mediaViewModel->getResponsivePictureHtml(
$image,
['class' => 'w-full h-auto', 'loading' => 'lazy']
) ?>
<?php endif; ?>
デスクトップ用とモバイル用で異なるソースを使用するレスポンシブ画像については、hyva-render-media-image スキルを参照してください。
リンクフィールド:
$link = $block->getData('link');
$linkData = $link ? $block->getLinkData($link) : null;
// In template:
<?php if ($linkData): ?>
<a href="<?= $escaper->escapeUrl($linkData['url']) ?>"
<?php if (!empty($linkData['target'])): ?>target="<?= $escaper->escapeHtmlAttr($linkData['target']) ?>"<?php endif; ?>>
<?= $escaper->escapeHtml($linkData['title'] ?: 'Read more') ?>
</a>
<?php endif; ?>
ブール値フィールド:
$showTitle = (bool) $block->getData('show_title');
// In template:
<?php if ($showTitle && $title): ?>
<?php endif; ?>
セレクトフィールド:
$style = $block->getData('style') ?: 'default';
$styleClasses = match($style) {
'primary' => 'bg-blue-600 text-white',
'secondary' => 'bg-gray-200 text-gray-800',
default => 'bg-white text-gray-600'
};
子フィールド(独自のテンプレートを持つ場合):
子コンポーネントが独自のテンプレートを持つ場合(デフォルトの動作)は、$block->createChildHtml() を使用します。
$children = $block->getData('children') ?: [];
// In template:
<?php foreach ($children as $index => $child): ?>
<?= /** @noEscape */ $block->createChildHtml($child, 'child-' . $index) ?>
<?php endforeach; ?>
template: false の子要素のレンダリング:
子コンポーネントに "template": false が設定されている場合、親コンポーネントが子要素を直接レンダリングします。子のデータはフラットです。フィールド値は子の配列に直接含まれ、content キーの下にはネストされません。
$children = $block->getData('children') ?: [];
// In template - iterate and access child data directly:
<?php foreach ($children as $elementData): ?>
<?php
// Access fields directly on $elementData (NOT $elementData['content']['field'])
$image = $elementData['image'] ?? null;
$title = $elementData['title'] ?? '';
$description = $elementData['description'] ?? '';
// Each child has a 'uid' for editor attributes
$childUid = $elementData['uid'];
?>
<div <?= /** @noEscape */ $block->getEditorAttrs('', $childUid) ?>>
<?php if (!empty($image['src'])): ?>
<?php // For image rendering patterns, see the hyva-render-media-image skill ?>
<?= /** @noEscape */ $mediaViewModel->getResponsivePictureHtml(
[$block->getResponsiveImageData($image)],
['alt' => $image['alt'] ?? '', 'class' => 'w-full h-auto', 'loading' => 'lazy']
) ?>
<?php endif; ?>
<p <?= /** @noEscape */ $block->getEditorAttrs('title', $childUid) ?>>
<?= $escaper->escapeHtml($title) ?>
</p>
</div>
<?php endforeach; ?>
template: false の子要素に関する重要なポイント:
- 子フィールドのデータはフラットです。
$elementData['field_name']を使用し、$elementData['content']['field_name']は使用しないでください。 - 各子要素には、エディター属性用の
uidプロパティがあります。 - 子フィールドのライブ編集を有効にするには、
$block->getEditorAttrs('field_name', $childUid)を使用します。 - 子要素のルート要素には、
$block->getEditorAttrs('', $childUid)を使用します。 - 画像の場合は
!empty($image['src'])を確認し、画像データの処理には$block->getResponsiveImageData($image)を使用します。 - 高度な画像レンダリングパターン(レスポンシブブレークポイントなど)については、
hyva-render-media-imageスキルを参照してください。
リソース
references/critical-patterns.md
最初にお読みください — 次の内容を含む、重要なパターンとよくある間違い:
- 正しい
children設定(ルートレベルとフィールドタイプ) attributesを使用した適切なフィールド検証- デフォルト値の構文
- コンポーネントを生成する前の簡易チェックリスト
よくあるエラーを避けるため、コンポーネントを生成する前にこのファイルをお読みください。
references/example-component.md
Feature Card コンポーネントの、最初から最後まで網羅した完全な例です。次の内容が含まれています。
- 完全な
components.json定義 - すべてのフィールドタイプに対応する PHTML テンプレート
- 関連するモジュールファイル(registration.php、module.xml、composer.json)
- ディレクトリー構成の概要
各要素がどのように連携するかを確認する必要がある場合は、このファイルをお読みください。
コンポーネント/フィールドのスキーマ(プロジェクトから読み込み、バンドル版をフォールバックとして使用)
Hyvä CMS のスキーマは、プロジェクトのバージョンによって異なります。インストール済みの Hyvä Commerce パッケージにあるライブスキーマを優先してください。
vendor/hyva-themes/commerce-module-cms/src/liveview-editor/etc/hyva_cms/jsonschema/
が存在する場合は、このプロジェクトで信頼できるコンポーネントとフィールドの宣言として、その JSON ファイルを直接読み取ってください(インタープリターは不要です)。
component-declaration.json— 有効なコンポーネントレベルのプロパティcomponent-field-declaration.json— フィールド宣言のプロパティ、フィールドタイプ、検証属性
Hyvä Commerce がインストールされていない場合に限り、バンドル版の
references/component-schema.md を使用してください。コンポーネント構造を検証する場合や、スキーマ検証エラーが発生した場合は、いずれかのソースをお読みください。
バンドル版の
references/component-schema.mdは、フォールバック用のスナップショットです。Hyvä CMS の更新後に内容を更新するには、上記のjsonschema/*.jsonファイルを読み取って再生成してください。ヘルパースクリプトは不要です。
references/field-types.md
サポートされるすべてのフィールドタイプを網羅したリファレンスです。次の内容が含まれています。
- フィールド設定の構文
- 使用可能なすべてのフィールドタイプと例
- 検証属性
- 条件付き表示(show_if/hide_if)
- 一般的なパターン向けのフィールドプリセット
フィールド設定を生成する際は、このファイルをお読みください。
references/variant-support.md
テンプレートのバリアントを実装するためのガイドです。以下の内容を含みます。
- バリアントテンプレートのディレクトリ構造
- components.json でのバリアントフィールドの設定
- テンプレートの実装パターン
- 一般的なバリアントパターンとベストプラクティス
コンポーネントに複数のレイアウトオプションを用意する場合は、このファイルをお読みください。
references/troubleshooting.md
以下を含む、よくある問題の解決策です。
- スキーマ検証エラー
- コンポーネントがエディターに表示されない
- テンプレートがレンダリングされない
- ライブエディターが動作しない
- 画像の表示に関する問題
- 依存するスキルを利用できない場合のフォールバック
コンポーネントの作成またはテスト中にエラーが発生した場合は、このファイルをお読みください。
assets/templates/component/template.phtml.tpl
CMS コンポーネント用の基本的な PHTML 構造です。
プレースホルダー:
{{CONTENT_FIELDS}}- PHP 変数の宣言{{TEMPLATE_BODY}}- HTML テンプレートの内容
重要なガイドライン
- ルート要素と各編集可能フィールド要素で、必ず
getEditorAttrs()を使用してください - テンプレートで
<script>タグを使用しないでください。alpine:initイベントを介して Alpine.js を使用してください - すべてのユーザーコンテンツを適切なエスケーパーのメソッドでエスケープしてください
- マーチャントの利便性を高めるため、意味のあるデフォルト値を使用してください
- 一貫性を保つため、インクルードを介してデザイン/詳細セクションを含めてください
- コンポーネント名が snake_case で、小文字、数字、アンダースコアのみを使用していることを検証してください
- 重要:
defaultではなくdefault_valueキーを使用してください - デフォルト値に使用する正しい JSON キーはdefaultではなく、default_value(アンダースコア付き)です。例:"default_value": "My Title"✅、"default": "My Title"❌ - 重要:
childrenはルートレベルのプロパティであり、フィールドタイプではありません - content/design/advanced で"type": "children"を使用しないでください。childrenはコンポーネントのルートレベルで宣言してください。テンプレートでは$block->getData('children')を介してアクセスします。 - 重要:検証設定は
attributesに記述し、直接のプロパティとして記述しないでください -"attributes": {"required": true}✅ を使用し、"required": true❌ は使用しないでください。すべての HTML5 検証属性(required、minlength、maxlength、pattern、min、max)はattributesオブジェクト内に記述する必要があります。