关于 hyva-cms-component
为 Magento 2 项目交互式创建 Hyvä CMS 自定义组件的技能,面向开发者。它涵盖模块选择、字段配置、模板生成和升级设置。
主要功能
- 01在新建或现有模块中创建组件
- 02提供常用字段预设与自定义字段
- 03配置模板变体及子组件
- 04生成组件 JSON 与 PHTML 模板
- 05执行 Magento 升级设置
适用场景
- 01为 CMS 编辑器添加内容组件
- 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:新建模块
询问以下两项(不要在未询问的情况下假定默认值):
- 供应商名称(例如
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 步:选择字段
提供字段预设或自定义字段创建选项。可用预设(Basic Card、Image Card、CTA Block、Text Block、Feature Item、Testimonial、Accordion Item)请参阅 references/field-types.md 中的“Field Presets”部分;也可以允许用户自定义字段定义。
**权威字段类型:**如果有可用的项目实时列表,应优先使用该列表——通过 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 - 使用适当的转义方法转义所有用户内容
- 使用有意义的默认值,提升商家的使用体验
- 通过 include 引入设计/高级部分,以保持一致性
- 验证组件名称为 snake_case,且仅包含小写字母、数字和下划线
- 重要:使用
default_value键,而不是default——默认值的正确 JSON 键为default_value(带下划线),而不是default。示例:"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对象中。