mcpField
C
craft-content-modeling

craft-content-modeling

github.com/michtio开发8679 次安装1 天前更新
代码仓库

关于 craft-content-modeling

craft-content-modeling 是用于规划 Craft CMS 5 内容架构的技能,面向开发者和内容架构师。它帮助选择分区类型、条目类型、字段与关系,并说明 Craft 5 以条目为核心的模型。

主要功能

  1. 01按内容需求选择分区类型
  2. 02规划可复用的条目类型与字段
  3. 03设计内容关系和 Matrix 用法
  4. 04讲解 Craft 5 的条目中心架构
  5. 05考虑版本与权限限制
  6. 06识别保留字段句柄

适用场景

  1. 01规划博客、层级页面或全站设置
  2. 02使用条目和分区设计分类体系
  3. 03选择内容条目之间的关联方式
  4. 04定义内容模型前检查字段句柄

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/michtio/craftcms-claude-skills --skill craft-content-modeling

安装后在 Claude Code 中输入/craft-content-modeling确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
content-patterns.md
element-index-sources.md
field-types.md
infrastructure.md
object-templates.md
relations-and-eager-loading.md
users-and-permissions.md

详细介绍

Craft CMS 5 — 内容建模

如何在 Craft CMS 5 中组织内容结构。涵盖分区、条目类型、字段、Matrix、 关联、资源管理,以及适用于实际项目的策略模式。

本技能涵盖内容架构——控制面板(CP)中包含什么、如何组织,以及模板如何访问这些内容。要使用 PHP 扩展 Craft (插件、模块、自定义元素类型),请参阅 craftcms 技能。

配套技能 — 始终一并加载

触发此技能时,还要加载:

  • craft-site — 模板架构、组件模式、路由。当内容决策影响模板如何呈现数据时必需。
  • craft-twig-guidelines — Twig 编码规范。当内容建模同时需要编写 Twig 示例或模板代码时必需。
  • ddev — 所有命令都通过 DDEV 运行。运行项目配置命令、Craft CLI 和内容迁移时必需。

文档

如果参考文件未涵盖足够细节,请使用 WebFetch 查看具体文档页面。

Craft 5 的思维模型

一切都在变成条目。 条目类型是全局的(可在各分区和 Matrix 字段间共享)。字段来自全局字段池。这就是 Craft 的“条目化”——类别、标签和全局集将在三个版本的周期中逐步统一为条目:

  • Craft 4.4 — 新增 entrify CLI 命令,可将类别、标签和全局集转换为条目
  • Craft 5 — 类别、标签和全局集已弃用,不建议新项目使用。仍可在 CP 中创建新的类别组、标签组和全局集(“New”按钮仍然存在,但受 allowAdminChanges 控制),现有内容也会继续正常工作。统一的“Content”分区取代了零散的条目视图。自定义条目索引页面(5.9.0)解决了侧边栏组织方面的顾虑。
  • Craft 6 — 类别、标签和全局集将被完全移除

对于新项目,始终使用条目:使用 Structure 分区组织分层分类法,使用 Channel 分区组织扁平分类法,使用 Singles 管理全站设置。对于现有项目,可按自己的节奏使用 entrify 命令进行迁移。

三项决策决定了内容架构:

  1. 选择哪种分区类型来组织内容(Single、Channel、Structure)
  2. 选择哪些条目类型来定义内容形态(全局定义,可在不同场景中重复使用)
  3. 选择哪种关联策略来连接内容(Entries 字段、Matrix、CKEditor 嵌套条目,或组合使用)

CMS 版本

Craft CMS 有四种版本(Solo、Team、Pro、Enterprise),会影响内容建模。关键区别是:如果有任何分区需要为多个自定义用户组设置各自的编辑/查看限制,则需要 Pro 或 Enterprise(仅 Pro 及更高版本支持多个自定义用户组)。Team 提供一个固定的“Team”组,可自定义非管理员的权限,并限制最多 5 位用户。完整版本对照表和权限架构请参阅 references/users-and-permissions.md。

请在建模前选择版本——它决定了能否按用户组限制内容访问,而这会影响分区和字段架构。

区段类型选择

需求区段类型URI 示例
一次性页面(首页、关于、联系)单项__home__、about
全站设置(页脚、页眉配置)单项(无 URI,preloadSingles)—
平面集合(博客、新闻、活动)频道blog/{slug}
层级页面(文档、服务)结构{parent.uri}/{slug}
分类法(主题、类别)结构(取代类别)topics/{slug}
平面标签频道(取代标签)—
区段属性

除了类型之外,区段还包含影响内容架构的设置:

  • maxAuthors(默认值为 1)— 允许每个条目有多位作者(5.0.0 新增)。协作内容可设为更高的值。
  • minAuthors(默认值为 1,5.10 新增)— 保存条目所需的最少作者人数。设为 1 可确保每个条目至少有一位作者。保存时会进行验证;设置 minAuthors > maxAuthors 会被 Craft 的区段验证器拒绝。可与 maxAuthors 结合使用来定义确切范围(min: 1, max: 3 =“需要 1 到 3 位作者”)。
  • enableVersioning(默认值为 true)— 条目的版本历史
  • defaultPlacement — 结构中新条目的 'beginning'(开头)或 'end'(末尾)
  • previewTargets — 由 {label, urlFormat} 对象组成的数组,用于定义条目可预览的位置。默认值:条目的主页面。可为无头前端、预发布 URL 或 PDF 预览添加自定义目标。
单项取代全局变量

在 config/general.php 中设置 preloadSingles => true,即可通过句柄将单项作为全局 Twig 变量访问——与旧版全局变量行为相同,同时支持草稿、 修订、实时预览和定时发布。

{# With preloadSingles enabled #}
{{ siteSettings.footerText }}
{{ siteSettings.socialLinks.all() }}

注意事项: 单项始终会传播到所有站点。这是硬编码的行为。

用结构查询实现导航
{% set topLevel = craft.entries.section('pages').level(1).all() %}
{% set children = craft.entries.descendantOf(entry).descendantDist(1).all() %}
{% set breadcrumbs = craft.entries.ancestorOf(entry).all() %}
{% set siblings = craft.entries.siblingOf(entry).all() %}

Craft 5 中的条目类型

条目类型在全局范围内定义(Settings → Entry Types),然后附加到 区段和 Matrix 字段。一个条目类型可用于多个上下文。

重要影响:

  • 更改条目类型的字段布局会影响使用该类型的所有区段和 Matrix 字段
  • 字段来自全局字段池——同一字段定义可在各处重复使用
  • 可按上下文覆盖名称、句柄和描述(5.6.0+)——同一条目类型在不同区段中承担不同用途时很有用
  • 全局字段池要求谨慎命名字段——请使用具体的句柄
条目类型的视觉标识(Craft 5 新增)

条目类型具有视觉属性,可改善编辑体验:

  • icon — 自定义图标标识符,显示在条目类型选择器和 Matrix“+”菜单中
  • color — 20 种选项之一(红色、橙色、琥珀色、黄色、青柠色、绿色、翠绿色、青绿色、青色、天蓝色、蓝色、靛蓝色、紫罗兰色、紫色、洋红色、粉色、玫瑰色、白色、灰色、黑色)
  • description(5.8.0)— 说明此条目类型用途的帮助文本
  • group(5.8.0)— 在区段/Matrix 条目类型分配中进行可折叠分组
  • uiLabelFormat(5.9.0)— 自定义元素索引中显示的标签(默认值为 '{title}')
  • hasTitleField / titleFormat — 禁用标题字段,并根据其他字段自动生成标题
  • showSlugField(5.0.0)/ showStatusField(4.5.0)— 对编辑者隐藏 slug 或状态
  • allowLineBreaksInTitles(5.9.0)— 适用于长标题

这些设置在 Settings → Entry Types 中配置,并会影响使用该条目类型的所有上下文。

保留句柄——请将每个拟用字段句柄与此列表进行核对

Craft 通过 Field::RESERVED_HANDLES 为所有元素类型保留了 83 个以上的句柄。验证时不区分大小写。将其中任一名称用作自定义字段句柄,都会导致验证错误,或造成无提示的模板冲突:原生属性会覆盖自定义字段。 在内容模型中提出任何字段句柄之前,请先对照以下列表检查。 如果用户请求的字段与原生属性名称相同,请始终使用特定领域的同义词。例如:用户说“我需要一个标题字段”——条目已经有原生的 title,因此请根据上下文使用 heading、headline 或 pageTitle。

最常发生冲突的名称(你实际会尝试使用的那些):

保留名称替代名称原因
titleheading、headline、label、pageTitle原生元素标题
slugurlSlug、handle原生 URL slug
statusstate、phase、condition原生元素状态
urlexternalUrl、targetUrl、websiteUrl原生元素 URL
linktargetLink、ctaLink、primaryLink原生 getLink() 方法
iconentryIcon、menuIcon、featureIcon原生元素图标(5.0.0)
parentparentEntry、parentItem、belongsTo原生结构父级
childrenchildEntries、subItems、nestedItems原生结构子级
ownerentryOwner、ownerElement原生嵌套条目所有者
sitelocation、branch、region原生站点对象
leveldepth、tier、nestingLevel原生结构层级
ancestorsparentChain、breadcrumbEntries原生结构祖先
siblingspeerEntries、relatedSiblings原生结构同级项
enabledisActive、isPublished、isVisible原生启用/禁用状态
languagelocale、contentLanguage原生站点语言
localizedtranslations、localizedVersions原生本地化条目查询
next / prevnextEntry / prevEntry原生结构导航
refreference、referenceCode原生引用标签
typeentryType、category、variant原生条目类型
author / authorswriter、creator、contributor原生条目作者
postDatepublishDate、releaseDate、goLiveDate原生条目发布日期

所有元素类型共用的完整保留句柄列表(来自 Field::RESERVED_HANDLES):

ancestors、archived、attributes、behaviors、canonical、children、contentTable、dateCreated、dateDeleted、dateLastMerged、dateUpdated、descendants、draftId、enabled、enabledForSite、error、errors、fieldLayoutId、fieldValue、fieldValues、firstSave、icon、id、language、level、lft、link、localized、next、nextSibling、owner、parent、parents、prev、prevSibling、ref、revisionId、rgt、root、searchScore、siblings、site、siteId、siteSettingsId、slug、sortOrder、status、structureId、title、trashed、uid、uri、url、viewMode

各元素类型的其他保留句柄:

元素类型其他保留名称
条目author、authorId、authorIds、authors、section、sectionId、type、postDate
资源alt、extension、filename、folder、height、kind、size、volume、width
用户active、addresses、admin、affiliatedSiteId、email、firstName、friendlyName、fullName、groups、lastName、locked、name、password、pending、photo、suspended、username
分类group
标签group
地址address、countryCode、fullName、latLong、organization、organizationTaxId

此外还全局保留(来自 HandleValidator::$baseReservedWords,适用于所有句柄):attribute、attributeLabels、attributeNames、attributes、dateCreated、dateUpdated、errors、false、fields、handle、id、n、name、no、rules、this、true、uid、y、yes

字段实例 — 复用而非重复创建

字段只需定义一次,然后实例化到字段布局中。每个实例都可以覆盖四项属性,而不影响全局定义:

  • 标签 — 在不同上下文中使用不同的显示名称
  • 句柄 — 在不同上下文中使用不同的模板句柄(5.0.0+)
  • 说明 — 特定于上下文的帮助文本
  • 必填 — 在一种布局中设为必填,在另一种布局中设为可选

这意味着,一个 heroImage 资产字段可以放入博客文章、服务页面和项目条目类型中——每处使用不同的标签(“主视觉图”“横幅”“封面照片”)和不同的必填设置。字段定义、类型和设置均为共享。

规则:通过实例复用字段定义。只有类型或设置不同时,才创建新字段(例如,可用资源卷、来源限制或字符数限制不同)。不要创建 blogHeroImage、serviceHeroImage、projectHeroImage——而应创建一个 heroImage 并将其实例化。

但不要仅仅因为两个字段目前看起来相似就复用它们。 应用单一职责测试(SRP):是否存在一种合理的情况,需要为其中一个实例设置不同的字符数限制、翻译方法或可用资源卷?如果是,那么这种相似只是偶然的,并非本质相同——应创建单独的字段。过度复用会带来难以在之后逆转的代价:

  • 搜索无法区分不同实例。 索引记录的是字段的关键词,而非实例的关键词,因此 summary::daisy 可能会匹配同一字段的 byline 实例(文档说明)。如果需要依靠不同字段范围进行搜索,就必须使用单独的字段。(按被覆盖的句柄进行条目查询筛选——.summary(x).byline(y)——确实有效;只有搜索索引无法区分实例。)
  • 据社区报告,少数关联/relatedTo 情况需要使用原始句柄——如果复用字段后的结果不正确,请针对具体情况进行验证。
多实例字段与单实例字段

字段的 isMultiInstance() 方法决定它能否在同一布局中多次出现并使用不同的句柄。这取决于 dbType()——返回 null 的字段为单实例字段。

类别字段类型多实例可跨布局复用
关系型条目、资产、分类、标签、用户是是
简单型纯文本、数字、电子邮件、URL、颜色、灯光开关、金额、范围、时间、日期/时间是是
选项型下拉菜单、复选框、多选、单选按钮、按钮组是是
结构化表格、链接、图标、国家/地区是是
嵌套元素Matrix、内容块、地址否是(有条件)

单实例注意事项: Matrix、内容块和地址字段可以在不同条目类型之间复用(放入多个字段布局),但在每个布局中只能出现一次,且其配置完全共享——更改 Matrix 字段上的条目类型或设置,会影响所有使用该字段的条目类型。只有在不同上下文确实共享相同结构时,才复用这些字段。如果不同上下文需要不同的嵌套条目类型或设置,则应创建单独的字段。

向条目类型添加字段 — 优先复用工作流

在内容模型变更中提出任何字段之前,你必须:

  1. 列出现有字段池。 阅读 config/project/fields/(或 CP Settings → Fields)。列出每个字段的类型、句柄和关键设置。
  2. 将每个拟议字段归入以下三类之一:
    • 复用 — 存在类型匹配且设置兼容的字段。将其添加到布局中;可选择覆盖标签、句柄、说明或必填设置。
    • 复用并审核设置 — 存在类型正确但设置略有不同的字段(例如,允许的资源卷不同、字符数限制不同)。提出能否统一设置,让同一个定义适用于这两种情境,并将此标记为待用户决定的事项。
    • 新建 — 没有字段在类型或功能用途上匹配。说明为何需要新字段。
  3. 对于单实例字段(Matrix、Content Block、Addresses)——如果现有字段具有相同的嵌套结构,则复用。如果不同情境需要不同的嵌套条目类型或设置,则可以新建字段——在说明理由时注明共享配置的注意事项。
  4. 用表格呈现计划 — 每个拟议字段占一行,显示复用决定、要复用的现有字段(如适用),以及新建字段的理由。没有这张表,不得创建新字段。

创建与现有字段功能重复的字段,是内容建模中最常见的错误——这会污染全局字段池、让编辑人员困惑,并增加未来重构的难度。

Entrification — 迁移旧版内容

CLI 命令
ddev craft entrify/categories <categoryGroupHandle>   # → Structure section
ddev craft entrify/tags <tagGroupHandle>               # → Channel section
ddev craft entrify/global-set <globalSetHandle>        # → Single section

这三个命令都接受 --section,用于指定现有分区,而不是新建分区。entrify/categories 和 entrify/tags 还接受 --entry-type 和 --author;entrify/global-set 则不接受。

从 5.9.0 起,这些命令可交互使用——handle 参数可省略。

命令的作用
  • 将元素类型转换为条目
  • 迁移所有内容和字段数据
  • 将 Categories/Tags 字段转换为 Entries 字段
  • 保留现有关系
  • 将新建的分区分配给合适的条目索引页
用于层级选择的 Entries 字段

将 Categories 字段替换为 Entries 字段时,请在 Entries 字段上启用 Maintain Hierarchy。选择嵌套条目时,此选项会自动选中其祖先条目,从而复现分类字段的行为。

替换 Tags 的注意事项

对于编辑人员临时创建术语的扁平分类体系,Entries 字段目前尚不支持临时创建术语的用户体验。这是旧版 Tags 字段仍具有用户体验优势的唯一情形。请使用 Channel 分区,并接受两步工作流(先单独创建条目,再关联该条目)。

CKEditor、Matrix 还是 Content Block

这三种工具都用于在条目中创建结构化内容——请根据编辑体验进行选择:

  • Matrix — 可重新排序的区块、页面构建器、数据网格、媒体图库。支持多种视图模式(blocks、cards、cards-grid、index)。
  • CKEditor 搭配嵌套条目 — 在富文本中偶尔插入结构化内容(图像区块、代码区块、CTA)。写作流程自然流畅。
  • Content Block(5.8.0)— 用于可复用字段组(SEO 元数据、横幅配置)的单个不可重复嵌套条目。

如需查看完整的决策表、嵌套条目类型模式,以及 CKEditor 分块渲染模式,请阅读 references/content-patterns.md。

创建分区后——整理 Entries 元素索引

自定义 Entries 源(自定义源)后,Craft 会将完整的源列表持久化到 config/project/project.yaml 中的 elementSources.craft\elements\Entry,并将每个新创建的分区追加到末尾,使用通用列。这意味着内容模型并未完整交付。(如果从未自定义过源,分区会按默认顺序显示,无需整理——前提条件请参阅 element-index-sources.md。)

后续必须完成的工作(与分区在同一个 PR/同一组变更中完成):

  1. 将源放在正确的侧边栏标题下,与同角色的源相邻(Indexes、Categories、Includes 等)。
  2. 将 tableAttributes 和 defaultSort 调整为与最相似的分区一致(例如,FAQ Index 对应 News Index;FAQ Categories 对应 News Categories)。
  3. 仅当分区有公开 URL 时才包含 link;删除空的 heading: '' 残留项。

完整清单、角色表格以及列键规则(field: 与 fieldInstance:):请参阅 references/element-index-sources.md。

常见陷阱

  • 将新分区源留在 Entries 索引底部 — 创建分区或单条目后,整理 elementSources 的位置和列,使其与同类项一致;参见 element-index-sources.md。如果一个尚未完善的模型发布了 FAQ,却没有将 FAQ Index 放在其他 Index 旁边,那就是一个例子。
  • 过度使用 Matrix — 如果内容需要独立 URL、独立查询或权限,就应该使用带有 Entries 关系字段的独立分区,而不是 Matrix 区块。
  • 创建新字段前未检查全局字段池 — 添加任何字段前,都要先执行上述 Reuse-First Workflow。通过 config/project/fields/ 枚举现有字段,并默认通过实例复用。只有字段类型不同或设置确实不兼容时,才有理由创建新字段。
  • 在需求不同的实例间过度复用同一字段 — 反过来也是个错误。搜索索引无法区分复用字段的各个实例(summary::daisy 可能会匹配 byline 实例 — 文档),而少数 relatedTo 用例需要原始句柄。只有在各实例确实是同一字段时才复用;如果某个实例合理地可能需要不同设置(单一职责),就应拆分。优先复用,而不是一味复用。
  • 字段句柄含糊或为保留字 — image、text、link 过于笼统(而且 link 实际上是保留字)。内容模型中的每个字段句柄都要按以下步骤检查:(1)句柄是否在保留列表中?如果是,就使用表格中的同义词。(2)该句柄对全局字段池来说是否过于笼统?如果是,就添加领域上下文:featuredImage、bodyContent、primaryLink。(3)不要过度细化 — blogFeaturedImage 会创建一个新字段,而你本可以为 featuredImage 实例覆盖标签。
  • 没有从一开始就规划多站点 — 内容创建前必须配置传播方式、字段翻译方式和站点设置。之后更改传播方式会重新保存所有条目。
  • 在新项目中使用 categories/tags/globals — 它们在 Craft 5 中已弃用且不建议使用(但仍可在 CP 中创建),并将在 Craft 6 中移除。请改用条目。
  • 忘记 preloadSingles — 没有它,single 就无法作为全局变量使用,你需要显式查询。
  • 什么都用 Matrix — 在一个 Matrix 字段中放入 15 种以上的条目类型是个危险信号。深层嵌套的 Matrix 会触及 max_input_vars 限制,并降低 CP 性能。
  • 未使用 .eagerly() — 循环中每次访问关系字段都应使用 .eagerly(),以避免 N+1 查询。
  • 手动编辑项目配置 YAML — 让 Craft 管理 config/project/。如有需要,使用 ddev craft project-config/rebuild 从 DB 重新生成。
  • 在 URI 格式中使用数据库 ID — ID 在不同环境中会有所不同。请使用 {slug}、{canonicalUid} 或自定义字段。
  • 在生产环境中未设置 allowAdminChanges => false — 如果不设置,生产环境中的架构更改将无法同步回开发环境。
  • 在文件系统 URL 中使用 @web — @web 会根据 HTTP 请求自动检测,在控制台或队列上下文中可能被伪造或为空。文件系统 URL 请使用环境变量($ASSETS_URL)。路径使用 @webroot 风险较低,但仍优先使用环境变量。
  • 忽略条目类型的视觉标识 — 编辑人员通过图标、颜色和描述进行导航。完善这些设置能让 CP 在内容模型不断扩展时依然易用。
  • 未规划 CMS 版本 — 如果需要按用户组设置内容权限,就需要 Pro 或 Enterprise。这会影响分区和字段架构。

参考文件

请阅读与你的任务相关的参考文件。

任务示例:

  • “向现有条目类型添加字段” → 使用本 SKILL.md 中的优先复用工作流
  • “修改条目类型的字段布局” → 使用本 SKILL.md 中的优先复用工作流
  • “规划博客内容架构” → 阅读 content-patterns.md
  • “我应该为 X 使用哪种字段类型?” → 阅读 field-types.md
  • “设置 relatedTo 查询” → 阅读 relations-and-eager-loading.md
  • “配置带嵌套条目的 Matrix” → 阅读 field-types.md(Matrix 部分)
  • “规划多站点内容模型” → 阅读 content-patterns.md + infrastructure.md(传播)
  • “设置用户、用户组和权限” → 阅读 users-and-permissions.md
  • “了解项目配置工作流” → 阅读 infrastructure.md(项目配置要点)
  • “Craft 如何在内部存储内容?” → 阅读 infrastructure.md(存储模型)
  • “设置资源卷和文件系统” → 阅读 infrastructure.md(资源部分)
  • “为结构板块配置 URI 格式” → 阅读 object-templates.md(结构 URI 模式)
  • “设置动态资源上传子路径” → 阅读 object-templates.md(资源子路径模式)
  • “将字段移入 Matrix 后,资源子路径失效” → 阅读 object-templates.md(Matrix 陷阱)
  • “创建 FAQ 板块后整理条目索引” → 阅读 element-index-sources.md
  • “新板块显示在条目列表底部,且列不正确” → 阅读 element-index-sources.md
  • “让 FAQ 索引/分类与新闻索引/分类资源相匹配” → 阅读 element-index-sources.md
参考文件范围
references/field-types.md所有内置字段类型:设置、Twig 访问模式、查询语法、注意事项。Matrix 配置、视图模式、嵌套。
references/relations-and-eager-loading.mdrelatedTo() 的形式(4 种)、.with() 预加载、.eagerly() 延迟预加载、嵌套预加载、原生可预加载属性。
references/content-patterns.md博客、作品集、多站点企业网站的策略模式。每种模式的板块/字段/关联架构。条目化迁移。CKEditor 与 Matrix 的选择。
references/users-and-permissions.md用户、用户组、CMS 版本、地址、权限架构、字段布局 UI 元素。
references/infrastructure.md多站点传播方法、字段翻译方法、项目配置工作流、Craft 如何存储内容(五表模型、JSON 字段值、关联、嵌套集)、资源卷/文件系统/变换。
references/object-templates.md对象模板语法:{attribute} 与 {{ twig }}、URI 格式、资源子路径、预览目标、owner/rootOwner 嵌套、结构模式、Matrix 陷阱。
references/element-index-sources.md项目配置中的条目控制面板索引资源:在标题下的放置位置、与同级板块相匹配的 tableAttributes/defaultSort、新增板块后的创建后检查清单。

评论

支持 Markdown