Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ The **Universal Conversions Variable for Google Tag Manager Web container** allo
- **item count**
- etc.

- ### Product ID Formatting

This template includes advanced options for formatting the product IDs sent to various platforms.

| Field | Description |
| :--- | :--- |
| **Product ID Format** | A dropdown menu to select which ID to use. <br> - **Default:** Uses the original `Product ID/SKU` field. <br> - **Variant ID:** Uses the ID from the `Item Variant ID Key` field. <br> - **SKU:** Uses the ID from the `Item SKU Key` field. <br> - **Custom Shopify:** Builds a custom string in the format `shopify_MARKET_prod_var`. |
| **Item Variant ID Key** | **Required for 'Variant ID' & 'Custom Shopify'.** The Data Layer key for your item's variant ID (e.g., `item_variant`). |
| **Item SKU Key** | **Required for 'SKU'.** The Data Layer key for your item's SKU (e.g., `item_sku`). |
| **Market Code** | **Used for 'Custom Shopify'.** The market code (e.g., `GB`, `US`) to be prefixed to the custom ID. |

It currenly supports the following platforms:
- Meta Pixel/CAPI
- Google Analytics 4
Expand Down
94 changes: 82 additions & 12 deletions template.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const Object = require('Object');
/*==============================================================================
==============================================================================*/

// Original Key fields
const keyId = data.keyId;
const keyPr = data.keyPr;
const keyNm = data.keyNm;
Expand All @@ -18,6 +19,14 @@ const keyImg = data.keyImg;
const contentType = data.contentType;
const taxDeductPercent = toFixed2(makeNumber(data.taxDeductPercent));
const keyDisc = data.keyDiscItemLevel;

// --- NEW FIELDS ---
const idFormat = data.idFormatType;
const keySku = data.keySku;
const keyVariantId = data.keyVariantId;
const market = data.marketCode || '';
// --- END NEW FIELDS ---

const customParamMap = data.customParams
? makeTableMap(data.customParams, 'cusKey', 'cusName')
: {};
Expand Down Expand Up @@ -75,7 +84,9 @@ function getContentName(arr) {
}

function getContentIds(arr) {
const content_ids = arr.map((item) => item[keyId]);
// --- MODIFIED ---
const content_ids = arr.map((item) => getFormattedId(item));
// --- END MODIFIED ---
return content_ids;
}

Expand All @@ -84,7 +95,9 @@ function getItem(arr) {
cat.push(arr[0][keyCat]);

let item = {
ProductID: arr[0][keyId],
// --- MODIFIED ---
ProductID: getFormattedId(arr[0]),
// --- END MODIFIED ---
ProductName: arr[0][keyNm],
Price: arr[0][keyPr],
ImageURL: arr[0][keyImg],
Expand Down Expand Up @@ -112,15 +125,19 @@ function getContents(arr, platform) {

if (platform === 'meta') {
contents.push({
id: arr[i][keyId],
// --- MODIFIED ---
id: getFormattedId(arr[i]),
// --- END MODIFIED ---
quantity: qt,
item_price: arr[i][keyPr]
});
}

if (platform === 'tiktok') {
contents.push({
content_id: makeString(arr[i][keyId]),
// --- MODIFIED ---
content_id: getFormattedId(arr[i]),
// --- END MODIFIED ---
content_type: contentType,
content_category: arr[i][keyCat],
content_name: arr[i][keyNm],
Expand All @@ -131,7 +148,9 @@ function getContents(arr, platform) {

if (platform === 'twitter') {
contents.push({
content_id: arr[i][keyId],
// --- MODIFIED ---
content_id: getFormattedId(arr[i]),
// --- END MODIFIED ---
content_name: arr[i][keyNm],
content_type: arr[i][keyCat],
num_items: qt,
Expand All @@ -143,6 +162,7 @@ function getContents(arr, platform) {
contents.push({
quantity: qt,
item_price: arr[i][keyPr] ? makeString(arr[i][keyPr]) : '0'
// Pinterest 'contents' array doesn't use ID
});
}
}
Expand All @@ -167,7 +187,9 @@ function getItems(arr, platform) {

if (platform === 'ga4') {
let itemObj = {
item_id: arr[i][keyId],
// --- MODIFIED ---
item_id: getFormattedId(arr[i]),
// --- END MODIFIED ---
item_name: arr[i][keyNm],
quantity: qt,
price: arr[i][keyPr],
Expand All @@ -189,7 +211,9 @@ function getItems(arr, platform) {
cat.push(arr[i][keyCat]);

let itemObj = {
ProductID: arr[i][keyId],
// --- MODIFIED ---
ProductID: getFormattedId(arr[i]),
// --- END MODIFIED ---
ProductName: arr[i][keyNm],
Quantity: qt,
ItemPrice: arr[i][keyPr],
Expand All @@ -208,7 +232,9 @@ function getItems(arr, platform) {

if (platform === 'criteo') {
let itemObj = {
id: arr[i][keyId],
// --- MODIFIED ---
id: getFormattedId(arr[i]),
// --- END MODIFIED ---
quantity: qt,
price: arr[i][keyPr]
};
Expand All @@ -218,15 +244,19 @@ function getItems(arr, platform) {

if (platform === 'gAdsOff') {
items.push({
productId: makeString(arr[i][keyId]),
// --- MODIFIED ---
productId: getFormattedId(arr[i]),
// --- END MODIFIED ---
quantity: qt,
unitPrice: makeNumber(arr[i][keyPr])
});
}

if (platform === 'pinterest') {
items.push({
product_id: arr[i][keyId],
// --- MODIFIED ---
product_id: getFormattedId(arr[i]),
// --- END MODIFIED ---
product_name: arr[i][keyNm],
product_quantity: qt,
product_price: arr[i][keyPr] ? makeNumber(arr[i][keyPr]) : 0
Expand All @@ -235,7 +265,9 @@ function getItems(arr, platform) {

if (platform === 'reddit') {
items.push({
id: arr[i][keyId],
// --- MODIFIED ---
id: getFormattedId(arr[i]),
// --- END MODIFIED ---
category: arr[i][keyCat],
name: arr[i][keyNm]
});
Expand Down Expand Up @@ -263,7 +295,9 @@ function getItems(arr, platform) {
}

let itemObj = {
sku: arr[i][keyId],
// --- MODIFIED ---
sku: getFormattedId(arr[i]), // Rakuten uses SKU as the main ID
// --- END MODIFIED ---
product_name: arr[i][keyNm],
quantity: qt,
amount: price > 0 ? price : toFixed2(p * 100 * qt),
Expand Down Expand Up @@ -302,6 +336,42 @@ function getItems(arr, platform) {
Helpers
==============================================================================*/

// --- NEW HELPER FUNCTION ---
// This function builds the ID based on the user's selection
function getFormattedId(item) {
// 1. Get the default ID (from the 'keyId' field) as a fallback
const defaultId = item[keyId] ? makeString(item[keyId]) : undefined;

// 2. Check the format dropdown
switch (idFormat) {
case 'sku':
// Use 'keySku' field if available, otherwise fall back to default
return item[keySku] ? makeString(item[keySku]) : defaultId;

case 'variantId':
// Use 'keyVariantId' field if available, otherwise fall back to default
return item[keyVariantId] ? makeString(item[keyVariantId]) : defaultId;

case 'customShopify':
// Use 'keyId' (as Product) and 'keyVariantId' (as Variant)
const prodId = item[keyId];
const varId = item[keyVariantId];

if (prodId && varId) {
// Build the custom string
return 'shopify_' + market + '_' + makeString(prodId) + '_' + makeString(varId);
}
// If data is missing, fall back to default
return defaultId;

case 'default':
default:
// Return the default ID
return defaultId;
}
}
// --- END NEW HELPER FUNCTION ---

function toFixed2(num) {
return math.round(num * 100) / 100;
}
Expand Down
Loading