EN
Shopify 知识库 · 指南

Horizon 商品推荐:分区请求、intent 与空结果回退

基于 Horizon 4.2.0 源码,说明商品页推荐区块如何用分区渲染接口按 related 或 complementary 取回商品、怎样为空时回退或隐藏,以及与商品卡、轮播的关系,并对照交叉销售模块列出差距。
历史资料
请结合文中的适用版本和来源阅读。

本文基于 Horizon 4.2.0,源码固定到 5acd1b6(核验于 2026-10-07)。结论限于此提交,不表示其他版本行为相同;本篇为静态源码分析,未完成店铺运行验证。

交叉销售与追加购买一文写明「本站对 Horizon 的解读未涉及推荐区块」,本篇补上。卡片本身与快速购买见商品卡。

对应哪些通用模式

  • 模块:交叉销售与追加购买中的「取推荐并展示」。本主题的推荐区块只负责展示,不含捆绑、结账后追加,也不提供预勾选或一起购买的组合加购。
  • 展现:layout_type 为 carousel 或开启 carousel_on_mobile 时用轮播,否则为网格。

入口与文件

文件职责何时输出
sections/product-recommendations.liquid独立分区,含骨架、结果、回退分支templates/product.json 在 main 之后放了一个,recommendation_type 为 related
blocks/product-recommendations.liquid同一逻辑的区块版,商品取自 closest.product_product-details 的预设带一个 complementary 区块,标题默认「搭配造型」
assets/product-recommendations.js<product-recommendations>:懒加载、fetch、缓存、hydration morph任一版本输出后
snippets/product-recommendations-styles.liquid骨架样式;data-has-recommendations='false' 时整体隐藏两个版本
snippets/resource-list-carousel.liquid轮播模式,转交 slideshow 片段layout_type 为 carousel 或移动端轮播

数据从哪来

  • 请求:data-url 为 routes.product_recommendations_url 加 ?limit=N,脚本再追加 &product_id=…&section_id=…&intent=…。分区版的商品为 section.settings.product.id | default: product.id(product.json 把该设置绑定为动态来源 closest.product);区块版为 closest.product.id。section_id 是宿主分区,区块版下,按 Section Rendering API 的语义响应是整个宿主分区的 HTML,客户端只合并带 key 的子树。
  • intent:只来自设置 recommendation_type,取 related 或 complementary,schema 默认 related;后台文案 content.complementary_products 写明 complementary 需在 Search & Discovery 中设置。
  • 对象:响应里的 Liquid recommendations.performed、products、products_count;初始 HTML 中 performed 为假,输出骨架。
  • 卡片:content_for 'block' 复用 _product-card。分区版传 product_view_context: 'recommendation',区块版未传。
  • 设置:分区 product、layout_type、carousel_on_mobile(分区默认 false,区块默认 true)、max_products(分区 3–10,区块 2–10,默认 4)、columns、mobile_columns、icons_style、icons_shape。
  • 搜索范围:全仓库搜索 recommendation,非 locales 的命中只有上述文件、templates/product.json、blocks/_product-details.liquid、snippets/resource-list-styles.liquid(注释)、variant-picker.js(注释)、standard-events.d.ts 与与本题无关的 README.md 措辞;搜索 productRecommendations、graphql 无命中。购物车、集合、首页文件中未找到推荐区块或对该接口的调用。

交互怎样运行

  1. 懒加载:IntersectionObserver(rootMargin: 0 0 400px 0)进入后断开并加载;MutationObserver 监听自身属性,除 data-error、hidden 类与 performed 置真外的变化都会重新加载;performed 已为 true 时直接返回。
  2. 请求:结果按完整 URL 缓存在实例内存;新请求前 abort 上一个,fetch(url, { signal }) 真正取消;!response.ok 视为失败。
  3. 渲染:正文非空则置 performed='true',调用 morphSection 的 hydration 模式(并注入分区样式表),只更新已存在且 data-hydration-key 相同的目标。
  4. 失败:#handleError 写 console.error、加 hidden 类与 data-error,界面无提示;设计模式下忽略 !ok。AbortError 也进同一个 catch,重复触发时可能先隐藏再合并,静态推断,未核验。
  5. 服务端为空(performed 且 products_count == 0):related 回退为 collections.all.products | reject: 'id', 当前商品 的前 max_products 件;complementary 置空,data-has-recommendations="false",CSS product-recommendations:has([data-has-recommendations='false']) 整体 display:none。
  6. 布局:网格用 resource-list--grid;轮播用 slideshow(infinite: false、无 autoplay、箭头可选、未传位置控件),slide_count 取 recommendations.products.size,回退商品时为 0,视觉影响未核验。carousel_on_mobile 会同时输出网格与移动轮播两份,靠 hidden--mobile、hidden--desktop 切换。未选商品时输出占位卡片(onboarding 分支)。
  7. 无 JS:只有骨架,不会出现推荐。

与通用契约的一致与差距

对照交叉销售与追加购买。

契约Horizon 4.2.0判断
零项时隐藏,不用随机商品填补complementary 为零时隐藏;related 为零时用全部商品集合回填并显示related 与契约相反
区分搭配与类似recommendation_type 区分 intent;标题是自由文本块,product.json 中为「You may also like」部分,依据与理由无字段
商品可售、排除购物车已有项交给平台;回退分支只排除当前商品,未过滤可售回退分支缺口
加载预留空间、失败安静隐藏骨架加 400px 预加载,失败加 hidden;骨架 aria-label 写在无角色的 div 上,读出与否未核验一致,读屏未核验
请求不阻塞购买按钮进入视口下方 400px 才加载;分区版脚本带 fetchpriority="low",区块版没有一致
购物车内放 1 至 3 项内置推荐只在商品页语境,购物车文件中未找到无内置
加购一致、无预勾选、拒绝路径复用 _product-card;无预勾选与组合加购不涉及
跨市场重算、不长期缓存库存服务端按当前请求渲染;缓存仅在页面实例内存跨市场未核验
埋点与视图上下文分区版带 recommendation,区块版未带不一致
Carousel:名称、状态、键盘、可暂停箭头按钮有本地化名称(accessibility.slideshow_previous、slideshow_next);无 autoplay,故无暂停问题;无位置指示;幻灯片靠 aria-hidden 随可见性切换,键盘行为未核验部分

定制入口与风险

  • 编辑器:上文设置项;分区自身可放 text、image、button、group 等区块作标题区。
  • 耦合点:data-hydration-key、data-section-id 与宿主分区 ID 是 hydration 的匹配条件;product.json 里 product 设置依赖 closest.product;改 _product-card 会同时影响集合、搜索与推荐。
  • 回退是产品决策:related 用全部商品回填与契约相反,若要「零项隐藏」,需要改 sections 与 blocks 两处分支。

建议的验证范围

本篇未执行。1) 抓取商品页推荐请求,核对 product_id、section_id、intent、limit;2) 用有、无相关商品的商品测 related,确认零项回填;3) 在 Search & Discovery 配置 complementary,再测有、无配置两种情形;4) 模拟 500,确认区块隐藏且无报错提示;5) 切换轮播与移动端轮播,核对卡片重复输出与键盘、读屏;6) 更换市场与语言,核对推荐与价格。

源码基线