1,000 个 tag 的天花板:为什么你的 collection 筛选器悄悄丢 tag
你的主题遍历 collection.all_tags 来渲染筛选侧边栏——而 Shopify 自己的 Liquid 文档给这个对象设了 1,000 个 tag 的上限。第 1,001 个 tag 永远到不了模板。没有报错,没有警告,只有消失的筛选项和再也筛不到的商品。本文给出复现方法和彻底修好的迁移路径。
TL;DR: collection.all_tags 最多返回 1,000 个 tag(Shopify Liquid 官方文档写明),而且这个上限被你的全局 tag 词表消耗。如果你的筛选 UI 基于 tag、商品量又大,它现在就已经在丢选项了。解法是 Shopify 官方推荐的筛选方式:把可筛选属性迁到 metafield(带类型的自定义字段),改用 storefront filtering(店面筛选,Search & Discovery 应用管理的就是它)。两个预算先记住:每个店铺最多 25 个筛选器;商品数超过 5,000 的 collection,collection.filters 返回空。
这是“Shopify Functions 生产实战”系列第三篇。第一篇讲折扣码冲突,第二篇讲 10,000 字节 metafield 陷阱。这一篇讲的天花板跟 Function 无关——只需要 tag 和一个大商品目录。
现场
一位商家在 Shopify 社区发帖:collection 侧边栏的筛选项“少了”。这家店用 product tag 标一切——颜色、材质、场景、人群——主题根据 collection 的 tag 渲染筛选 UI。几百个商品,几千个不同的 tag。没有任何报错:后台没警告,主题没异常。只是有些 tag 永远不出现在筛选项里,它们背后的商品从此无法被筛选找到。
帖子里三位独立的社区专家收敛到同一个答案:别再用 tag 做筛选,把可筛选属性迁到 metafield,交给 storefront filtering。我们在生产环境撞上了同一堵墙,这篇文章是我们希望自己当时能读到的复盘。
根因一:collection.all_tags 硬上限 1,000
经典的 tag 筛选模式长这样(按 Shopify 官方 tag 筛选文档:遍历 collection 的 tag,用 current_tags 生成添加/移除链接):
{% comment %} sections/main-collection.liquid — 经典 tag 筛选 UI {% endcomment %}
<ul class="tag-filters">
{% for tag in collection.all_tags %}
<li>
{% if current_tags contains tag %}
{{ tag | link_to_remove_tag: tag }}
{% else %}
{{ tag | link_to_add_tag: tag }}
{% endif %}
</li>
{% endfor %}
</ul>没人事先读到的那一行是:collection 对象的 Liquid 参考文档写明,all_tags 最多返回 1,000 个 tag。不是软限制,不是分页提示——是硬顶。第 1,001 个起的 tag 根本到不了你的模板。你的循环没问题;数据在到达之前就被截断了。
这个失效模式有两个讨厌的性质:
- 它是静默的。 后台没有任何地方告诉你 distinct tag 用量。模板拿到什么就渲染什么。
- 它的退化是不对称的。
all_tags还包含被当前视图过滤掉的商品的 tag,所以消耗上限的是你的全局 tag 词表,不只是当前可见商品的 tag。大目录烧穿 1,000 个 distinct tag 比直觉快得多——每个打错的 tag(greyvsgray)、每个季节 tag、每个供应商 tag 都算。
同时,tag URL 自身也有锋利的边角:collection URL 里多个 tag 按 AND 组合(商品必须全部携带);如果 URL 里某个 tag 全店没有任何商品在用,Shopify 会重定向到剥掉该 tag 的 collection URL。对“顾客按属性浏览”的体验来说,AND 语义加上重定向剥离,是 Facet 筛选的反面。
根因二:tag 没有数据模型
tag 就是字符串。没有类型,没有校验,没有“这个属性只允许这些值”的后台界面。当标签用没问题,当筛选 Facet 用是致命的——因为没有任何东西阻止词表无界增长,这又在喂根因一。
metafield 是带类型的对照物。一个 metafield 是由 namespace + key(命名空间 + 键,如 custom.material)标识的键值对,带值和类型。你先创建 metafield definition(字段定义),definition 建立数据 schema:类型校验、后台集成、可查询筛选。换句话说,“材质只能取固定字符串列表”这件事,是在 definition 里从愿望变成强制的。
最小复现
一个下午就能在开发店铺演示这个上限:
- 建一个 collection 和约 50 个商品,给这些商品打上 1,001+ 个 distinct tag(比如
tag-0001…tag-1100,分散到各商品)。 - 在主题的 collection 模板里渲染
{{ collection.all_tags.size }}。 - 观察输出:1000——不管超出部分还有多少 distinct tag。
- 渲染上面的 tag 筛选循环:上限之外的 tag 永不出现为筛选项,而且没有任何报错告诉你为什么。
那个永远不超过 1000 的 size 就是整个 bug 报告。
解法:metafield 支撑的 storefront filtering
Shopify 文档写了两种主题筛选方式,并明确把 storefront filtering 标为推荐(另一种是 tag 筛选)。迁移路径如下:
1. 设计属性 schema。 对每个充当筛选 Facet 的 tag 族(颜色、材质、场景……),创建一个 product metafield definition。类型要对齐 storefront filtering 实际支持的范围——基于 metafield 的筛选器只能引用这些类型:single_line_text_field、list.single_line_text_field、metaobject_reference、list.metaobject_reference、number_integer、number_decimal、boolean。多值 Facet(一个商品既是“羊毛”又是“真丝”)对应 list.single_line_text_field。
2. 从 tag 回填值。 遍历目录,把每个商品的 tag 值拷进对应的 metafield。用 Admin GraphQL API 的 metafieldsSet 写值(不存在则创建);一次调用最多 25 个 metafield、总请求体上限 10MB,且操作是原子的——要么整批落库要么都不落。按此分批。(我们的脚本按 25 个一批跑,记录每次非原子失败用于重试;回填脚本要幂等,重跑安全。)
3. 在后台创建筛选器。 storefront 筛选器不是主题配置——按文档,筛选器必须先在 Shopify 后台创建才能生效(Search & Discovery 应用管的就是这件事)。一个要提前知道的预算:每个店铺最多 25 个筛选器。 狠心合并——25 个类型良好的 Facet 胜过 40 个半闲置的,而且这会逼你开那场早就该开的会:“到底哪些属性配拥有筛选器?”
4. 核对 URL 契约。 生效的筛选会体现在 URL 上。product 作用域的 metafield Facet 形如 filter.p.m.<namespace>.<key>=value——例如 /collections/all?filter.p.m.custom.material=wool——多选用逗号分隔。如果你的主题(或 headless 店面)自己拼筛选链接,这就是要对齐的契约。
5. 还有一个要提前规划的天花板。 storefront filtering 自己有文档写明的限制,最好在大目录商家来问之前就知道:商品数超过 5,000 的 collection,collection.filters 返回空。超大目录的解法是把大 collection 拆成更小的预筛选 collection,而不是指望 1 万商品“全部商品”页的筛选 UI。
检查清单:你离天花板有多近?
- 在最大的 collection 上渲染
{{ collection.all_tags.size }}。接近或达到 1,000?你的 tag 筛选 UI 已经在丢 tag 了。 - 数一下全局 distinct tag 词表(全店导出,不是单个 collection)——
all_tags包含被当前视图过滤掉的商品的 tag,上限承压是全局的。 - 有没有本该“多选或”的 Facet?tag URL 是 AND 组合——这是 metafield 筛选的活。
- 盘点顾客真正按哪些属性筛选,把每个映射到受支持的 metafield 类型(
single_line_text_field、list.single_line_text_field等)。 - 给筛选器做预算:每店最多 25 个。先合并再创建。
- 用
metafieldsSet按 ≤25 个/批原子回填;脚本要幂等。 - 有没有单个 collection 超过 5,000 商品?那里的
collection.filters会是空的——拆开它。 - tag 留给运营标签(拣货单、自动化触发器);可筛选属性放 metafield。两套词表,两份职责。
Agent 在这里的位置
上面的迁移是一次性项目。持续的风险是漂移:新的 tag 族悄悄混进来、有人又直接用 tag 做筛选、某个 collection 悄悄涨过 5,000 商品导致筛选器返空。这是一个监测循环,正是店铺运营 Agent 能扛下来的事:盯着全局 tag 数对 1,000 上限的距离、盯着 collection 大小对 5,000 上限的距离,异常出现时带着证据提醒店主——赶在顾客报告“筛选项不见了”之前。
本文按 Shopify 官方文档(Liquid collection 对象、主题筛选方式、storefront filtering、metafields、metafieldsSet)核实,截至 2026 年 8 月。需求证据来自 Shopify 社区线程 659430——三位独立专家在该帖收敛到 metafields + Search & Discovery 路径。