1// This script tracks key Ecommerce events such as: 2// 1. "add_to_cart" - Tracks when an item is added to the cart. 3// 2. "view_item" - Tracks when a user views a product. 4// 3. "begin_checkout" - Tracks when the user starts the checkout process. 5// 4. "purchase" - Tracks when the user completes the purchase (after the "Thank You" page). 6// The event data (product information, prices, etc.) is pushed to the dataLayer for analytics tracking (e.g., Google Tag Manager). 7// ============================ 8//File-Location : wp-content/themes/your-theme/js/EcommerceTracking.js 9 10// Wait for the DOM to be fully loaded before executing the script 11document.addEventListener("DOMContentLoaded", function () { 12 // Define the default currency code 13 const currencyCode = "INR"; 14 15 /** 16 * Push data to the `dataLayer` for GA4 tracking. 17 * @param {string} eventName - The name of the GA4 event (e.g., "add_to_cart"). 18 * @param {Object} data - The data object containing event details. 19 */ 20 function pushToDataLayer(eventName, data) { 21 window.dataLayer = window.dataLayer || []; 22 window.dataLayer.push({ event: eventName, ecommerce: data }); 23 } 24 25 /** 26 * Track "add_to_cart" events based on user interactions. 27 * Handles multiple button types and purchase options. 28 * @param {Event} event - The click event triggered by user interaction. 29 */ 30 function trackAddToCart(event) { 31 if ( 32 event.target.matches(".product_type_simple") && 33 !event.target.hasAttribute("data-tracked") 34 ) { 35 // Extract product data from attributes 36 event.target.setAttribute("data-tracked", "true"); 37 const itemId = 38 event.target.getAttribute("data-product_id") || "Unknown ID"; 39 const itemName = 40 event.target.getAttribute("data-product_name") || "Unknown Product"; 41 const priceElement = document.querySelector(".price bdi"); 42 const price = priceElement 43 ? parseFloat(priceElement.innerText.replace(/[^\d.]/g, "")) 44 : 0.0; 45 46 // Push event data for a simple add to cart action 47 pushToDataLayer("add_to_cart", { 48 currency: currencyCode, 49 value: price, 50 items: [ 51 { item_id: itemId, item_name: itemName, price: price, quantity: 1 }, 52 ], 53 }); 54 } else if ( 55 event.target.matches(".single_add_to_cart_button") && 56 !event.target.hasAttribute("data-tracked") 57 ) { 58 // Extract product data from the page 59 const productIdElement = document.querySelector( 60 'input[name="product_id"]' 61 ).value || "Unknown Product Id"; 62 63 event.target.setAttribute("data-tracked", "true"); 64 const itemName = 65 document 66 .querySelector(".elementor-widget-woocommerce-product-title h1") 67 ?.innerText.trim() || "Unknown Product"; 68 const price = 69 parseFloat( 70 document 71 .querySelector(".elementor-widget-container .price bdi") 72 ?.innerText.replace(/[^\d.]/g, "") 73 ) || 0.0; 74 75 // Push event data for a single product view 76 pushToDataLayer("add_to_cart", { 77 currency: currencyCode, 78 value: price, 79 //order_type: "One Time Purchase", 80 items: [ 81 { 82 item_id: productIdElement, 83 item_name: itemName, 84 price: price, 85 quantity: 1, 86 }, 87 ], 88 }); 89 } 90 else if ( 91 event.target.matches(".single_add_to_cart_button1") && 92 !event.target.hasAttribute("data-tracked") 93 ) { 94 // Extract product data from the page 95 const productIdElement = document.querySelector( 96 'input[name="product_id"]' 97 )?.value || "Unknown Product Id"; 98 99 event.target.setAttribute("data-tracked", "true"); 100 const itemName = 101 document 102 .querySelector(".elementor-widget-woocommerce-product-title h1") 103 ?.innerText.trim() || "Unknown Product"; 104 const price = 105 parseFloat( 106 document 107 .querySelector(".elementor-widget-container .price bdi") 108 ?.innerText.replace(/[^\d.]/g, "") 109 ) || 0.0; 110 111 // Push event data for a single product view 112 pushToDataLayer("add_to_cart", { 113 currency: currencyCode, 114 value: price, 115 //order_type: "One Time Purchase", 116 items: [ 117 { 118 item_id: productIdElement, 119 item_name: itemName, 120 price: price, 121 quantity: 1, 122 }, 123 ], 124 }); 125 } else if (event.target.closest(".wcsatt-options-prompt-label-one-time")) { 126 // Track one-time purchase option 127 const itemName = 128 document 129 .querySelector(".elementor-widget-woocommerce-product-title h1") 130 ?.innerText.trim() || "Unknown Product"; 131 const price = 132 parseFloat( 133 document 134 .querySelector(".elementor-widget-woocommerce-product-price p span") 135 ?.innerText.replace(/[^\d.]/g, "") 136 ) || 0.0; 137 138 pushToDataLayer("add_to_cart", { 139 currency: currencyCode, 140 value: price, 141 items: [{ item_name: itemName, price: price, quantity: 1 }], 142 }); 143 } else if ( 144 event.target.closest(".wcsatt-options-prompt-label-subscription") 145 ) { 146 // Track subscription option 147 const itemName = 148 document 149 .querySelector(".elementor-widget-woocommerce-product-title h1") 150 ?.innerText.trim() || "Unknown Product"; 151 const price = 152 parseFloat( 153 document 154 .querySelector(".elementor-widget-woocommerce-product-price p span") 155 ?.innerText.replace(/[^\d.]/g, "") 156 ) || 0.0; 157 158 pushToDataLayer("add_to_cart", { 159 currency: currencyCode, 160 value: price, 161 order_type: "Subscription", 162 items: [{ item_name: itemName, price: price, quantity: 1 }], 163 }); 164 } 165 } 166 167 /** 168 * Track "view_item" events when a product page is loaded. 169 */ 170 function trackViewItem() { 171 if (window.location.pathname.includes("/product/")) { 172 const productIdElement = 173 document.querySelector('input[name="product_id"]') 174 ?.value || "Unknown ID"; 175 176 const itemName = 177 document 178 .querySelector(".elementor-widget-woocommerce-product-title h1") 179 ?.innerText.trim() || "Unknown Product"; 180 181 const price = 182 parseFloat( 183 document 184 .querySelector(".elementor-widget-woocommerce-product-price p span") 185 ?.innerText.replace(/[^\d.]/g, "") 186 ) || 0.0; 187 188 const itemWeight = 189 document 190 .querySelector( 191 ".woocommerce-product-details__short-description div strong" 192 ) 193 ?.nextSibling?.textContent.trim() || "Unknown Weight"; 194 195 const itemRoastLevel = 196 document.querySelector(".roast_level_title")?.innerText.trim() || 197 "Unknown Roast Level"; 198 199 const itemOrigin = 200 document 201 .querySelector(".elementor-element-bde0230 p") 202 ?.innerText.trim() || "Unknown Origin"; 203 204 const itemTastingNotes = 205 document 206 .querySelector(".elementor-element-f1cd0ae p") 207 ?.innerText.trim() || "Unknown Tasting Notes"; 208 209 window.dataLayer = window.dataLayer || []; 210 window.dataLayer.push({ 211 event: "view_item", 212 currency: "INR", 213 value: price, 214 ecommerce: { 215 items: [ 216 { 217 item_id: productIdElement, 218 item_name: itemName, 219 item_weight: itemWeight, 220 item_roast_level: itemRoastLevel, 221 item_origin: itemOrigin, 222 item_tasting_notes: itemTastingNotes, 223 price: price, 224 quantity: 1, 225 }, 226 ], 227 }, 228 }); 229 } 230 } 231 232 /** 233 * Track "begin_checkout" events when the checkout process starts. 234 */ 235 236 function trackBeginCheckout() { 237 if ( 238 window.location.pathname.includes("/checkout/") && 239 !window.location.pathname.includes("/checkout/order-pay/") && 240 !window.location.pathname.includes("/checkout/thank-you/") 241 ) { 242 const cartItems = document.querySelectorAll(".cart_item"); 243 244 // Get total order value using the correct class 245 const orderTotalText = document 246 .querySelector(".order-total .total-price .woocommerce-Price-amount") 247 ?.innerText.trim(); 248 const totalAmount = 249 parseFloat(orderTotalText?.replace(/[^\d.]/g, "")) || 0; 250 251 const items = Array.from(cartItems).map((item) => { 252 const itemName = 253 item 254 .querySelector(".product-name") 255 ?.childNodes[0].textContent.trim() || "Unknown Product"; 256 257 // Log the itemName to debug 258 259 const price = 260 parseFloat( 261 item 262 .querySelector(".product-total .woocommerce-Price-amount") 263 ?.innerText.replace(/[^\d.-]/g, "") 264 ) || 0.0; 265 266 const quantity = 267 parseInt( 268 item 269 .querySelector(".product-name h6") 270 ?.innerText.replace(/[^\d]/g, ""), 271 10 272 ) || 1; 273 const itemId = 274 item.querySelector(".product-name input[type=hidden]")?.value || 275 "Unknown"; 276 277 return { 278 item_id: itemId, 279 item_name: itemName, 280 price: price, 281 quantity: quantity, 282 }; 283 }); 284 285 sessionStorage.setItem( 286 "checkoutData", 287 JSON.stringify({ currency: currencyCode, totalAmount, items }) 288 ); 289 290 pushToDataLayer("begin_checkout", { 291 currency: currencyCode, 292 value: totalAmount, 293 items: items, 294 }); 295 } 296 } 297 298 /**
299 * Track "purchase" events after order confirmation. 300 */ 301 function trackOrderConfirmed() { 302 if (window.location.pathname.includes("/thank-you/")) { 303 let transactionId = 304 document 305 .querySelector(".order-number") 306 ?.innerText.replace("Order #", "") 307 .trim() || "unknown_transaction"; 308 309 let email = 310 document 311 .querySelector( 312 ".order-detail .details-wrapper:nth-of-type(1) .order-detail-desc" 313 ) 314 ?.innerText.trim() || "unknown_email"; 315 316 let phone = 317 document 318 .querySelector( 319 ".order-detail .details-wrapper:nth-of-type(2) .order-detail-desc" 320 ) 321 ?.innerText.trim() || "unknown_phone"; 322 323 let orderData = document.querySelector("#hidden_order_data"); 324 let products = []; 325 326 if (orderData) { 327 let productIds = Array.from( 328 orderData.querySelectorAll("input[name='product_id[]']") 329 ).map((el) => el.value); 330 let productNames = Array.from( 331 orderData.querySelectorAll("input[name='product_name[]']") 332 ).map((el) => el.value); 333 let quantities = Array.from( 334 orderData.querySelectorAll("input[name='quantity[]']") 335 ).map((el) => parseInt(el.value) || 1); 336 let prices = Array.from( 337 orderData.querySelectorAll("input[name='price[]']") 338 ).map((el) => parseFloat(el.value) || 0); 339 340 productIds.forEach((id, index) => { 341 products.push({ 342 item_id: id, 343 item_name: productNames[index] || "Unknown Product", 344 quantity: quantities[index], 345 price: prices[index], 346 }); 347 }); 348 } 349 350 let orderTotal = 351 parseFloat( 352 orderData?.querySelector("input[name='order_total']")?.value 353 ) || 0; 354 let shippingTotal = 355 parseFloat( 356 orderData?.querySelector("input[name='shipping_total']")?.value 357 ) || 0; 358 359 window.dataLayer = window.dataLayer || []; 360 window.dataLayer.push({ 361 event: "purchase", 362 ecommerce: { 363 transaction_id: transactionId, 364 currency: "INR", 365 value: orderTotal + shippingTotal, // Total order value including shipping 366 shipping: shippingTotal, 367 items: products, 368 }, 369 customer_info: { 370 email: email, 371 phone: phone, 372 }, 373 }); 374 } 375 } 376 377 /** 378 * Track "view_cart" events when the cart is viewed. 379 */ 380 document.addEventListener("click", function (e) { 381 if (e.target.closest(".elementor-menu-cart__toggle_button")) { 382 const cartItems = document.querySelectorAll( 383 ".widget_shopping_cart_content .cart-products-wrapper ul li .line-item-container" 384 ); 385 const totalPriceElement = document.querySelector( 386 ".total-wrapper .order-total td strong bdi" 387 ); 388 const totalAmount = 389 parseFloat(totalPriceElement?.innerText.replace(/[^\d.-]/g, "")) || 0; 390 391 const items = []; 392 const itemMap = {}; // Object to track unique items by name 393 394 cartItems.forEach((item) => { 395 const itemName = 396 item.querySelector(".item-second-col a")?.innerText.trim() || 397 "Unknown Product"; 398 399 const price = 400 parseFloat( 401 item 402 .querySelector(".item-last-col .item-price") 403 ?.innerText.replace(/[^\d.-]/g, "") 404 ) || 0.0; 405 const quantity = 406 parseInt( 407 item.querySelector(".main_show_qty")?.value.replace(/[^\d]/g, ""), 408 10 409 ) || 1; 410 411 // Fetch the item ID from the <a> tag (data-product_id attribute) 412 const itemId = 413 item 414 .querySelector(".mini-c-close a") 415 ?.getAttribute("data-product_id") || "Unknown ID"; 416 417 // Check if the item already exists in the map 418 if (itemMap[itemName]) { 419 } else { 420 itemMap[itemName] = { 421 item_id: itemId, 422 item_name: itemName, 423 price: price, 424 quantity: quantity, 425 }; 426 } 427 }); 428 429 // Convert the itemMap values to an array 430 const uniqueItems = Object.values(itemMap); 431 432 pushToDataLayer("view_cart", { 433 currency: currencyCode, 434 value: parseFloat(totalAmount.toFixed(2)), 435 items: uniqueItems, 436 }); 437 } 438 }); 439 440 // Add event listeners for tracking 441 document.addEventListener("click", trackAddToCart); 442 trackViewItem(); 443 trackBeginCheckout(); 444 trackOrderConfirmed(); 445});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.