You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Google Tag Manager中用JS处理Shopify产品变体结构化数据

Fixing Shopify Variant Structured Data in GTM

Alright, let's tackle this problem step by step. The core issues here are how you're pushing variant data to the Data Layer and how you're processing it in GTM—let's fix both to get those 1:1 Offer mappings for each product variant.

Root Causes of the Problem

  1. Data Layer Variables Are Strings, Not Arrays: Your current Shopify code pushes gtm_product_price and gtm_product_variants as comma-separated strings, not proper JSON arrays. When you wrap them in [] in GTM, you end up with invalid syntax (unquoted URLs treated as variables, not strings).
  2. Incorrect Loop Logic: Using text += in your loop was causing prices and URLs to accumulate across variants instead of mapping one-to-one.

Step 1: Fix the Shopify Data Layer Push Code

First, we need to push valid JSON arrays for variants and prices. Use Shopify's json filter to automatically handle quoting and escaping, ensuring the Data Layer gets properly structured data:

<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  'gtm_product_url': {{ shop.url | append: product.url | json }},
  'gtm_product_title' : {{ product.title | json }},
  'gtm_product_image' : {{ product.featured_media | img_url: media_size | prepend: "https:" | json }},
  'gtm_product_description' : {{ product.description | strip_html | strip_newlines | json }},
  'gtm_date' : "{{'now' | date: '%Y-%m-%d' }}",
  'gtm_sku' : "{{ current_variant.sku }}",
  'gtm_barcode' : "{{ current_variant.barcode }}",
  'gtm_review_rating': "{{ shop.metafields.judgeme.shop_reviews_rating }}",
  'gtm_review_count': "{{ shop.metafields.judgeme.shop_reviews_count }}",
  // Push prices as a number array
  'gtm_product_price': [{%- for variant in product.variants -%}{{ variant.price | divided_by: 100.00}}{% unless forloop.last %},{% endunless %}{%- endfor -%}],
  // Push variant URLs as a string array (using json filter for proper quoting)
  'gtm_product_variants': [{%- for variant in product.variants -%}{{ shop.url | append: variant.url | json }}{% unless forloop.last %},{% endunless %}{%- endfor -%}]
});
</script>

Key changes here:

  • Wrapped the variant price loop in [] to create a proper array of numbers.
  • Wrapped each variant URL in {{ ... | json }} to ensure it's a quoted string, and placed the entire loop in [] to create a string array.
  • Replaced manual quote handling for gtm_product_description with the json filter to avoid syntax errors from unescaped quotes.

Step 2: Fix the GTM Tag Code

Now that the Data Layer has valid arrays, we can clean up the GTM code to map each variant to its own Offer correctly:

<script>
(function() {
  var data = {
    "@context": "http://schema.org/",
    "@type": "Product",
    "@id": "{{TitanProductURL}}",
    "name": "{{TitanProductTitle}}",
    "url": "{{TitanProductURL}}",
    "image": [ "{{TitanProductImage}}" ],
    "description": "{{TitanProductDescription}}",
    "sku": "{{TitanSKU}}",
    "gtin12": "{{TitanBarcode}}",
    "brand": {
      "@type": "Thing",
      "name": "Titan Casket"
    },
    "offers": [],
    "aggregateRating": {
      "@type": "AggregateRating",
      "ratingValue": "{{TitanReviewRating}}",
      "bestRating": "5", // Use plain number for Schema.org compliance
      "worstRating": "1",
      "ratingCount": "{{TitanReviewCount}}"
    }
  };

  // Variables are now arrays—no need to wrap in []
  var variants = {{TitanProductVariants}};
  var prices = {{TitanProductPrice}};

  // Ensure we don't loop beyond the shorter array to avoid errors
  var maxVariantCount = Math.min(variants.length, prices.length);
  
  for (var i = 0; i < maxVariantCount; i++) {
    data.offers.push({
      "@type" : "Offer",
      "availability" : "http://schema.org/InStock",
      "priceValidUntil" : "{{TitanDate}}",
      "price" : prices[i], // Directly use the i-th price
      "priceCurrency" : "USD",
      "url" : variants[i] // Directly use the i-th variant URL
    });
  }

  var script = document.createElement('script');
  script.type = "application/ld+json";
  script.innerHTML = JSON.stringify(data);
  document.getElementsByTagName('head')[0].appendChild(script);
})(document);
</script>

Key changes here:

  • Removed the [] around {{TitanProductVariants}} and {{TitanProductPrice}} since they're now proper arrays from the Data Layer.
  • Eliminated the text += logic—each Offer now uses the exact price and URL at index i for the variant.
  • Added Math.min(variants.length, prices.length) to prevent index out-of-bounds errors if the arrays ever have mismatched lengths.
  • Updated bestRating and worstRating to plain numbers (per Schema.org recommendations, numeric values are preferred over "5 star" text).

Verification

After publishing these changes:

  1. View your product page's source code to confirm the Data Layer has arrays for variants and prices.
  2. Use Google's Structured Data Testing Tool to validate that each product variant has its own Offer object with the correct price and URL.

内容的提问来源于stack exchange,提问作者Kenny King

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:36:52