Shopify Metafields 与 Metaobjects 完整指南
Metafields 与 Metaobjects 是 Shopify Online Store 2.0 时代的核心数据扩展能力。理解清楚它们能让主题、应用、Headless 站点都拥有结构化、可校验、可复用的自定义数据,避免把业务数据硬编码到主题或脏写到产品描述里。
适合:主题开发者、应用开发者、需要结构化数据的店铺运营团队
一、概念区分
Metafield(元字段)
给某个具体资源(产品、变体、集合、客户、订单、店铺)附加一个自定义字段。每个 metafield 由 namespace.key 唯一标识。
类比:给产品贴一张便签——副标题、保质期、护理说明、燃烧时长。一条便签一个值(单值或列表)。
Metaobject(元对象)
定义一类可复用的内容结构,并可创建多条具体条目。
类比:定义一张表(“尺码表”、“门店”、“品牌故事”),然后填入多行数据。
二者的协作
简单加字段 → Metafield。
需要可复用的结构化内容(多字段、多条记录)→ 先建 Metaobject,再用 metaobject_reference 类型的 Metafield 在资源上引用。
何时用 Metafield,何时用 Metaobject
| 需求 | 推荐 |
|---|---|
| 给产品加副标题 / 保质期 | product.metafields |
| 给变体加单独属性 | variant.metafields |
| 全站统一 Slogan | shop.metafields |
| 多语言翻译 / 多市场字段 | product.metafields + 翻译 |
| 可复用尺码表 / 门店 | metaobject + metaobject_reference |
| 品牌故事(多字段结构) | metaobject |
| 一组互不相关的字段 | 多个独立 metafield |
| 一组互相关联的字段 | 一个 metaobject |
二、为什么用元字段而非产品描述
很多店铺把”成分”、“尺寸”、“保养方法”塞到产品描述(description)里。Metafields 的优势:
| 维度 | 塞到描述 | 用 Metafield |
|---|---|---|
| 结构化 | ❌ 纯文本 | ✅ 字段化 |
| 校验 | ❌ 无 | ✅ 类型 + 验证规则 |
| 多语言 | ❌ 难维护 | ✅ 翻译友好 |
| 主题渲染 | 单点 HTML 块 | 可视化编辑器动态绑定 |
| 应用读写 | 难 | API 一致 |
| Headless | 需要 HTML 解析 | 直接 GraphQL 读取 |
| SEO | 单页可索引 | 可以用 Schema 标注 |
| 集合筛选 | 不支持 | 支持作为智能集合条件 |
| POS 显示 | 无 | 可置顶到 POS |
生产建议:所有结构化数据用 Metafield,描述只放营销长文本。
三、命名空间规范
格式:namespace.key,如 custom.subtitle、marketing.badge。
推荐规范
- 业务前缀 + 模块:
product_info、marketing、storefront - 保留
custom给通用字段:默认 Shopify 后台创建的字段在custom命名空间 - 避免下划线开头:Shopify 保留下划线开头作为内部命名
- 小写 + 下划线:
size_chart、burn_time
不推荐的做法
- 单一巨大 namespace(如全部用
custom.*),后期重构困难 - 中文 key(虽然技术上支持,但维护麻烦)
- 业务模型与 namespace 混乱
四、字段类型
Shopify 支持丰富的字段类型,按类别:
文本类
single_line_text_field:单行文本multi_line_text_field:多行文本rich_text_field:富文本(含格式)url:URLjson:JSON 数据color:颜色(#RRGGBB)
数值类
number_integer:整数number_decimal:小数
布尔类
boolean
日期类
datedate_time
媒体类
file_reference:文件image_reference:图片video_reference:视频
关系类
product_reference:产品引用variant_reference:变体引用collection_reference:集合引用page_reference:页面引用metaobject_reference:元对象引用
列表变体
多数类型都有 list.* 列表变体:
list.single_line_text_field:字符串列表list.product_reference:产品引用列表list.color:颜色列表(用于色块展示)
评定单位
weight、dimension、volume:带单位的数值
类型选择原则
- 简单文本 →
single_line_text_field - 富文本展示 →
rich_text_field - 结构化数据 →
json或metaobject_reference - 多选关联 →
list.metaobject_reference
五、后台操作
创建 Metafield 定义
Shopify 后台 → Settings → Custom data:
- 选择资源类型(Products / Variants / Collections 等)
- 点击 Add definition
- 填写:名称、Namespace、Key、Type、验证规则、是否可在 Storefront 访问
- 保存
创建 Metaobject 定义
Shopify 后台 → Settings → Custom data → Metaobjects:
- 点击 Add definition
- 命名 type(如
size_chart) - 添加多个字段(每个字段独立 type)
- 设置 access:Storefront 可读 / 主题可见 / 仅 Admin
- 创建 entries(具体条目)
在资源上填写值
进入产品 / 集合详情页 → “Custom data” 区域 → 录入值。
可以置顶常用字段:右上角 “Pin” 让该字段在产品列表显示。
关联到主题
Online Store 2.0 主题支持动态来源:
- 在线商店 → 主题 → Customize
- 添加 Block 或 Section(如”Text”)
- 字段旁的 “Connect dynamic source” 按钮
- 选择对应 metafield
无需写代码即可在前台展示。
六、Liquid 中读取
读取简单字段
{# 读取产品副标题 #}
{% if product.metafields.custom.subtitle %}
<p class="product-subtitle">{{ product.metafields.custom.subtitle | escape }}</p>
{% endif %}
{# 带默认值 #}
{% assign badge = product.metafields.marketing.badge | default: 'New' %}
{# 富文本字段 #}
{% if product.metafields.custom.care_instructions %}
<div class="rte">
{{ product.metafields.custom.care_instructions | metafield_tag }}
</div>
{% endif %}| metafield_tag filter 是 2024 年新增的,自动按字段类型渲染(富文本会输出 HTML,图片会输出 <img>)。
读取列表字段
{% if product.metafields.custom.features %}
<ul>
{% for feature in product.metafields.custom.features.value %}
<li>{{ feature }}</li>
{% endfor %}
</ul>
{% endif %}注意:列表字段需要 .value 才能拿到数组。
读取关联字段
{# 读取关联产品 #}
{% assign related = product.metafields.custom.related_product.value %}
{% if related %}
<a href="{{ related.url }}">{{ related.title }}</a>
{% endif %}
{# 读取关联 metaobject #}
{% assign size_chart = product.metafields.custom.size_chart.value %}
{% if size_chart %}
<h3>{{ size_chart.title }}</h3>
<div>{{ size_chart.content | metafield_tag }}</div>
{% endif %}读取 JSON 字段
{% assign spec = product.metafields.custom.spec_json.value %}
{% if spec %}
<table>
{% for key in spec %}
<tr>
<td>{{ key[0] }}</td>
<td>{{ key[1] }}</td>
</tr>
{% endfor %}
</table>
{% endif %}七、Admin GraphQL:写入
创建 / 更新 Metafield
mutation UpsertMetafield(
$ownerId: ID!,
$namespace: String!,
$key: String!,
$type: String!,
$value: String!
) {
metafieldsSet(
metafields: [{
ownerId: $ownerId,
namespace: $namespace,
key: $key,
type: $type,
value: $value
}]
) {
metafields { id namespace key type value }
userErrors { field message }
}
}变量示例:
{
"ownerId": "gid://shopify/Product/1234567890",
"namespace": "custom",
"key": "subtitle",
"type": "single_line_text_field",
"value": "轻盈透气,全天舒适"
}批量写入
metafieldsSet 支持一次最多 25 个 metafield。批量操作比循环单写效率高 10-20 倍。
创建 Metaobject Definition
mutation {
metaobjectDefinitionCreate(definition: {
type: "size_chart"
name: "Size Chart"
fieldDefinitions: [
{ name: "Title", key: "title", type: "single_line_text_field", required: true },
{ name: "Content", key: "content", type: "rich_text_field" }
]
access: { storefront: PUBLIC_READ }
}) {
metaobjectDefinition { id type name }
userErrors { field message }
}
}创建 Metaobject Entry
mutation {
metaobjectCreate(metaobject: {
type: "size_chart"
fields: [
{ key: "title", value: "上装尺码表" },
{ key: "content", value: "{\"type\":\"root\",\"children\":[...]}" }
]
}) {
metaobject { id handle }
userErrors { field message }
}
}关联 Metaobject 到产品
mutation LinkMetaobjectToProduct(
$productId: ID!,
$metaobjectId: ID!
) {
metafieldsSet(metafields: [{
ownerId: $productId,
namespace: "custom",
key: "size_chart",
type: "metaobject_reference",
value: $metaobjectId
}]) {
metafields { id }
userErrors { field message }
}
}value 字段传 metaobject 的 GID(如 gid://shopify/Metaobject/xxx)。
八、Storefront API:读取
Headless 站点或前端 API 集成场景:
query ProductWithCustomData($handle: String!) {
product(handle: $handle) {
id
title
handle
# 单字段
subtitle: metafield(namespace: "custom", key: "subtitle") {
value
}
# 关联元对象
sizeChart: metafield(namespace: "custom", key: "size_chart") {
reference {
... on Metaobject {
handle
type
fields { key value }
}
}
}
# 关联产品列表
relatedProducts: metafield(namespace: "custom", key: "related") {
references(first: 10) {
edges {
node {
... on Product {
handle
title
}
}
}
}
}
}
}关键:Storefront API 只能读取 access 设为 PUBLIC_READ 的字段。Admin 后台可能能看到但 Storefront 看不到,需检查 access 设置。
九、典型应用场景
场景 1:产品规格表
每个产品的规格不同,结构化为 JSON:
- 字段:
product.metafields.specs.json - 类型:
json - 值:
{"重量": "200g", "材质": "棉", "产地": "中国"}
Liquid 渲染表格。
场景 2:可复用尺码表
服饰品类的不同 SKU 共享同一尺码表:
- 创建 Metaobject
size_chart,含 title + content 字段 - 创建几个具体 entries(上装、下装、童装等)
- 在产品上加 metafield
custom.size_chart(类型metaobject_reference)
场景 3:FAQ 折叠面板
每个产品有不同的 FAQ:
- 创建 Metaobject
faq_item,含 question + answer 字段 - 产品 metafield
custom.faqs(类型list.metaobject_reference) - 在产品上挂多个 FAQ entries
- 主题循环渲染并加 FAQPage schema
场景 4:品牌故事
每个品牌的故事内容复杂:
- Metaobject
brand_story,含 title / hero_image / content / founder - 产品 metafield 引用对应 brand_story
- 多个产品共享同一品牌故事
场景 5:补货邮件订阅
记录客户对哪个 variant 想要补货:
- Customer metafield
notifications.restock_variants(类型list.variant_reference) - 通过 API 维护列表
十、常见问题排查
主题中字段显示空
- 拼写是否正确(namespace、key 必须精确匹配)
- 字段是否定义在该资源类型(如不要把 product metafield 当 collection metafield 读取)
- access 是否允许(Storefront 读取需要
PUBLIC_READ) - 该字段是否真的填了值(后台空字段当然返回空)
Storefront API 读不到
- 检查 metafield 定义的 access 是否包含 Storefront
- 检查 metaobject 定义的 access 是否包含 Storefront
- 关联字段时引用对象的 access 也要打开
metafieldsSet 返回错误
userErrors 字段中查看:
type与value必须匹配(如boolean类型 value 必须是"true"或"false")ownerId是否是正确格式的 GID- 命名空间不能用 Shopify 保留前缀
- 列表类型 value 必须是 JSON 字符串数组
性能问题
大量产品都引用同一个 metaobject 时,渲染性能可能下降:
- 用
{% liquid %}块预加载到本地变量 - 避免循环内重复访问
- 考虑 metaobject 内容内嵌到产品(如果不复用,直接用 metafield 即可)
十一、生产实践建议
命名规划
新店上线前规划好 namespace 与字段分类:
custom.* - 通用字段(默认)
product_info.* - 产品信息扩展
marketing.* - 营销标签 / 角标
seo.* - SEO 元数据扩展
shipping.* - 物流相关
b2b.* - B2B 客户分级类型选择
- 简单文本永远用
single_line_text_field,不要塞 JSON - 结构化数据用 JSON 或 Metaobject,不要硬塞分隔符(如用
;分隔的字符串) - 颜色用
color类型,不要用 hex 字符串
验证规则
- 数值字段设最小 / 最大
- 文本字段限制长度
- URL 字段加正则
- 必填项标记 required
减少后台运营录入错误。
文档化
每个 namespace 与 key 在内部 wiki 中记录:
- 用途
- 类型
- 示例值
- 在主题哪里展示
- 在 API 哪里读取
新员工接手时能快速理解。
不要做的
- 不要把 metafield 当数据库用(高频写入应该用专门系统)
- 不要在循环里频繁访问 metafield(性能差)
- 不要把超大数据(> 10KB)塞进单个 metafield