From d04ed6b71ebf9d70f753adc7500cf998f7c8db33 Mon Sep 17 00:00:00 2001 From: Alberto Mendoza Date: Wed, 30 Jul 2025 01:17:59 -0600 Subject: [PATCH 01/12] Update gtin value --- react/Product.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/react/Product.js b/react/Product.js index b5415e5..035c26f 100644 --- a/react/Product.js +++ b/react/Product.js @@ -90,6 +90,8 @@ const parseSKUToOffer = ( const gtin = isGTINField ? formatGTIN(rawGTIN) : null const skuValue = isGTINField ? gtin : item.itemId + console.log('skuValue', skuValue) + // When a product is not available the API can't define its price and returns zero. // If we set structured data product price as zero, Google will show that the // product it's free (wrong info), but out of stock. @@ -224,7 +226,17 @@ export const parseToJsonLD = ({ const category = getCategoryName(product) const rawGTIN = selectedItem?.[gtinValue] - const gtin = formatGTIN(rawGTIN) + + const formatGTIN = (value) => { + if (!value) return null + return String(value).replace(/^0+/, '') + } + + const gtin = rawGTIN != null + ? gtinValue === 'itemId' + ? rawGTIN // don't format itemId + : formatGTIN(rawGTIN) + : null const fallbackSKU = selectedItem?.itemId || null const productLD = { @@ -238,7 +250,7 @@ export const parseToJsonLD = ({ : images[0]?.imageUrl || null, description: product.metaTagDescription || product.description, mpn, - sku: gtin || fallbackSKU, + sku: selectedItem?.itemId || null, category, offers: disableOffers ? null : offers, gtin, From e86a81e620b722825b6ddcaeafc2d251a51c5dd0 Mon Sep 17 00:00:00 2001 From: Alberto Mendoza Date: Wed, 30 Jul 2025 01:32:43 -0600 Subject: [PATCH 02/12] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0293566..de65380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Fixed +- Fixed formatting for the gtinValue coming back from getAppSetting, if this value is itemId it should not format + ## [0.16.0] - 2025-07-18 ## [0.15.0] - 2025-04-28 From aa28a2b5c28acc9bc5a610c98c62025d324b058c Mon Sep 17 00:00:00 2001 From: Alberto Mendoza Date: Sun, 10 Aug 2025 22:26:59 -0600 Subject: [PATCH 03/12] Update gtin value --- react/Product.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react/Product.js b/react/Product.js index 035c26f..e91e869 100644 --- a/react/Product.js +++ b/react/Product.js @@ -250,7 +250,7 @@ export const parseToJsonLD = ({ : images[0]?.imageUrl || null, description: product.metaTagDescription || product.description, mpn, - sku: selectedItem?.itemId || null, + sku: gtin || fallbackSKU, category, offers: disableOffers ? null : offers, gtin, From a5841be06a9eaaa7ccfa689c077a5b44f103ff39 Mon Sep 17 00:00:00 2001 From: Alberto Mendoza Date: Tue, 9 Sep 2025 20:35:13 -0600 Subject: [PATCH 04/12] Fix linters --- react/Product.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/react/Product.js b/react/Product.js index e91e869..3b138ff 100644 --- a/react/Product.js +++ b/react/Product.js @@ -90,8 +90,6 @@ const parseSKUToOffer = ( const gtin = isGTINField ? formatGTIN(rawGTIN) : null const skuValue = isGTINField ? gtin : item.itemId - console.log('skuValue', skuValue) - // When a product is not available the API can't define its price and returns zero. // If we set structured data product price as zero, Google will show that the // product it's free (wrong info), but out of stock. @@ -227,16 +225,13 @@ export const parseToJsonLD = ({ const rawGTIN = selectedItem?.[gtinValue] - const formatGTIN = (value) => { - if (!value) return null - return String(value).replace(/^0+/, '') - } + const gtin = + rawGTIN != null + ? gtinValue === 'itemId' + ? rawGTIN // don't format itemId + : formatGTIN(rawGTIN) + : null - const gtin = rawGTIN != null - ? gtinValue === 'itemId' - ? rawGTIN // don't format itemId - : formatGTIN(rawGTIN) - : null const fallbackSKU = selectedItem?.itemId || null const productLD = { From ae510aeee4470e8bcd749a0db77a6c0d16ea539c Mon Sep 17 00:00:00 2001 From: Alberto Mendoza Date: Tue, 30 Sep 2025 10:09:05 -0600 Subject: [PATCH 05/12] Update code based on GH suggestion --- react/Product.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/react/Product.js b/react/Product.js index 3b138ff..ddf2d95 100644 --- a/react/Product.js +++ b/react/Product.js @@ -225,12 +225,11 @@ export const parseToJsonLD = ({ const rawGTIN = selectedItem?.[gtinValue] - const gtin = - rawGTIN != null - ? gtinValue === 'itemId' - ? rawGTIN // don't format itemId - : formatGTIN(rawGTIN) - : null + let gtin = null + + if (rawGTIN != null) { + gtin = gtinValue === 'itemId' ? rawGTIN : formatGTIN(rawGTIN) + } const fallbackSKU = selectedItem?.itemId || null From adba013bf65bea7135106884f23f187b95bcdc0a Mon Sep 17 00:00:00 2001 From: Alberto Mendoza Date: Sun, 5 Oct 2025 15:57:58 -0600 Subject: [PATCH 06/12] Address linters from GH copilot --- react/Product.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react/Product.js b/react/Product.js index ddf2d95..8f98ce2 100644 --- a/react/Product.js +++ b/react/Product.js @@ -227,7 +227,7 @@ export const parseToJsonLD = ({ let gtin = null - if (rawGTIN != null) { + if (rawGTIN !== null && rawGTIN !== undefined) { gtin = gtinValue === 'itemId' ? rawGTIN : formatGTIN(rawGTIN) } From aa68f010e0829a33f726b73fdfce05f57f04eb2f Mon Sep 17 00:00:00 2001 From: Alberto Mendoza Date: Mon, 3 Nov 2025 13:40:19 -0600 Subject: [PATCH 07/12] Update product schema render --- react/Product.js | 83 +++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/react/Product.js b/react/Product.js index 8f98ce2..d3d7b6d 100644 --- a/react/Product.js +++ b/react/Product.js @@ -60,36 +60,62 @@ const OUT_OF_STOCK = 'http://schema.org/OutOfStock' const getSKUAvailabilityString = (seller) => isSkuAvailable(seller) ? IN_STOCK : OUT_OF_STOCK -const formatGTIN = (gtin) => { - if (!gtin || typeof gtin !== 'string') return null +const normalizeGTIN = (raw) => { + if (raw === null || raw === undefined) return null - const validLengths = [8, 12, 13, 14] + const digits = String(raw).replace(/\D+/g, '') - if (validLengths.includes(gtin.length)) return gtin + if (!digits || /^0+$/.test(digits)) return null - const targetLength = validLengths.find((len) => gtin.length < len) || 14 + const VALID = [8, 12, 13, 14] - return gtin.padStart(targetLength, '0') + if (VALID.includes(digits.length)) { + return { value: digits, length: digits.length } + } + + const target = VALID.find((len) => digits.length < len) + + if (target) { + return { value: digits.padStart(target, '0'), length: target } + } + + return null +} + +const mapGtinToSpecificField = (gtinObj) => { + if (!gtinObj) return {} + const { value, length } = gtinObj + + switch (length) { + case 8: + return { gtin8: value } + + case 12: + return { gtin12: value } + + case 13: + return { gtin13: value } + + case 14: + return { gtin14: value } + + default: + return {} + } } const parseSKUToOffer = ( item, currency, - { decimals, pricesWithTax, useSellerDefault, gtinValue } + { decimals, pricesWithTax, useSellerDefault } ) => { const seller = useSellerDefault ? getSellerDefault(item.sellers) : lowHighForSellers(item.sellers, { pricesWithTax }).low const availability = getSKUAvailabilityString(seller) - const price = getFinalPrice(seller, getSpotPrice, { decimals, pricesWithTax }) - const rawGTIN = item?.[gtinValue] - const isGTINField = gtinValue !== 'itemId' && typeof rawGTIN === 'string' - const gtin = isGTINField ? formatGTIN(rawGTIN) : null - const skuValue = isGTINField ? gtin : item.itemId - // When a product is not available the API can't define its price and returns zero. // If we set structured data product price as zero, Google will show that the // product it's free (wrong info), but out of stock. @@ -103,7 +129,7 @@ const parseSKUToOffer = ( price, priceCurrency: currency, availability, - sku: skuValue, + sku: item.itemId, itemCondition: 'http://schema.org/NewCondition', priceValidUntil: path(['commertialOffer', 'PriceValidUntil'], seller), seller: { @@ -131,13 +157,7 @@ const getSellerDefault = (sellers) => { const composeAggregateOffer = ( product, currency, - { - decimals, - pricesWithTax, - useSellerDefault, - disableAggregateOffer, - gtinValue, - } + { decimals, pricesWithTax, useSellerDefault, disableAggregateOffer } ) => { const items = product.items || [] const allSellers = getAllSellers(items) @@ -149,7 +169,6 @@ const composeAggregateOffer = ( decimals, pricesWithTax, useSellerDefault, - gtinValue, }) ) .filter(Boolean) @@ -212,7 +231,6 @@ export const parseToJsonLD = ({ pricesWithTax, useSellerDefault, disableAggregateOffer, - gtinValue, }) if (offers === null) { @@ -220,18 +238,17 @@ export const parseToJsonLD = ({ } const baseUrl = getBaseUrl() - const category = getCategoryName(product) const rawGTIN = selectedItem?.[gtinValue] + const gtinObj = + gtinValue === 'itemId' + ? normalizeGTIN(selectedItem?.itemId) + : normalizeGTIN(rawGTIN) - let gtin = null + const gtinFields = mapGtinToSpecificField(gtinObj) - if (rawGTIN !== null && rawGTIN !== undefined) { - gtin = gtinValue === 'itemId' ? rawGTIN : formatGTIN(rawGTIN) - } - - const fallbackSKU = selectedItem?.itemId || null + const merchantSKU = selectedItem?.itemId || null const productLD = { '@context': 'https://schema.org/', @@ -244,10 +261,10 @@ export const parseToJsonLD = ({ : images[0]?.imageUrl || null, description: product.metaTagDescription || product.description, mpn, - sku: gtin || fallbackSKU, + sku: merchantSKU, category, offers: disableOffers ? null : offers, - gtin, + ...gtinFields, } return productLD @@ -281,6 +298,8 @@ function StructuredData({ product, selectedItem }) { gtinValue, }) + if (!productLD) return null + return