product structured data 怎么写:独立站产品页的两套规则,先分清这一页能不能直接下单

product structured data 动手前只有一个判断:这一页能不能直接下单。能下单按 merchant listings 那套写,测评页按 product snippets 那套写,两套的必填项互相不同。先用一条命令查你的 Shopify 或 WooCommerce 主题是不是已经在发,再看对照表、两段能粘的 JSON-LD 和三种最常见的写错法。

抓取与收录9 分钟读完2344 次阅读
product structured data 怎么写:独立站产品页的两套规则,先分清这一页能不能直接下单

product structured data 动手之前只有一个判断:这一页能不能直接下单?能,就按 Google 的 merchant listings 那套要求写;不能——测评页、对比页、只导流到别处卖的品牌页——就按 product snippets 那套写。两套要求是分开发布的,一套里可选的属性在另一套里是必填。下面给你:怎么分、一张对照表、两段能直接粘的 JSON-LD、一条先查自己主题的命令,以及独立站上最常见的三种写错法。

先读 结构化数据还有哪些类型有效,那一章定了 Google 现在还会展示哪些类型;再回来读这章,然后才去开 富媒体搜索结果测试——它的 Product 面板会按两套要求分别报警,不先弄清自己要的是哪一套,那些警告读不懂。

先查你的主题是不是已经在发

做独立站的人多半不是从零写这段标记,而是 Shopify 或 WooCommerce 的主题早就替你发了一段。所以第一步不是写,是查:用爬虫的方式读一遍你的产品页原始 HTML,看里面有几个 Product 节点、各带了什么。下面这条命令不跑 JavaScript,只读服务器返回的那份 HTML,把每个 JSON-LD 块里的 Product 节点挖出来,打印两套要求各自会盯的那几个属性。

curl -sL -A 'Mozilla/5.0 (Macintosh) Chrome/126.0' https://example.com/products/some-product \
  | python3 -c "
import json, re, sys
doc = sys.stdin.read()
blocks = re.findall(r'<script[^>]*type=[\"\\']application/ld\+json[\"\\'][^>]*>(.*?)</script>', doc, re.S | re.I)
def walk(n):
    if isinstance(n, dict):
        t = n.get('@type')
        if t == 'Product' or (isinstance(t, list) and 'Product' in t): yield n
        for v in n.values(): yield from walk(v)
    elif isinstance(n, list):
        for v in n: yield from walk(v)
products = [p for b in blocks for p in walk(json.loads(b))]
print(len(blocks), 'JSON-LD block(s),', len(products), 'Product node(s)')
for p in products:
    o = p.get('offers') or {}
    o = o[0] if isinstance(o, list) else o
    print(p.get('name'), '|', o.get('@type'), o.get('price'), o.get('priceCurrency'), o.get('availability'),
          '| gtin', p.get('gtin') or p.get('gtin13'), '| sku', p.get('sku'), '| rating', 'aggregateRating' in p)
"

2026-09-11 拿它跑了一个真实的店:gymshark.com 上一件卫衣的产品页。返回 1 个 JSON-LD 块、7 个 Product 节点,全部挂在一个按尺码分变体的 ProductGroup 下面。每个变体带自己的 13 位 gtinmpn、共用一个 sku、一张图,以及一个 40 USD 的 Offer,带 itemConditionavailability:4 个 InStock、3 个 OutOfStock。品牌、aggregateRatingreview 只在 group 那一层出现一次,变体上没有。这是一个页面,挑它是因为它是个知名的店,放在这里是给你一个可以照抄的形状,不是统计数字。

写这条命令时踩过一个坑,顺手写下来:第一版对 <script> 里的内容先做了 HTML 反转义再解析 JSON,结果那个页面的描述里带着 &quot;,反转义之后 JSON 当场失效。script 里的文本本来就不是 HTML 转义过的,直接 json.loads 就对了。

命令打出 1 个 Product 节点、带 Offer、有货币、有库存状态,你的主题已经把必填项发了,剩下的是核对值对不对;打出 2 个节点,多半是主题一段、某个 SEO 插件又一段,删掉一段;打出 0 个,往下读。

哪一套 product structured data 是你的

Google 的分法看的是访客在这一页能做什么,不是你卖什么。原文:"Product snippets: For product pages where people can't directly purchase the product … Merchant listings: For pages where customers can purchase products from you"(Product structured data,2026-09-11 访问)。独立站的产品页是 merchant listing;测评、对比、年度榜单、把人导去经销商的品牌官网,是 product snippet。

两套有重叠,而且重叠是单向的。同一页写着 "In general, adding the required product information properties for merchant listings means that your product pages can also be eligible for product snippets." 所以你卖货,就按严的那套写,两种展示都有资格。你不卖货,怎么标都进不了 merchant 那一套——资格页写得很死:"Only pages where a shopper can purchase a product are eligible for merchant listing experiences, not pages with links to other sites that sell the product"(Merchant listing structured data,2026-09-11 访问)。

属性能下单的页测评页
name必填必填
image必填推荐
offers必填,且必须是 Offeroffers / review / aggregateRating 三选一
offers.price必填,必须大于零有 Offer 就必填;允许为零
offers.priceCurrency有价格就必填有价格就必填
offers.availability推荐推荐
AggregateOffer不接受接受
gtin / sku / mpn推荐推荐
shippingDetails、退货政策推荐,优先写在 Organization 层
优缺点(pros / cons)只限编辑测评

决定性的是三行。能下单的页必须是 Offer,因为 "the merchant has to be the seller of the product in order to be eligible",而且 "require a price greater than zero"——测评那套的文档反而拿 "price": 0 当免费商品的示范写法。另外,测评页只写 offers、不写评分,测试工具可能给你一个警告,原文是 "the product snippets section of the Rich Results Test may report a warning if you provide offers without review or aggregateRating properties"(Product snippet structured data,2026-09-11 访问)。警告不是错误。把它当成测试在告诉你:它以为你要的是哪一套。

标记你手上这一页,不是你想象中那一页:标记写在哪,货就得能在哪买到。

五步加上去

每一步都有看得见的完成标志。按顺序做——第一步决定后面所有事,我们见过的写坏的产品标记,多数是跳过了它。

  1. 给页面定性。访客能在这个网址上把商品加进购物车,就是 merchant listing;不能,就是 product snippet。先把答案写下来,再碰模板。
  2. 确认这一页只讲一个商品。Google 写明 "product rich results only support pages that focus on a single product (or multiple variants of the same product)",反例是 "shoes in our shop"。分类页、集合页不挂 Product 标记。
  3. 照下面的交付物写,把每个值换成页面上肉眼能看到的那个。价格、货币、库存必须和买家看到的一致,Google 说它 "may attempt to verify merchant listing product data before showing the information in search results"。
  4. 放进服务器返回的 HTML 里。merchant 那页的原话是 "we recommend putting Product structured data in the initial HTML for best results",并警告 "dynamically-generated markup can make Shopping crawls less frequent and less reliable, which can be an issue for fast-changing content like product availability and price"。完成标志:上面那条不跑 JavaScript 的命令能看见它。
  5. 把网址丢进富媒体搜索结果测试,然后盯 Search Console 把它归到哪份报表:"Merchant listings report: For pages where shoppers can buy products. Product snippets report: For other product related pages"。完成标志:报表里显示有效,第一次抓取之后可能要等几天。

交付物:两段标记

第一段是能下单的页,一个商品一个价。出现的每个属性要么是必填,要么是几乎不用额外成本就能填上的推荐项;运费和退货政策用 @id 引过去,因为 Google 建议在 Organization 标记里声明一次全站政策 "instead",别在每个 Offer 上重复。

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Merino Crew Sock, Charcoal",
  "image": [
    "https://example.com/photos/1x1/merino-crew-charcoal.jpg",
    "https://example.com/photos/4x3/merino-crew-charcoal.jpg",
    "https://example.com/photos/16x9/merino-crew-charcoal.jpg"
  ],
  "description": "Mid-weight merino crew sock, reinforced heel, made in Portugal.",
  "sku": "MC-CHR-01",
  "gtin13": "0123456789012",
  "brand": { "@type": "Brand", "name": "Example Knitwear" },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/products/merino-crew-charcoal",
    "price": 18.00,
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "itemCondition": "https://schema.org/NewCondition",
    "shippingDetails": { "@id": "https://example.com/shipping#policy" },
    "hasMerchantReturnPolicy": { "@id": "https://example.com/returns#policy" }
  }
}
</script>

第二段是编辑测评页——这一页不卖这双袜子,所以没有你的 Offer,资格来自 review。评审人的名字必须是一个人或一个团队,Google 给的反面例子是 "50% off on Black Friday"。

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Merino Crew Sock, Charcoal",
  "image": "https://example.com/reviews/merino-crew/hero.jpg",
  "brand": { "@type": "Brand", "name": "Example Knitwear" },
  "review": {
    "@type": "Review",
    "author": { "@type": "Person", "name": "Dana Ortiz" },
    "reviewRating": { "@type": "Rating", "ratingValue": 4, "bestRating": 5 },
    "positiveNotes": { "@type": "ItemList", "itemListElement": [
      { "@type": "ListItem", "position": 1, "name": "No thinning at the heel after 40 washes" },
      { "@type": "ListItem", "position": 2, "name": "Stays up without a tight cuff" } ] },
    "negativeNotes": { "@type": "ItemList", "itemListElement": [
      { "@type": "ListItem", "position": 1, "name": "Only three colours" } ] }
  },
  "aggregateRating": { "@type": "AggregateRating", "ratingValue": 4.3, "reviewCount": 212 }
}
</script>

有尺码、颜色变体的商品,形状就是 gymshark 那一页的形状,也是 Google 变体文档描述的形状:"use the ProductGroup class with associated properties variesBy, hasVariant, and productGroupID to group such variants together",group 那一层放 "common product-properties for all variants, such as brand and review information"(Product variant structured data,2026-09-11 访问)。同一页还要求每个变体有自己的网址、打开就是选中该变体的状态,Google 才能逐个抓到。

上线前核对规则出处
一页一个商品;集合页不挂两页的技术准则
能下单的页:Offer 不是 AggregateOffer,价格大于零Merchant listing 的 Offer 必填项
priceCurrency 是三个字母的 ISO 4217 代码两页的 Offer 属性
多币种定价,一个币种一个网址技术准则
gtin 只写数字,不写 URLMerchant listing 的 Product 推荐项
写了 priceValidUntil 就得是未来的日期Merchant listing:过期日期可能让列表不显示
标记在服务器返回的 HTML 里,不是后注入的技术准则的 JavaScript 说明
值和页面上看到的一致Merchant listing:Google 可能核验

独立站上最常见的三种写错法

三种都能通过语法校验。它们栽在资格规则上,而校验器不读资格规则。

  1. 集合页上挂了 Product 标记。 主题把第一个商品的标记块打到了每个列表网址上,或者干脆把集合本身标成 Product。Google 那句「什么不算一个商品」的例子——"shoes in our shop"——说的就是这种页。删掉;集合页要么是 ItemList,要么什么都不挂。
  2. 能下单的页价格是零,或者没写货币。 免费样品、「价格面议」、模板给缺货变体统一打 price: 0,都会让 merchant listing 失去资格——它要的是大于零的价格。测评那套容忍零,merchant 这套不容忍。
  3. 标记是页面加载后由 JavaScript 拼出来的。 上面那条命令打出 0 个 Product 节点,富媒体测试因为会渲染可能照样通过,而 Shopping 的抓取拿到得晚、或者根本拿不到。把标记挪进服务器响应里。

这一章帮不到的地方

两条边界。标记只给页面资格,不让任何东西出现——Google 的排错段落原话是 "does not guarantee that features that consume structured data will show up in search results",一个合格的 merchant listing 实际多久被展示一次,我们也告诉不了你。第二,结构化数据只是 Google 读购物数据的两条通道之一:总览页写着你可以 "add Product structured data to your web pages, upload data feeds with Google Merchant Center and opt into free listings within the Merchant Center console, or both",两条都做 "maximizes your eligibility"。本章只管页面这一半,Merchant Center 的 feed 怎么配不在这里。如果你的产品页根本没被抓到,什么标记都救不了;先去跑一遍 AI 爬虫可达性检查再回来。

常见问题

Shopify 站还要不要自己加 product structured data?

先查再加:大多数 Shopify 主题已经打了一段 Product 标记,再装一个应用就是两个互相竞争的节点。拿本章开头那条命令跑一个产品网址,打出 1 个带 Offer、货币、库存状态的节点,就不用动了;打出 2 个,删一个。托管平台里哪些东西你改不了,见 Shopify SEO 里你改不了的五层

收到「product snippets structured data issues detected」是什么意思?

Search Console 在它归到 snippet 报表的页面上发现了 Product 标记,其中至少一页不合规——最常见的是 offersreviewaggregateRating 一个都没有,因为 snippet 那套三选一必须有一个。打开报表,点进那条问题,先修示例网址;同一个模板通常能解释每一行。

product snippets vs merchant listings,该看哪份报表?

你卖货,就看 Merchant listings。Google 说那份报表 "includes checks for product snippets that include Offer structured data, so the Product snippets report only needs to be consulted for non-merchant listing pages"。一个店两份都盯,只是噪音翻倍。

有没有靠谱的 product schema checker?

用富媒体搜索结果测试,因为它套的是 Google 的规则,不是 schema.org 的。通用校验器会放过能下单的页上的 AggregateOffer 和零价格,而这两样都没有资格。

WooCommerce 自带的 product 标记够不够?

我们没有逐个版本测过 WooCommerce 的输出,不替它打包票。判据和 Shopify 一样:命令跑一遍,看节点数、看 Offer 是不是 Offer、价格是不是大于零、货币在不在。三样都在就够了,哪样不在就补哪样。

本文属于 QueryWin 实操手册 · 第 2 阶

product structured data 怎么写:独立站产品页的两套规则,先分清这一页能不能直接下单