PageSourceSearch

https://openupwide.com/wp-content/plugins/duracelltomi-google-tag-…/gtm4wp-woocommerce-enhanced.js?ver=1.16.2

js openupwide.com collected 2026-09-24 14:49:32 UTC 41,370 bytes, 1,223 lines download raw bytes

1window.gtm4wp_last_selected_product_variation;
2window.gtm4wp_changedetail_fired_during_pageload=false;
3
4window.gtm4wp_is_cart     = false;
5window.gtm4wp_is_checkout = false;
6window.gtm4wp_checkout_step_fired = []; // step 1 will be the billing section which is reported during pageload, no need to handle here
7window.gtm4wp_shipping_payment_method_step_offset =  gtm4wp_needs_shipping_address ? 0 : -1;
8
9window.gtm4wp_first_container_id = "";
10
11function gtm4wp_map_eec_to_ga4( productdata ) {
12	if ( !productdata ) {
13		return;
14	}
15
16	const category_path  = productdata.category ? productdata.category : '';
17	const category_parts = category_path.toString().split('/');
18
19	// default, required parameters
20	let ga4_product = {
21		'item_id': productdata.id ? productdata.id : '',
22		'item_name': productdata.name ? productdata.name : '',
23		'item_brand': productdata.brand ? productdata.brand : '',
24		'price': productdata.price ? productdata.price : ""
25	};
26
27	// category, also handle category path
28	if ( 1 == category_parts.length ) {
29		ga4_product.item_category = category_parts[0];
30	} else if ( category_parts.length > 1 ) {
31		ga4_product.item_category = category_parts[0];
32		for( let i=1; i < Math.min( 5, category_parts.length ); i++ ) {
33			ga4_product[ 'item_category' + (i+1) ] = category_parts[i];
34		}
35	}
36
37	// optional parameters which should not be included in the array if not set
38	if ( productdata.variant ) {
39		ga4_product.item_variant = productdata.variant;
40	}
41	if ( productdata.list ) {
42		ga4_product.item_list_name = productdata.list;
43	}
44	if ( productdata.position ) {
45		ga4_product.index = productdata.position;
46	}
47	if ( productdata.quantity ) {
48		ga4_product.quantity = productdata.quantity;
49	}
50	if ( productdata.coupon ) {
51		ga4_product.coupon = productdata.coupon;
52	}
53
54	ga4_product.google_business_vertical = gtm4wp_business_vertical;
55	ga4_product[ gtm4wp_business_vertical_id ] = gtm4wp_id_prefix + ga4_product[ "item_id" ];
56
57	return ga4_product;
58}
59
60function gtm4wp_handle_cart_qty_change() {
61	document.querySelectorAll( '.product-quantity input.qty' ).forEach(function( qty_el ) {
62		const original_value = qty_el.defaultValue;
63
64		let current_value  = parseInt( qty_el.value );
65		if ( isNaN( current_value ) ) {
66			current_value = original_value;
67		}
68
69		// is quantity changed changed?
70		if ( original_value != current_value ) {
71			const cart_item_temp = qty_el.closest( '.cart_item' );
72			const productdata = cart_item_temp && cart_item_temp.querySelector( '.remove' );
73			if ( !productdata ) {
74				return;
75			}
76
77			let productprice = productdata.getAttribute( 'data-gtm4wp_product_price' );
78
79			if ( typeof productprice == "string" ) {
80				productprice = parseFloat( productprice );
81				if ( isNaN( productprice ) ) {
82					productprice = 0;
83				}
84			} else if ( typeof productprice != "number" ) {
85				productprice = 0;
86			}
87
88			// does the quantity increase?
89			if ( original_value < current_value ) {
90				// yes => handle add to cart event
91				const product_data = {
92					'name':       productdata.getAttribute( 'data-gtm4wp_product_name' ),
93					'id':         productdata.getAttribute( 'data-gtm4wp_product_id' ),
94					'price':      productprice.toFixed(2),
95					'category':   productdata.getAttribute( 'data-gtm4wp_product_cat' ),
96					'variant':    productdata.getAttribute( 'data-gtm4wp_product_variant' ),
97					'stocklevel': productdata.getAttribute( 'data-gtm4wp_product_stocklevel' ),
98					'brand':      productdata.getAttribute( 'data-gtm4wp_product_brand' ),
99					'quantity':   current_value - original_value
100				};
101
102				// fire ga3 version
103				window[ gtm4wp_datalayer_name ].push({
104					'event': 'gtm4wp.addProductToCartEEC',
105					'ecommerce': {
106						'currencyCode': gtm4wp_currency,
107						'add': {
108							'products': [ product_data ]
109						}
110					}
111				});
112
113				// fire ga4 version
114				window[ gtm4wp_datalayer_name ].push({
115					'event': 'add_to_cart',
116					'ecommerce': {
117						'currency': gtm4wp_currency, // ga4 version
118						'value': productprice.toFixed(2) * (current_value - original_value),
119						'items': [ gtm4wp_map_eec_to_ga4( product_data ) ]
120					}
121				});
122			} else {
123				// no => handle remove from cart event
124				const product_data = {
125					'name':       productdata.getAttribute( 'data-gtm4wp_product_name' ),
126					'id':         productdata.getAttribute( 'data-gtm4wp_product_id' ),
127					'price':      productprice.toFixed(2),
128					'category':   productdata.getAttribute( 'data-gtm4wp_product_cat' ),
129					'variant':    productdata.getAttribute( 'data-gtm4wp_product_variant' ),
130					'stocklevel': productdata.getAttribute( 'data-gtm4wp_product_stocklevel' ),
131					'brand':      productdata.getAttribute( 'data-gtm4wp_product_brand' ),
132					'quantity':   original_value - current_value
133				};
134
135				// fire ga3 version
136				window[ gtm4wp_datalayer_name ].push({
137					'event': 'gtm4wp.removeFromCartEEC',
138					'ecommerce': {
139						'currencyCode': gtm4wp_currency,
140						'remove': {
141							'products': [ product_data ]
142						}
143					}
144				});
145
146				// fire ga4 version
147				window[ gtm4wp_datalayer_name ].push({
148					'event': 'remove_from_cart',
149					'ecommerce': {
150						'currency': gtm4wp_currency,
151						'value': productprice.toFixed(2) * (original_value - current_value),
152						'items': [ gtm4wp_map_eec_to_ga4( product_data ) ]
153					}
154				});
155			}
156		} // end if qty changed
157	}); // end each qty field
158} // end gtm4wp_handle_cart_qty_change()
159
160function gtm4wp_handle_payment_method_change() {
161	// do not report checkout step if already reported
162	if ( gtm4wp_checkout_step_fired.indexOf( 'payment_method' ) > -1 ) {
163		return;
164	}
165
166	// do not fire event during page load
167	if ( 'complete' != document.readyState ) {
168		return;
169	}
170
171	let payment_type = '(payment type not found)';
172	let payment_el = document.querySelector( '.payment_methods input:checked' );
173	if ( !payment_el ) {
174		payment_el = document.querySelector( 'input[name^=payment_method]' ); // select the first input element
175	}
176	if ( payment_el ) {
177		payment_type = payment_el.value;
178	}
179
180	// fire ga3 version
181	window[ gtm4wp_datalayer_name ].push({
182		'event': 'gtm4wp.checkoutStepEEC',
183		'ecommerce': {
184			'currencyCode': gtm4wp_currency,
185			'checkout': {
186				'actionField': {
187					'step': 4 + window.gtm4wp_checkout_step_offset + gtm4wp_shipping_payment_method_step_offset
188				},
189				'products': window.gtm4wp_checkout_products
190			}
191		}
192	});
193
194	// fire ga4 version
195	window[ gtm4wp_datalayer_name ].push({
196		'event': 'add_payment_info',
197		'ecommerce': {
198			'currency': gtm4wp_currency,
199			'payment_type': payment_type,
200			'value': window.gtm4wp_checkout_value,
201			'items': window.gtm4wp_checkout_products_ga4
202		}
203	});
204
205	gtm4wp_checkout_step_fired.push( 'payment_method' );
206} // end gtm4wp_handle_payment_method_change()
207
208function gtm4wp_handle_shipping_method_change() {
209	// do not report checkout step if already reported
210	if ( gtm4wp_checkout_step_fired.indexOf( 'shipping_method' ) > -1 ) {
211		return;
212	}
213
214	// do not fire event during page load
215	if ( 'complete' != document.readyState ) {
216		return;
217	}
218
219	let shipping_tier = '(shipping tier not found)';
220	let shipping_el = document.querySelector( 'input[name^=shipping_method]:checked' );
221	if ( !shipping_el ) {
222		shipping_el = document.querySelector( 'input[name^=shipping_method]' ); // select the first input element
223	}
224	if ( shipping_el ) {
225		shipping_tier = shipping_el.value;
226	}
227
228	// fire ga3 version
229	window[ gtm4wp_datalayer_name ].push({
230		'event': 'gtm4wp.checkoutStepEEC',
231		'ecommerce': {
232			'currencyCode': gtm4wp_currency,
233			'checkout': {
234				'actionField': {
235					'step': 3 + window.gtm4wp_checkout_step_offset + gtm4wp_shipping_payment_method_step_offset
236				},
237				'products': window.gtm4wp_checkout_products
238			}
239		}
240	});
241
242	// fire ga4 version
243	window[ gtm4wp_datalayer_name ].push({
244		'event': 'add_shipping_info',
245		'ecommerce': {
246			'currency': gtm4wp_currency,
247			'shipping_tier': shipping_tier,
248			'value': window.gtm4wp_checkout_value,
249			'items': window.gtm4wp_checkout_products_ga4
250		}
251	});
252
253	gtm4wp_checkout_step_fired.push( 'shipping_method' );
254}
255
256function gtm4wp_process_woocommerce_pages() {
257	window.gtm4wp_is_cart     = false;
258	window.gtm4wp_is_checkout = false;
259
260	const doc_body = document.querySelector( 'body' );
261	if ( doc_body ) {
262		window.gtm4wp_is_cart     = doc_body.classList && doc_body.classList.contains( 'woocommerce-cart' );
263		window.gtm4wp_is_checkout = doc_body.classList && doc_body.classList.contains( 'woocommerce-checkout' );
264	}
265
266	// loop through WC blocks to set proper listname and position parameters
267	const gtm4wp_product_block_names = {
268		'wp-block-handpicked-products': {
269			'displayname': 'Handpicked Products',
270			'counter': 1
271		},
272		'wp-block-product-best-sellers': {
273			'displayname': 'Best Selling Products',
274			'counter': 1
275		},
276		'wp-block-product-category': {
277			'displayname': 'Product Category List',
278			'counter': 1
279		},
280		'wp-block-product-new': {
281			'displayname': 'New Products',
282			'counter': 1
283		},
284		'wp-block-product-on-sale': {
285			'displayname': 'Sale Products',
286			'counter': 1
287		},
288		'wp-block-products-by-attribute': {
289			'displayname': 'Products By Attribute',
290			'counter': 1
291		},
292		'wp-block-product-tag': {
293			'displayname': 'Products By Tag',
294			'counter': 1
295		},
296		'wp-block-product-top-rated': {
297			'displayname': 'Top Rated Products',
298			'counter': 1
299		},
300	}
301	document.querySelectorAll( '.wc-block-grid .wc-block-grid__product' ).forEach( function( product_grid_item ) {
302
303		const product_grid_container = product_grid_item.closest( '.wc-block-grid' );
304		const product_data = product_grid_item.querySelector( '.gtm4wp_productdata' );
305
306		if ( product_grid_container && product_data ) {
307
308			const product_grid_container_classes = product_grid_container.classList;
309
310			if ( product_grid_container_classes ) {
311
312				for(let i in gtm4wp_product_block_names) {
313					if ( product_grid_container_classes.contains( i ) ) {
314						product_data.setAttribute("data-gtm4wp_productlist_name", gtm4wp_product_block_names[i].displayname);
315						product_data.setAttribute("data-gtm4wp_product_listposition", gtm4wp_product_block_names[i].counter);
316
317						gtm4wp_product_block_names[i].counter++;
318					}
319				}
320			}
321		}
322	});
323
324	// track impressions of products in product lists
325	if ( document.querySelectorAll( '.gtm4wp_productdata,.widget-product-item' ).length > 0 ) {
326		let products = [];
327		let ga4_products = [];
328		let productprice = 0;
329		let product_data;
330
331		document.querySelectorAll( '.gtm4wp_productdata,.widget-product-item' ).forEach( function( dom_productdata ) {
332			productprice = dom_productdata.getAttribute( 'data-gtm4wp_product_price' );
333
334			if ( typeof productprice == "string" ) {
335				productprice = parseFloat( productprice );
336				if ( isNaN( productprice ) ) {
337					productprice = 0;
338				}
339			} else if ( typeof productprice != "number" ) {
340				productprice = 0;
341			}
342
343			product_data = {
344				'name':       dom_productdata.getAttribute( 'data-gtm4wp_product_name' ),
345				'id':         dom_productdata.getAttribute( 'data-gtm4wp_product_id' ),
346				'price':      productprice.toFixed(2),
347				'category':   dom_productdata.getAttribute( 'data-gtm4wp_product_cat' ),
348				'position':   dom_productdata.getAttribute( 'data-gtm4wp_product_listposition' ),
349				'list':       dom_productdata.getAttribute( 'data-gtm4wp_productlist_name' ),
350				'stocklevel': dom_productdata.getAttribute( 'data-gtm4wp_product_stocklevel' ),
351				'brand':      dom_productdata.getAttribute( 'data-gtm4wp_product_brand' )
352			};
353
354			products.push(product_data);
355			ga4_products.push( gtm4wp_map_eec_to_ga4( product_data ) );
356		});
357
358		if ( gtm4wp_product_per_impression > 0 ) {
359			// Need to split the product submissions up into chunks in order to avoid the GA 8kb submission limit
360			let chunk
361			let ga4_chunk;
362
363			while ( products.length ) {
364				chunk = products.splice( 0, gtm4wp_product_per_impression );
365				ga4_chunk = ga4_products.splice( 0, gtm4wp_product_per_impression );
366
367				// fire ga3 version
368				window[ gtm4wp_datalayer_name ].push({
369					'event': 'gtm4wp.productImpressionEEC',
370					'ecommerce': {
371						'currencyCode': gtm4wp_currency,
372						'impressions': chunk
373					}
374				});
375
376				// fire ga4 version
377				window[ gtm4wp_datalayer_name ].push({
378					'event': 'view_item_list',
379					'ecommerce': {
380						'currency': gtm4wp_currency,
381						'items': ga4_chunk
382					}
383				});
384			}
385		} else {
386			for( var i=0; i<window[ gtm4wp_datalayer_name ].length; i++ ) {
387				if ( window[ gtm4wp_datalayer_name ][ i ][ 'ecommerce' ] ) {
388
389					if ( ! window[ gtm4wp_datalayer_name ][ i ][ 'ecommerce' ][ 'impressions' ] ) {
390						window[ gtm4wp_datalayer_name ][ i ][ 'ecommerce' ][ 'impressions' ] = products;
391					} else {
392						window[ gtm4wp_datalayer_name ][ i ][ 'ecommerce' ][ 'impressions' ] = window[ gtm4wp_datalayer_name ][ i ][ 'ecommerce' ][ 'impressions' ].concat( products );
393					}
394
395					break;
396				}
397			}
398
399			if ( i == window[ gtm4wp_datalayer_name ].length ) {
400				// no existing ecommerce data found in the datalayer
401				i = 0;
402				window[ gtm4wp_datalayer_name ][ i ][ 'ecommerce' ] = {};
403				window[ gtm4wp_datalayer_name ][ i ][ 'ecommerce' ][ 'impressions' ] = products;
404			}
405
406			window[ gtm4wp_datalayer_name ][ i ][ 'ecommerce' ][ 'currencyCode' ] = gtm4wp_currency;
407		}
408	}
409
410	// track add to cart events for simple products in product lists
411	document.addEventListener( 'click', function( e ) {
412		let event_target_element = e.target;
413
414		if ( !event_target_element ) {
415			// for some reason event target is not specificed
416			return true;
417		}
418
419		try {
420			if ( !event_target_element.closest( '.add_to_cart_button:not(.product_type_variable, .product_type_grouped, .single_add_to_cart_button)' ) ) {
421				return true;
422			}
423		} catch (e) {
424			// during beta testing, closest() sometimes threw SyntaxError which is thrown if selector is invali
424d. But the selector above should be valid in all cases
425			// assumption was that perhaps event_target_element was not set or not a proper DOM node for some reasons
426			return true;
427		}
428
429		const product_el = event_target_element.closest( '.product,.wc-block-grid__product' );
430		const productdata = product_el && product_el.querySelector( '.gtm4wp_productdata' );
431		if ( !productdata ) {
432			return true;
433		}
434
435		let productprice = productdata.getAttribute( 'data-gtm4wp_product_price' );
436
437		if ( typeof productprice == "string" ) {
438			productprice = parseFloat( productprice );
439			if ( isNaN( productprice ) ) {
440				productprice = 0;
441			}
442		} else if ( typeof productprice != "number" ) {
443			productprice = 0;
444		}
445
446		const product_data = {
447			'name':       productdata.getAttribute( 'data-gtm4wp_product_name' ),
448			'id':         productdata.getAttribute( 'data-gtm4wp_product_id' ),
449			'price':      productprice.toFixed(2),
450			'category':   productdata.getAttribute( 'data-gtm4wp_product_cat' ),
451			'stocklevel': productdata.getAttribute( 'data-gtm4wp_product_stocklevel' ),
452			'brand':      productdata.getAttribute( 'data-gtm4wp_product_brand' ),
453			'quantity':   1
454		};
455
456		// fire ga3 version
457		window[ gtm4wp_datalayer_name ].push({
458			'event': 'gtm4wp.addProductToCartEEC',
459			'ecommerce': {
460				'currencyCode': gtm4wp_currency,
461				'add': {
462					'products': [ product_data ]
463				}
464			}
465		});
466
467		// fire ga4 version
468		window[ gtm4wp_datalayer_name ].push({
469			'event': 'add_to_cart',
470			'ecommerce': {
471				'currency': gtm4wp_currency,
472				'value': productprice.toFixed(2),
473				'items': [ gtm4wp_map_eec_to_ga4( product_data ) ]
474			}
475		});
476	});
477
478	// track add to cart events for products on product detail pages
479	document.addEventListener( 'click', function( e ) {
480		let event_target_element = e.target;
481
482		if ( !event_target_element ) {
483			// for some reason event target is not specificed
484			return true;
485		}
486
487		try {
488			if ( !event_target_element.closest( '.single_add_to_cart_button:not(.disabled)' ) ) {
489				return true;
490			}
491		} catch (e) {
492			// during beta testing, closest() sometimes threw SyntaxError which is thrown if selector is invalid. But the selector above should be valid in all cases
493			// assumption was that perhaps event_target_element was not set or not a proper DOM node for some reasons
494			return true;
495		}
496
497		const product_form = event_target_element.closest( 'form.cart' );
498		if ( !product_form ) {
499			return true;
500		}
501
502		let product_variant_id = product_form.querySelectorAll( '[name=variation_id]' );
503		let product_is_grouped = product_form.classList && product_form.classList.contains( 'grouped_form' );
504
505		if ( product_variant_id.length > 0 ) {
506			if ( gtm4wp_last_selected_product_variation ) {
507				const qty_el = product_form.querySelector( '[name=quantity]' );
508				gtm4wp_last_selected_product_variation.quantity = (qty_el && qty_el.value) || 1;
509
510				// fire ga3 version
511				window[ gtm4wp_datalayer_name ].push({
512					'event': 'gtm4wp.addProductToCartEEC',
513					'ecommerce': {
514						'currencyCode': gtm4wp_currency,
515						'add': {
516							'products': [gtm4wp_last_selected_product_variation]
517						}
518					}
519				});
520
521				// fire ga4 version
522				window[ gtm4wp_datalayer_name ].push({
523					'event': 'add_to_cart',
524					'ecommerce': {
525						'currency': gtm4wp_currency,
526						'value': gtm4wp_last_selected_product_variation.price * gtm4wp_last_selected_product_variation.quantity,
527						'items': [ gtm4wp_map_eec_to_ga4( gtm4wp_last_selected_product_variation ) ]
528					}
529				});
530			}
531		} else if ( product_is_grouped ) {
532			const products_in_group = document.querySelectorAll( '.grouped_form .gtm4wp_productdata' );
533			let products = [];
534			let ga4_products = [];
535			let sum_value = 0;
536
537			products_in_group.forEach( function( dom_productdata ) {
538				const product_qty_input = document.querySelectorAll( 'input[name=quantity\\[' + dom_productdata.getAttribute( 'data-gtm4wp_product_id' ) + '\\]]' );
539				if ( product_qty_input.length > 0 ) {
540					product_qty = (product_qty_input[0] && product_qty_input[0].value) || 1;
541				} else {
542					return true;
543				}
544
545				if ( 0 == product_qty ) {
546					return true;
547				}
548
549				const product_data = {
550					'id':         gtm4wp_use_sku_instead ? dom_productdata.getAttribute( 'data-gtm4wp_product_sku' ) : dom_productdata.getAttribute( 'data-gtm4wp_product_id' ),
551					'name':       dom_productdata.getAttribute( 'data-gtm4wp_product_name' ),
552					'price':      dom_productdata.getAttribute( 'data-gtm4wp_product_price' ),
553					'category':   dom_productdata.getAttribute( 'data-gtm4wp_product_cat' ),
554					'quantity':   product_qty,
555					'stocklevel': dom_productdata.getAttribute( 'data-gtm4wp_product_stocklevel' ),
556					'brand':      dom_productdata.getAttribute( 'data-gtm4wp_product_brand' )
557				};
558
559				products.push( product_data );
560				ga4_products.push( gtm4wp_map_eec_to_ga4( product_data ) );
561				sum_value += product_data.price * product_data.quantity;
562			});
563
564			if ( 0 == products.length ) {
565				return true;
566			}
567
568			// fire ga3 version
569			window[ gtm4wp_datalayer_name ].push({
570				'event': 'gtm4wp.addProductToCartEEC',
571				'ecommerce': {
572					'currencyCode': gtm4wp_currency,
573					'add': {
574						'products': products
575					}
576				}
577			});
578
579			// fire ga4 version
580			window[ gtm4wp_datalayer_name ].push({
581				'event': 'add_to_cart',
582				'ecommerce': {
583					'currency': gtm4wp_currency,
584					'value': sum_value,
585					'items': ga4_products
586				}
587			});
588		} else {
589			const product_id_el = gtm4wp_use_sku_instead ? product_form.querySelector( '[name=gtm4wp_sku]' ) : product_form.querySelector( '[name=gtm4wp_id]' );
590			const product_data = {
591				'id':         product_id_el && product_id_el.value,
592				'name':       product_form.querySelector( '[name=gtm4wp_name]' ) && product_form.querySelector( '[name=gtm4wp_name]' ).value,
593				'price':      product_form.querySelector( '[name=gtm4wp_price]' ) && product_form.querySelector( '[name=gtm4wp_price]' ).value,
594				'category':   product_form.querySelector( '[name=gtm4wp_category]' ) && product_form.querySelector( '[name=gtm4wp_category]' ).value,
595				'quantity':   product_form.querySelector( '[name=quantity]' ) && product_form.querySelector( '[name=quantity]' ).value,
596				'stocklevel': product_form.querySelector( '[name=gtm4wp_stocklevel]' ) && product_form.querySelector( '[name=gtm4wp_stocklevel]' ).value,
597				'brand':      product_form.querySelector( '[name=gtm4wp_brand]' ) && product_form.querySelector( '[name=gtm4wp_brand]' ).value
598			};
599
600			// fire ga3 version
601			window[ gtm4wp_datalayer_name ].push({
602				'event': 'gtm4wp.addProductToCartEEC',
603				'ecommerce': {
604					'currencyCode': gtm4wp_currency,
605					'add': {
606						'products': [ product_data ]
607					}
608				}
609			});
610
611			// fire ga4 version
612			window[ gtm4wp_datalayer_name ].push({
613				'event': 'add_to_cart',
614				'ecommerce': {
615					'currency': gtm4wp_currency,
616					'value': product_data.price * product_data.quantity,
617					'items': [ gtm4wp_map_eec_to_ga4( product_data ) ]
618				}
619			});
620		}
621	});
622
623	// track remove links in mini cart widget and on cart page
624	document.addEventListener( 'click', function( e ) {
625		const dom_productdata = e.target;
626
627		if ( !dom_productdata || !dom_productdata.closest( '.mini_cart_item a.remove,.product-remove a.remove' ) ) {
628			return true;
629		}
630
631		let qty = 0;
632		const cart_item_el = dom_productdata.closest( '.cart_item' );
633		let qty_element = cart_item_el && cart_item_el.querySelectorAll( '.product-quantity input.qty' );
634		if ( !qty_element || ( qty_element.length === 0 ) ) {
635			const mini_cart_item_el = dom_productdata.closest( '.mini_cart_item' );
636			qty_element = mini_cart_item_el && mini_cart_item_el.querySelectorAll( '.quantity' );
637			if ( qty_element && ( qty_element.length > 0 ) ) {
638				qty = parseInt( qty_element[0].textContent );
639
640				if ( Number.isNaN( qty ) ) {
641					qty = 0;
642				}
643			}
644		} else {
645			qty = qty_element[0].value;
646		}
647
648		if ( qty === 0 ) {
649			return true;
650		}
651
652		const product_data = {
653			'name':       dom_productdata.getAttribute( 'data-gtm4wp_product_name' ),
654			'id':         dom_productdata.getAttribute( 'data-gtm4wp_product_id' ),
655			'price':      dom_productdata.getAttribute( 'data-gtm4wp_product_price' ),
656			'category':   dom_productdata.getAttribute( 'data-gtm4wp_product_cat' ),
657			'variant':    dom_productdata.getAttribute( 'data-gtm4wp_product_variant' ),
658			'stocklevel': dom_productdata.getAttribute( 'data-gtm4wp_product_stocklevel' ),
659			'brand':      dom_productdata.getAttribute( 'data-gtm4wp_product_brand' ),
660			'quantity':   qty
661		};
662
663		// fire ga3 version
664		window[ gtm4wp_datalayer_name ].push({
665			'event': 'gtm4wp.removeFromCartEEC',
666			'ecommerce': {
667				'currencyCode': gtm4wp_currency,
668				'remove': {
669					'products': [ product_data ]
670				}
671			}
672		});
673
674		// fire ga4 version
675		window[ gtm4wp_datalayer_name ].push({
676			'event': 'remove_from_cart',
677			'ecommerce': {
678				'currency': gtm4wp_currency,
679				'value': product_data.price * product_data.quantity,
680				'items': [ gtm4wp_map_eec_to_ga4( product_data ) ]
681			}
682		});
683	});
684
685	// track clicks in product lists
686	let productlist_item_selector = '.products li:not(.product-category) a:not(.add_to_cart_button):not(.quick-view-button),'
687		+'.wc-block-grid__products li:not(.product-category) a:not(.add_to_cart_button):not(.quick-view-button),'
688		+'.products>div:not(.product-category) a:not(.add_to_cart_button):not(.quick-view-button),'
689		+'.widget-product-item,'
690		+'.woocommerce-grouped-product-list-item__label a'
691	document.addEventListener( 'click', function( e ) {
692		// do nothing if GTM is blocked for some reason
693		if ( 'undefined' == typeof google_tag_manager ) {
694			return true;
695		}
696
697		const event_target_element = e.target;
698		const matching_link_element = event_target_element.closest( productlist_item_selector );
699
700		if ( !matching_link_element ) {
701			return true;
702		}
703
704		let temp_selector = event_target_element.closest( '.product,.wc-block-grid__product' );
705		let dom_productdata;
706
707		if ( temp_selector ) {
708			dom_productdata = temp_selector.querySelector( '.gtm4wp_productdata' );
709
710		} else {
711			temp_selector = event_target_element.closest( '.products li' );
712
713			if ( temp_selector ) {
714				dom_productdata = temp_selector.querySelector( '.gtm4wp_productdata' );
715
716			} else {
717				temp_selector = event_target_element.closest( '.products>div' );
718
719				if ( temp_selector ) {
720					dom_productdata = temp_selector.querySelector( '.gtm4wp_productdata' );
721
722				} else {
723					temp_selector = event_target_element.closest( '.woocommerce-grouped-product-list-item__label' );
724
725					if ( temp_selector ) {
726						dom_productdata = temp_selector.querySelector( '.gtm4wp_productdata' );
727					} else {
728						dom_productdata = event_target_element;
729					}
730				}
731			}
732		}
733
734		if ( ( 'undefined' == typeof dom_productdata.getAttribute( 'data-gtm4wp_product_id' ) ) || ( '' == dom_productdata.getAttribute( 'data-gtm4wp_product_id' ) ) ) {
735			return true;
736		}
737
738		// only act on links pointing to the product detail page
739		if ( dom_productdata.getAttribute( 'data-gtm4wp_product_url' ) != matching_link_element.getAttribute( 'href' ) ) {
740			return true;
741		}
742
743		const product_data = {
744			'id':         dom_productdata.getAttribute( 'data-gtm4wp_product_id' ),
745			'name':       dom_productdata.getAttribute( 'data-gtm4wp_product_name' ),
746			'price':      dom_productdata.getAttribute( 'data-gtm4wp_product_price' ),
747			'category':   dom_productdata.getAttribute( 'data-gtm4wp_product_cat' ),
748			'stocklevel': dom_productdata.getAttribute( 'data-gtm4wp_product_stocklevel' ),
749			'brand':      dom_productdata.getAttribute( 'data-gtm4wp_product_brand' ),
750			'position':   dom_productdata.getAttribute( 'data-gtm4wp_product_listposition' )
751		};
752
753		for (let i in window.google_tag_manager) {
754			if (i.substring(0,4).toLowerCase() == "gtm-") {
755				window.gtm4wp_first_container_id = i;
756				break;
757			}
758		}
759
760		// do not do anything if GTM was not loaded for any reason
761		if ( "" === window.gtm4wp_first_container_id ) {
762			return true;
763		}
764
765		const ctrl_key_pressed = e.ctrlKey || e.metaKey;
766
767		e.preventDefault();
768		if ( ctrl_key_pressed ) {
769			// we need to open the new tab/page here so that popup blocker of the browser doesn't block our code
770			window.productpage_window = window.open( 'about:blank', '_blank' );
771		}
772
773		// fire ga3 version
774		window[ gtm4wp_datalayer_name ].push({
775			'event': 'gtm4wp.productClickEEC',
776			'ecommerce': {
777				'currencyCode': gtm4wp_currency,
778				'click': {
779					'actionField': {'list': dom_productdata.getAttribute( 'data-gtm4wp_productlist_name' )},
780					'products': [ product_data ]
781				}
782			},
783			'eventCallback': function( container_id ) {
784				if ( "undefined" !== typeof container_id && window.gtm4wp_first_container_id != container_id) {
785					// only call this for the first loaded container
786					return true;
787				}
788
789				// fire ga4 version
790				window[ gtm4wp_datalayer_name ].push({
791					'event': 'select_item',
792					'ecommerce': {
793						'currency': gtm4wp_currency,
794						'items': [ gtm4wp_map_eec_to_ga4( product_data ) ]
795					},
796					'eventCallback': function() {
797						if ( ctrl_key_pressed && productpage_window ) {
798							productpage_window.location.href = dom_productdata.getAttribute( 'data-gtm4wp_product_url' );
799						} else {
800							document.location.href = dom_productdata.getAttribute( 'data-gtm4wp_product_url' );
801						}
802
803					},
804					'eventTimeout': 2000
805				});
806			},
807			'eventTimeout': 2000
808		});
809	});
810
811	// track variable products on their detail pages
812	// currently, we need to use jQuery here since WooCommerce is firing this event using jQuery
813	// that can not be catched using vanilla JS
814	jQuery( document ).on( 'found_variation', function( event, product_variation ) {
815		if ( "undefined" == typeof product_variation ) {
816			// some ither plugins trigger this event without variation data
817			return;
818		}
819
820		if ( (document.readyState === "interactive") && gtm4wp_changedetail_fired_during_pageload ) {
821			// some custom attribute rendering plugins fire this event multiple times during page load
822			return;
823		}
824
825		const product_form       = event.target;
826		const product_variant_id = product_form.querySelector( '[name=variation_id]' ) && product_form.querySelector( '[name=variation_id]' ).value;
827		const product_id         = product_form.querySelector( '[name=gtm4wp_id]' ) && product_form.querySelector( '[name=gtm4wp_id]' ).value;
828		const product_name       = product_form.querySelector( '[name=gtm4wp_name]' ) && product_form.querySelector( '[name=gtm4wp_name]' ).value;
829		const product_sku        = product_form.querySelector( '[name=gtm4wp_sku]' ) && product_form.querySelector( '[name=gtm4wp_sku]' ).value;
830		const product_category   = product_form.querySelector( '[name=gtm4wp_category]' ) && product_form.querySelector( '[name=gtm4wp_category]' ).value;
831		const product_price      = product_form.querySelector( '[name=gtm4wp_price]' ) && product_form.querySelector( '[name=gtm4wp_price]' ).value;
832		const product_stocklevel = product_form.querySelector( '[name=gtm4wp_stocklevel]' ) && product_form.querySelector( '[name=gtm4wp_stocklevel]' ).value;
833		const product_brand      = product_form.querySelector( '[name=gtm4wp_brand]' ) && product_form.querySelector( '[name=gtm4wp_brand]' ).value;
834
835		let current_product_detail_data = {
836			name: product_name,
837			id: 0,
838			price: 0,
839			category: product_category,
840			stocklevel: product_stocklevel,
841			brand: product_brand,
842			variant: ''
843		};
844
845		current_product_detail_data.id = product_variation.variation_id;
846		if ( gtm4wp_use_sku_instead && product_variation.sku && ('' !== product_variation.sku) ) {
847			current_product_detail_data.id = product_variation.sku;
848		}
849		current_product_detail_data.price = product_variation.display_price;
850
851		let product_variation_attribute_values = [];
852		for( let attrib_key in product_variation.attributes ) {
853			product_variation_attribute_values.push( product_variation.attributes[ attrib_key ] );
854		}
855		current_product_detail_data.variant = product_variation_attribute_values.join(',');
856		gtm4wp_last_selected_product_variation = current_product_detail_data;
857
858		// fire ga3 version
859		window[ gtm4wp_datalayer_name ].push({
860			'event': 'gtm4wp.changeDetailViewEEC',
861			'ecommerce': {
862				'currencyCode': gtm4wp_currency,
863				'detail': {
864					'products': [ current_product_detail_data ]
865				}
866			},
867			'ecomm_prodid': gtm4wp_id_prefix + current_product_detail_data.id,
868			'ecomm_pagetype': 'product',
869			'ecomm_totalvalue': current_product_detail_data.price,
870		});
871
872		// fire ga4 version
873		window[ gtm4wp_datalayer_name ].push({
874			'event': 'view_item',
875			'ecommerce': {
876				'currency': gtm4wp_currency,
877				'value': current_product_detail_data.price,
878				'items': [ gtm4wp_map_eec_to_ga4( current_product_detail_data ) ]
879			}
880		});
881
882		if ( document.readyState === "interactive" ) {
883			gtm4wp_changedetail_fired_during_pageload = true;
884		}
885	});
886	jQuery( '.variations select' ).trigger( 'change' );
887
888	// initiate codes in WooCommere Quick View
889	// currently, we need to use jQuery here since WooCommerce Quick View is showing the popup using
890	// jQuery AJAX calls that can not be catched using vanilla JS
891	jQuery( document ).ajaxSuccess( function( event, xhr, settings ) {
892		if(typeof settings !== 'undefined') {
893			if (settings.url.indexOf( 'wc-api=WC_Quick_View' ) > -1 ) {
894				setTimeout( function() {
895
896					const dl_data = document.querySelector('#gtm4wp_quickview_data');
897					if ( dl_data && dl_data.dataset && dl_data.dataset.gtm4wp_datalayer ) {
898						try {
899							const dl_data_obj = JSON.parse( dl_data.dataset.gtm4wp_datalayer );
900							if ( dl_data_obj && window.dataLayer ) {
901								window.dataLayer.push(dl_data_obj);
902							}
903						} catch(e) {
904							console && console.error && console.error( e.message );
905						}
906					}
907
908				}, 500);
909			}
910		}
911	});
912
913	// codes for enhanced ecommerce events on cart page
914	if ( gtm4wp_is_cart ) {
915		document.addEventListener( 'click', function( e ) {
916			let event_target_element = e.target;
917
918			if ( !event_target_element ) {
919				// for some reason event target is not specificed
920				return true;
921			}
922
923			if ( !event_target_element.closest( '[name=update_cart]' ) ) {
924				return true;
925			}
926
927			gtm4wp_handle_cart_qty_change();
928		});
929
930		document.addEventListener( 'keypress', function( e ) {
931			let event_target_element = e.target;
932
933			if ( !event_target_element ) {
934				// for some reason event target is not specificed
935				return true;
936			}
937
938			if ( !event_target_element.closest( '.woocommerce-cart-form input[type=number]' ) ) {
939				return true;
940			}
941
942			gtm4wp_handle_cart_qty_change();
943		});
944	}
945
946	// codes for enhanced ecommerce events on checkout page
947	if ( gtm4wp_is_checkout ) {
948		window.gtm4wp_checkout_step_offset  = window.gtm4wp_checkout_step_offset || 0;
949		window.gtm4wp_checkout_value        = window.gtm4wp_checkout_value || 0;
950		window.gtm4wp_checkout_products     = window.gtm4wp_checkout_products || [];
951		window.gtm4wp_checkout_products_ga4 = window.gtm4wp_checkout_products_ga4 || [];
952
953		// this checkout step is not reported to GA4 as currently there is no option to report in-between custom steps
954		document.addEventListener( 'focusout', function( e ) {
955			let event_target_element = e.target;
956
957			if ( !event_target_element ) {
958				// for some reason event target is not specificed
959				return true;
960			}
961
962			if ( !event_target_element.closest || !event_target_element.closest( 'input[name^=shipping_]:not(input[name^=shipping_method])' ) ) {
963				return true;
964			}
965
966			// do not report checkout step if already reported
967			if ( gtm4wp_checkout_step_fired.indexOf( 'shipping' ) > -1 ) {
968				return;
969			}
970
971			// do not report checkout step if user is traversing through the section without filling in any data
972			if ( event_target_element.value.trim() == '' ) {
973				return;
974			}
975
976			window[ gtm4wp_datalayer_name ].push({
977				'event': 'gtm4wp.checkoutStepEEC',
978				'ecommerce': {
979					'currencyCode': gtm4wp_currency, // ga3 version
980					'checkout': {
981						'actionField': {
982							'step': 2 + window.gtm4wp_checkout_step_offset
983						},
984						'products': window.gtm4wp_checkout_products
985					}
986				}
987			});
988
989			gtm4wp_checkout_step_fired.push( 'shipping' );
990		});
991
992		document.addEventListener( 'change', function( e ) {
993			let event_target_element = e.target;
994
995			if ( !event_target_element ) {
996				// for some reason event target is not specificed
997				return true;
998			}
999
1000			if ( !event_target_element.closest( 'input[name^=shipping_method]' ) ) {
1001				return true;
1002			}
1003
1004			gtm4wp_handle_shipping_method_change();
1005		});
1006
1007		document.addEventListener( 'change', function( e ) {
1008			let event_target_element = e.target;
1009
1010			if ( !event_target_element ) {
1011				// for some reason event target is not specificed
1012				return true;
1013			}
1014
1015			if ( !event_target_element.closest( 'input[name=payment_method]' ) ) {
1016				return true;
1017			}
1018
1019			gtm4wp_handle_payment_method_change();
1020		});
1021
1022		document.addEventListener( 'submit', function( e ) {
1023			let event_target_element = e.target;
1024
1025			if ( !event_target_element ) {
1026				// for some reason event target is not specificed
1027				return true;
1028			}
1029
1030			if ( !event_target_element.closest( 'form[name=checkout]' ) ) {
1031				return true;
1032			}
1033
1034			if ( gtm4wp_checkout_step_fired.indexOf( 'shipping_method' ) == -1 ) {
1035				// shipping methods are not visible if only one is available
1036				// and if the user has already a pre-selected method, no click event will fire to report the checkout step
1037				gtm4wp_handle_shipping_method_change();
1038			}
1039
1040			if ( gtm4wp_checkout_step_fired.indexOf( 'payment_method' ) == -1 ) {
1041				// if the user has already a pre-selected method, no click event will fire to report the checkout step
1042				gtm4wp_handle_payment_method_change();
1043			}
1044
1045			let shipping_el = document.querySelector( 'input[name^=shipping_method]:checked' );
1046			if ( !shipping_el ) {
1047				shipping_el = document.querySelector( 'input[name^=shipping_method]' ); // select the first input element
1048			}
1049			if ( shipping_el ) {
1050				window[ gtm4wp_datalayer_name ].push({
1051					'event': 'gtm4wp.checkoutOptionEEC',
1052					'ecommerce': {
1053						'checkout_option': {
1054							'actionField': {
1055								'step': 3 + window.gtm4wp_checkout_step_offset + gtm4wp_shipping_payment_method_step_offset,
1056								'option': 'Shipping: ' + shipping_el.value
1057							}
1058						}
1059					}
1060				});
1061			}
1062
1063			let payment_el = document.querySelector( '.payment_methods input:checked' );
1064			if ( !payment_el ) {
1065				payment_el = document.querySelector( 'input[name^=payment_method]' ); // select the first input element
1066			}
1067			if ( payment_el ) {
1068				window[ gtm4wp_datalayer_name ].push({
1069					'event': 'gtm4wp.checkoutOptionEEC',
1070					'ecommerce': {
1071						'checkout_option': {
1072							'actionField': {
1073								'step': 4 + window.gtm4wp_checkout_step_offset + gtm4wp_shipping_payment_method_step_offset,
1074								'option': 'Payment: ' + payment_el.value
1075							}
1076						}
1077					}
1078				});
1079			}
1080		});
1081	}
1082
1083	// codes for Google Ads dynamic remarketing
1084	// this part of the code is deprecated and will be removed in a later version
1085	// therefore jQuery usage will be not rewritten
1086	// turn of the deprecated Google Ads remarketing feature and this code will not execute
1087	if ( window.gtm4wp_remarketing&& !gtm4wp_is_cart && !gtm4wp_is_checkout ) {
1088		if ( jQuery( '.gtm4wp_productdata' ).length > 0 ) {
1089			for( var i=0; i<window[ gtm4wp_datalayer_name ].length; i++ ) {
1090				if ( window[ gtm4wp_datalayer_name ][ i ][ 'ecomm_prodid' ] ) {
1091					break;
1092				}
1093			}
1094
1095			if ( i == window[ gtm4wp_datalayer_name ].length ) {
1096				// no existing dyn remarketing data found in the datalayer
1097				i = 0;
1098				window[ gtm4wp_datalayer_name ][ i ][ 'ecomm_prodid' ] = [];
1099			}
1100
1101			if ( 'undefined' !== typeof window[ gtm4wp_datalayer_name ][ i ][ 'ecomm_prodid' ].push ) {
1102				var productdata;
1103				jQuery( '.gtm4wp_productdata' ).each( function() {
1104					productdata = jQuery( this );
1105
1106					window[ gtm4wp_datalayer_name ][ i ][ 'ecomm_prodid' ].push( gtm4wp_id_prefix + productdata.data( 'gtm4wp_product_id' ) );
1107				});
1108			}
1109		}
1110	}
1111
1112	// loop through datalayer and fire GA4 version of EEC events
1113	if ( window[ gtm4wp_datalayer_name ] && window[ gtm4wp_datalayer_name ].forEach ) {
1114		window[ gtm4wp_datalayer_name ].forEach(function( item ) {
1115
1116			if ( item && item.ecommerce && item.ecommerce.detail ) {
1117				window[ gtm4wp_datalayer_name ].push({
1118					'event': 'view_item',
1119					'ecommerce': {
1120						'currency': gtm4wp_currency,
1121						'value': item.ecommerce.detail.products[0].price,
1122						'items': [ gtm4wp_map_eec_to_ga4( item.ecommerce.detail.products[0] ) ]
1123					}
1124				});
1125			}
1126
1127			if ( item && item.ecommerce && ( item.ecommerce.cart || (item.ecommerce.checkout && gtm4wp_is_cart) ) ) {
1128				let source_products = item.ecommerce.cart || item.ecommerce.checkout.products;
1129				let ga4_products = [];
1130				let sum_value = 0;
1131
1132				source_products.forEach(function( product ) {
1133					ga4_products.push( gtm4wp_map_eec_to_ga4( product ) );
1134					sum_value += product.price * product.quantity;
1135				});
1136
1137				window[ gtm4wp_datalayer_name ].push({
1138					'event': 'view_cart',
1139					'ecommerce': {
1140						'currency': gtm4wp_currency,
1141						'value': sum_value.toFixed(2),
1142						'items': ga4_products
1143					}
1144				});
1145			}
1146
1147			if ( item && item.ecommerce && item.ecommerce.checkout && !gtm4wp_is_cart ) {
1148				let ga4_products = [];
1149				let sum_value = 0;
1150
1151				item.ecommerce.checkout.products.forEach(function( product ) {
1152					ga4_products.push( gtm4wp_map_eec_to_ga4( product ) );
1153					sum_value += product.price * product.quantity;
1154				});
1155
1156				window[ gtm4wp_datalayer_name ].push({
1157					'event': 'begin_checkout',
1158					'ecommerce': {
1159						'currency': gtm4wp_currency,
1160						'value': sum_value,
1161						'items': ga4_products
1162					}
1163				});
1164			}
1165
1166			// present if product is readded into cart just after removel
1167			if ( item && item.ecommerce && item.ecommerce.add ) {
1168				let ga4_products = [];
1169				let sum_value = 0;
1170
1171				item.ecommerce.add.products.forEach(function( product ) {
1172					ga4_products.push( gtm4wp_map_eec_to_ga4( product ) );
1173					sum_value += product.price * product.quantity;
1174				});
1175
1176				window[ gtm4wp_datalayer_name ].push({
1177					'event': 'add_to_cart',
1178					'ecommerce': {
1179						'currency': gtm4wp_currency,
1180						'value': sum_value,
1181						'items': ga4_products
1182					}
1183				});
1184			}
1185
1186			if ( item && item.ecommerce && item.ecommerce.purchase ) {
1187				let ga4_products = [];
1188				item.ecommerce.purchase.products.forEach(function( product ) {
1189					ga4_products.push( gtm4wp_map_eec_to_ga4( product ) );
1190				});
1191
1192				window[ gtm4wp_datalayer_name ].push({
1193					'event': 'purchase',
1194					'ecommerce': {
1195						'currency': gtm4wp_currency,
1196						'items': ga4_products,
1197						'transaction_id': item.ecommerce.purchase.actionField.id,
1198						'affiliation': item.ecommerce.purchase.actionField.affiliation,
1199						'value': item.ecommerce.purchase.actionField.revenue,
1200						'tax': item.ecommerce.purchase.actionField.tax,
1201						'shipping': item.ecommerce.purchase.actionField.shipping,
1202						'coupon': item.ecommerce.purchase.actionField.coupon
1203					}
1204				});
1205			}
1206		});
1207	}
1208};
1209
1210function gtm4wp_page_loading_completed() {
1211	document.removeEventListener( "DOMContentLoaded", gtm4wp_page_loading_completed );
1212	window.removeEventListener( "load", gtm4wp_page_loading_completed );
1213	gtm4wp_process_woocommerce_pages();
1214}
1215
1216// code and idea borrowed from jQuery:
1217// https://github.com/jquery/jquery/blob/main/src/core/ready.js
1218if ( document.readyState !== "loading" ) {
1219	window.setTimeout( gtm4wp_process_woocommerce_pages );
1220} else {
1221	document.addEventListener( "DOMContentLoaded", gtm4wp_page_loading_completed );
1222	window.addEventListener( "load", gtm4wp_page_loading_completed );
1223}

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.