Changeset 3342931
- Timestamp:
- 08/11/2025 02:06:50 PM (7 months ago)
- Location:
- metrion
- Files:
-
- 53 added
- 15 edited
-
tags/1.5.5 (added)
-
tags/1.5.5/assets (added)
-
tags/1.5.5/assets/icon-128x128.png (added)
-
tags/1.5.5/assets/icon-256x256.png (added)
-
tags/1.5.5/css (added)
-
tags/1.5.5/css/settings.css (added)
-
tags/1.5.5/includes (added)
-
tags/1.5.5/includes/api_endpoints.php (added)
-
tags/1.5.5/includes/event_capture.php (added)
-
tags/1.5.5/includes/initial.php (added)
-
tags/1.5.5/includes/js_bundler.php (added)
-
tags/1.5.5/js (added)
-
tags/1.5.5/js/bundles (added)
-
tags/1.5.5/js/cmp (added)
-
tags/1.5.5/js/cmp/cmplz (added)
-
tags/1.5.5/js/cmp/cmplz/logic.js (added)
-
tags/1.5.5/js/cmp/cookiebot (added)
-
tags/1.5.5/js/cmp/cookiebot/logic.js (added)
-
tags/1.5.5/js/cmp/cookiefirst (added)
-
tags/1.5.5/js/cmp/cookiefirst/logic.js (added)
-
tags/1.5.5/js/cmp/cookieyes (added)
-
tags/1.5.5/js/cmp/cookieyes/logic.js (added)
-
tags/1.5.5/js/cmp/moove_gdpr (added)
-
tags/1.5.5/js/cmp/moove_gdpr/logic.js (added)
-
tags/1.5.5/js/cmp/none (added)
-
tags/1.5.5/js/cmp/none/logic.js (added)
-
tags/1.5.5/js/cmp/onetrust (added)
-
tags/1.5.5/js/cmp/onetrust/logic.js (added)
-
tags/1.5.5/js/core (added)
-
tags/1.5.5/js/core/events.js (added)
-
tags/1.5.5/js/core/initialisation_sequence.js (added)
-
tags/1.5.5/js/detect (added)
-
tags/1.5.5/js/detect/detect.js (added)
-
tags/1.5.5/js/elementor (added)
-
tags/1.5.5/js/elementor/form_events.js (added)
-
tags/1.5.5/js/google_ads (added)
-
tags/1.5.5/js/google_ads/consent_mode.js (added)
-
tags/1.5.5/js/google_ads/events.js (added)
-
tags/1.5.5/js/meta (added)
-
tags/1.5.5/js/meta/events.js (added)
-
tags/1.5.5/js/microsoft_ads (added)
-
tags/1.5.5/js/microsoft_ads/consent_mode.js (added)
-
tags/1.5.5/js/microsoft_ads/events.js (added)
-
tags/1.5.5/js/settings (added)
-
tags/1.5.5/js/settings/settings.js (added)
-
tags/1.5.5/js/woo (added)
-
tags/1.5.5/js/woo/other_events.js (added)
-
tags/1.5.5/js/woo/purchase_event.js (added)
-
tags/1.5.5/main.php (added)
-
tags/1.5.5/readme.txt (added)
-
tags/1.5.5/uninstall.php (added)
-
tags/1.5.5/views (added)
-
tags/1.5.5/views/settings.php (added)
-
trunk/includes/event_capture.php (modified) (15 diffs)
-
trunk/includes/initial.php (modified) (9 diffs)
-
trunk/includes/js_bundler.php (modified) (3 diffs)
-
trunk/js/cmp/cmplz/logic.js (modified) (2 diffs)
-
trunk/js/core/events.js (modified) (27 diffs)
-
trunk/js/detect/detect.js (modified) (1 diff)
-
trunk/js/google_ads/events.js (modified) (12 diffs)
-
trunk/js/meta/events.js (modified) (6 diffs)
-
trunk/js/microsoft_ads/events.js (modified) (2 diffs)
-
trunk/js/settings/settings.js (modified) (1 diff)
-
trunk/js/woo/other_events.js (modified) (3 diffs)
-
trunk/js/woo/purchase_event.js (modified) (2 diffs)
-
trunk/main.php (modified) (4 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/views/settings.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
metrion/trunk/includes/event_capture.php
r3300778 r3342931 15 15 } 16 16 17 add_action('wp_head', function() { 18 if (!is_wc_endpoint_url('order-received')) return; 19 20 $order_id = absint(get_query_var('order-received')); 21 if (!$order_id) return; 22 23 // Always print the echo script for debug 24 metrion_echo_webhook_purchase($order_id, 'wp_head_force_echo'); 25 }); 26 17 27 // Add tracking function to both hooks with appropriate source information 18 28 add_action('woocommerce_checkout_order_processed', function($order_id) { … … 23 33 metrion_order_tracking($order_id, 'woocommerce_thankyou'); 24 34 }, 10, 1); 35 36 37 /** 38 * Returns an array that can be used to sanitize a <script> block using wp_kses(). 39 * 40 * @return array 41 */ 42 function metrion_sanitize_script_block_rules() { 43 return array( 44 'script' => array( 45 'data-cfasync' => array(), 46 'data-pagespeed-no-defer' => array(), 47 'data-cookieconsent' => array(), 48 'type' => array(), 49 'nonce' => array(), 50 ), 51 ); 52 } 53 54 function metrion_generate_script_opening_tag() { 55 $has_html5_support = current_theme_supports( 'html5' ); 56 $add_cookiebot_ignore = false; 57 $csp_nonce = apply_filters( GET_METRION_WPFILTER_CSP_NONCE, '' ); 58 return '<script data-cfasync="false" data-pagespeed-no-defer' . ( $has_html5_support ? '' : ' type="text/javascript"' ) . ( $add_cookiebot_ignore ? ' data-cookieconsent="ignore"' : '' ) . ( $csp_nonce ? ' nonce="' . esc_attr( $csp_nonce ) . '"' : '' ) . '>'; 59 } 60 61 function metrion_echo_webhook_purchase($order_id, $triggered_by_hook = '') { 62 // Get the base order object 63 $order = wc_get_order($order_id); 64 if ( ! $order instanceof WC_Order ) { 65 return; 66 } 67 // conversion details 68 $google_ads_tag_id = get_option('metrion_google_ads_tag_id', ''); 69 $google_ads_conversion_label = get_option('metrion_google_ads_purchase_enhanced_conversion_label', ''); 70 71 $order_total = $order->get_total(); 72 $currency = $order->get_currency(); 73 $transaction_id = $order->get_id(); 74 75 $metrion_consent_cookie_value = metrion_get_cookie_value('metrion_consent_cookie_name', 'mtrn_consent'); 76 $allow_marketing = isset($metrion_consent_cookie_value['allow_marketing']) && $metrion_consent_cookie_value['allow_marketing'] === "1"; 77 78 $script_tag = "" . metrion_generate_script_opening_tag() . " 79 document.addEventListener('DOMContentLoaded', function() { 80 window.metrion = window.metrion || {}; 81 window.metrion_api = window.metrion_api || {}; 82 window.metrion.google_ads = window.metrion.google_ads || {}; 83 window.metrion.google_ads.purchase_triggered = window.metrion.google_ads.purchase_triggered || false; 84 if(window.metrion.google_ads.purchase_triggered === false){ 85 window.metrion.google_ads.purchase_echo_loaded = true; 86 window.metrion.google_ads.purchase_echo_triggered = false; 87 window.metrion.google_ads.google_ads_purchase_enhanced_conversion_label = '" . esc_js($google_ads_conversion_label) . "'; 88 window.metrion.google_ads.google_ads_tag_id = '" . esc_js($google_ads_tag_id ) . "'; 89 window.metrion.google_ads.order_id = '" . esc_js($transaction_id) . "'; 90 // Initialize the Google Ads tracking script 91 window.metrion.google_ads.echo_direct = function(){ 92 // Conditionally start with the handling 93 function start_google_ads_event_handling(){ 94 window.gtag('event', 'conversion', { 95 'send_to': (window.metrion.google_ads.google_ads_tag_id + '/' + window.metrion.google_ads.google_ads_purchase_enhanced_conversion_label), 96 'value': " . esc_js($order_total) . ", 97 'currency': '" . esc_js($currency) . "', 98 'transaction_id': '" . esc_js($transaction_id) . "' 99 }); 100 window.metrion.google_ads.purchase_triggered = true; 101 window.metrion.google_ads.purchase_echo_triggered = true; 102 } 103 104 if(typeof window.metrion === 'undefined' && typeof window.metrion_api === 'undefined'){ 105 window.metrion.google_ads.metrion_not_available = true; 106 } 107 else{ 108 // GOOGLE ADS CONTEXT CHECKS 109 // First Check if recent relevant click-ids are stored 110 var google_ads_click_id = undefined; 111 try{ 112 //Parse the cookie if it exists 113 var parsed_click_ids = JSON.parse(decodeURIComponent(window.metrion.helpers.get_cookie_value(window.metrion_api.click_ids_cookie_name))); 114 if(parsed_click_ids !== null && typeof parsed_click_ids.gclid !== 'undefined'){ 115 google_ads_click_id = parsed_click_ids.gclid; 116 } 117 }catch(e){}; 118 119 // If block dectection is not enabled set the value to undefined to remove the variable from the conversion 120 var block_detected = '0'; 121 122 try{ 123 //Parse the cookie if it exists 124 var parsed_consent = JSON.parse(decodeURIComponent(window.metrion.helpers.get_cookie_value(window.metrion_api.consent_cookie_name))); 125 if(parsed_consent !== null && typeof parsed_consent.b !== 'undefined'){ 126 block_detected = parsed_consent.b; 127 } 128 }catch(e){}; 129 130 // Allways send enhanced conversion event for deduplication 131 // If this event does not exist, this gtag script has failed. 132 // If this event contains a blocking intent (1), don't deduplicate for untagged conversions 133 window.metrion.helpers.log_debug('Google Ads conversion send through echo', 'log'); 134 window.metrion.send_event('google_ads_gtag_purchase_triggered', { 135 'send_to': (window.metrion_api.google_ads_tag_id + '/' + window.metrion_api.google_ads_purchase_enhanced_conversion_label), 136 'value': " . esc_js($order_total) . ", 137 'currency': '" . esc_js($currency) . "', 138 'transaction_id': '" . esc_js($transaction_id) . "', 139 'gclid': google_ads_click_id, 140 'enable_detection': window.metrion_api.enable_detection, 141 'b': block_detected, 142 'trigger_type': 'front-end', 143 'trigger_mechanism': 'echo', 144 'non_interaction': '1' 145 }, {}); 146 } 147 148 if(typeof window.gtag === 'undefined'){ 149 // Pre-define before loading gtag.js 150 window.dataLayer = window.dataLayer || []; 151 window.gtag = window.gtag || function(){ dataLayer.push(arguments); }; 152 153 // Dynamically and Async loading of gtag script 154 var gtag_script = document.createElement('script'); 155 gtag_script.async = true; 156 gtag_script.src = 'https://www.googletagmanager.com/gtag/js?id=' + window.metrion_api.google_ads_tag_id; 157 document.body.appendChild(gtag_script); 158 159 // Onload just initializes config and conversion 160 gtag_script.onload = function() { 161 window.gtag('js', new Date()); 162 window.gtag('config', window.metrion_api.google_ads_tag_id); 163 start_google_ads_event_handling(); 164 }; 165 } 166 else{ 167 window.gtag('js', new Date()); 168 window.gtag('config', (window.metrion.google_ads.google_ads_tag_id)); 169 start_google_ads_event_handling(); 170 } 171 }; 172 window.metrion.google_ads.echo_direct(); 173 } 174 175 }); 176 </script>"; 177 echo htmlspecialchars_decode( //phpcs:ignore 178 wp_kses( 179 $script_tag, 180 metrion_sanitize_script_block_rules() 181 ) 182 ); 183 } 184 25 185 26 186 function metrion_woocommerce_webhook_purchase($order_id, $triggered_by_hook = '') { … … 167 327 $meta_fbc = isset($_COOKIE['_fbc']) ? sanitize_text_field(wp_unslash($_COOKIE['_fbc'])) : ''; 168 328 329 // Metrion click-id values 330 $click_id_cookie_name = get_option('metrion_click_ids_cookie_name', 'mtrn_cids'); 331 $click_ids_json_string = '{}'; // default fallback 332 333 if ( isset($_COOKIE[$click_id_cookie_name]) ) { 334 $raw_cookie = wp_unslash( $_COOKIE[$click_id_cookie_name] ); 335 $decoded_cookie_json = rawurldecode( $raw_cookie ); 336 337 if ( $decoded_cookie_json && is_string($decoded_cookie_json) ) { 338 $click_ids_array = json_decode( $decoded_cookie_json, true ); 339 340 if ( json_last_error() === JSON_ERROR_NONE && is_array($click_ids_array) ) { 341 $reencoded = json_encode( $click_ids_array ); 342 if ( $reencoded !== false ) { 343 $click_ids_json_string = $reencoded; 344 } 345 } 346 } 347 } 348 349 // Session number and session start time 350 $metrion_session_cookie_name = get_option('metrion_session_cookie_name', 'mtrn_sid'); 351 $metrion_session_cookie_value = metrion_get_cookie_value($metrion_session_cookie_name, 'mtrn_sid'); 352 $metrion_session_cookie_values = explode('--', $metrion_session_cookie_value); 353 $metrion_session_start_time = isset($metrion_session_cookie_values[2]) ? $metrion_session_cookie_values[2] : null; 354 355 // The second value of the front-end user cookie contains the session number 356 $metrion_user_cookie_name = get_option('metrion_user_cookie_name', 'mtrn_uid') . "_js"; 357 $metrion_user_cookie_value = metrion_get_cookie_value($metrion_user_cookie_name, 'mtrn_uid_js'); 358 $metrion_user_cookie_values = explode('--', $metrion_user_cookie_value); 359 $metrion_session_number = isset($metrion_user_cookie_values[1]) ? $metrion_user_cookie_values[1] : null; 360 361 169 362 // VAT/TAX calculations 170 363 $order_total = floatval($order->get_total()); … … 173 366 $shipping_tax = floatval($order->get_shipping_tax()); 174 367 $shipping_incl_tax = $shipping_excl_tax + $shipping_tax; 368 369 370 // Initialize purchase data 371 $purchase_items = []; 372 373 // Get applied coupons (if any) 374 $applied_coupons = $order->get_coupon_codes(); 375 foreach ($applied_coupons as $coupon_code) { 376 $purchase_data['coupons'][] = $coupon_code; 377 } 378 379 // Get order items 380 foreach ($order->get_items() as $item) { 381 $product = $item->get_product(); 382 if (!$product) { 383 continue; 384 } 385 386 // Get product categories 387 $categories = get_the_terms($product->get_id(), 'product_cat'); 388 $nested_categories = array_map(fn($category) => $category->name, $categories ?: []); 389 390 // Add detailed item data 391 $purchase_items[] = [ 392 'id' => strval($product->get_id()), 393 'name' => strval($product->get_name()), 394 'price' => strval($product->get_price()), 395 'regular_price' => strval($product->get_regular_price()), 396 'sku' => strval($product->get_sku()), 397 'url' => strval(get_permalink($product->get_id())), 398 'quantity' => strval($item->get_quantity()), 399 'currency' => strval($order->get_currency()), 400 'category_1' => isset($nested_categories[0]) ? strval($nested_categories[0]) : '', 401 'category_2' => isset($nested_categories[1]) ? strval($nested_categories[1]) : '', 402 'category_3' => isset($nested_categories[2]) ? strval($nested_categories[2]) : '', 403 'category_4' => isset($nested_categories[3]) ? strval($nested_categories[3]) : '' 404 ]; 405 } 175 406 176 407 return array( … … 200 431 'meta_fbp' => $meta_fbp, 201 432 'meta_fbc' => $meta_fbc, 433 'items' => wp_json_encode($purchase_items), 434 'coupons' => $applied_coupons, 435 'click_ids' => $click_ids_json_string, 436 'session_number' => $metrion_session_number, 437 'session_start_time' => $metrion_session_start_time 202 438 ); 203 439 } … … 308 544 // Add detailed item data 309 545 $purchase_data['items'][] = [ 310 'id' => $product->get_id(),311 'name' => $product->get_name(),312 'price' => $product->get_price(),313 'regular_price' => $product->get_regular_price(),314 'sku' => $product->get_sku(),546 'id' => strval($product->get_id()), 547 'name' => strval($product->get_name()), 548 'price' => strval($product->get_price()), 549 'regular_price' => strval($product->get_regular_price()), 550 'sku' => strval($product->get_sku()), 315 551 'url' => get_permalink($product->get_id()), 316 'quantity' => $item->get_quantity(),552 'quantity' => strval($item->get_quantity()), 317 553 'currency' => $order->get_currency(), 318 'category_1' => $nested_categories[0] ??'',319 'category_2' => $nested_categories[1] ??'',320 'category_3' => $nested_categories[2] ??'',321 'category_4' => $nested_categories[3] ?? '',554 'category_1' => isset($nested_categories[0]) ? strval($nested_categories[0]) : '', 555 'category_2' => isset($nested_categories[1]) ? strval($nested_categories[1]) : '', 556 'category_3' => isset($nested_categories[2]) ? strval($nested_categories[2]) : '', 557 'category_4' => isset($nested_categories[3]) ? strval($nested_categories[3]) : '' 322 558 ]; 323 559 } 324 560 325 // Google Ads Enhanced Purchase Conversion Tracking326 if (327 get_option('metrion_enable_google_ads_enhanced_conversions', false) &&328 get_option('metrion_allow_marketing', true) &&329 get_option('metrion_allow_pii', true) &&330 get_option('metrion_google_enable_tracking', false)331 ) {332 $purchase_data['google_ads'] = [333 'conversion_id' => get_option('metrion_google_ads_tag_id', ''),334 'conversion_label' => get_option('metrion_google_ads_purchase_enhanced_conversion_label', ''),335 'conversion_account_id' => get_option('metrion_google_ads_account_id', ''),336 'enforce_google_consent_mode' => get_option('metrion_enforce_google_consent_mode', 0),337 ];338 }339 340 561 // Get the file modification time of this script for cache busting 341 $script_version = file_exists(__FILE__) ? filemtime(__FILE__) : '1.1.0';562 $script_version = file_exists(__FILE__) ? filemtime(__FILE__) : GLOBAL_METRION_PLUGIN_VERSION; 342 563 343 564 // Register a dummy script to ensure script execution … … 354 575 } 355 576 356 357 358 577 $purchase_only_tracking = get_option('metrion_purchase_only_tracking', 1); 359 360 578 361 579 // Only trigger in non purchase-only mode … … 440 658 if($is_loop_item){ 441 659 $product_data = [ 442 'id' => $product->get_id(),443 'name' => $product->get_name(),444 'price' => $product->get_price(),445 'regular_price' => $product->get_regular_price(),446 'sku' => $product->get_sku(),447 'url' => get_permalink($product->get_id()),448 'category_1' => isset($nested_categories[0]) ? $nested_categories[0] : '',449 'category_2' => isset($nested_categories[1]) ? $nested_categories[1] : '',450 'category_3' => isset($nested_categories[2]) ? $nested_categories[2] : '',451 'category_4' => isset($nested_categories[3]) ? $nested_categories[3] : '',452 'type' => $product->get_type(),453 'currency' => $currency660 'id' => strval($product->get_id()), 661 'name' => strval($product->get_name()), 662 'price' => strval($product->get_price()), 663 'regular_price' => strval($product->get_regular_price()), 664 'sku' => strval($product->get_sku()), 665 'url' => get_permalink($product->get_id()), 666 'category_1' => isset($nested_categories[0]) ? $nested_categories[0] : '', 667 'category_2' => isset($nested_categories[1]) ? $nested_categories[1] : '', 668 'category_3' => isset($nested_categories[2]) ? $nested_categories[2] : '', 669 'category_4' => isset($nested_categories[3]) ? $nested_categories[3] : '', 670 'type' => strval($product->get_type()), 671 'currency' => $currency 454 672 ]; 455 673 $metrion_loop_items[] = $product_data; … … 458 676 // Output the metrion_item_data span 459 677 echo '<span class="' . esc_attr($class) . '" 460 data-item_id="' . esc_attr( $product->get_id()) . '"461 data-item_name="' . esc_attr( $product->get_name()) . '"462 data-item_price="' . esc_attr( $product->get_price()) . '"463 data-item_regular_price="' . esc_attr( $product->get_regular_price()) . '"464 data-item_sku="' . esc_attr( $product->get_sku()) . '"678 data-item_id="' . esc_attr(strval($product->get_id())) . '" 679 data-item_name="' . esc_attr(strval($product->get_name())) . '" 680 data-item_price="' . esc_attr(strval($product->get_price())) . '" 681 data-item_regular_price="' . esc_attr(strval($product->get_regular_price())) . '" 682 data-item_sku="' . esc_attr(strval($product->get_sku())) . '" 465 683 data-item_url="' . esc_url(get_permalink($product->get_id())) . '" 466 684 data-item_category_1="' . esc_attr(isset($nested_categories[0]) ? $nested_categories[0] : '') . '" … … 517 735 518 736 // Define a script version based on file modification time to prevent caching issues 519 $script_version = file_exists(__FILE__) ? filemtime(__FILE__) : '1.0.0';737 $script_version = file_exists(__FILE__) ? filemtime(__FILE__) : GLOBAL_METRION_PLUGIN_VERSION; 520 738 521 739 // Register a dummy script to attach inline localized data … … 556 774 // If the cart is not empty, process cart items 557 775 if (!empty($cart)) { 558 foreach ($cart as $cart_item) { 776 foreach ($cart as $cart_item) { 559 777 $product = $cart_item['data']; 560 778 … … 570 788 // Add item data to the checkout items array 571 789 $checkout_items[] = [ 572 'id' => $product->get_id(),573 'name' => $product->get_name(),574 'price' => $product->get_price(),575 'regular_price' => $product->get_regular_price(),576 'sku' => $product->get_sku(),577 'url' => get_permalink($product->get_id()),578 'quantity' => $cart_item['quantity'],790 'id' => strval($product->get_id()), 791 'name' => strval($product->get_name()), 792 'price' => strval($product->get_price()), 793 'regular_price' => strval($product->get_regular_price()), 794 'sku' => strval($product->get_sku()), 795 'url' => strval(get_permalink($product->get_id())), 796 'quantity' => strval($cart_item['quantity']), 579 797 'currency' => get_woocommerce_currency(), 580 'category_1' => $nested_categories[0] ??'',581 'category_2' => $nested_categories[1] ??'',582 'category_3' => $nested_categories[2] ??'',583 'category_4' => $nested_categories[3] ?? '',798 'category_1' => isset($nested_categories[0]) ? strval($nested_categories[0]) : '', 799 'category_2' => isset($nested_categories[1]) ? strval($nested_categories[1]) : '', 800 'category_3' => isset($nested_categories[2]) ? strval($nested_categories[2]) : '', 801 'category_4' => isset($nested_categories[3]) ? strval($nested_categories[3]) : '' 584 802 ]; 585 803 } … … 587 805 588 806 // Get the file modification time of this script 589 $script_version = file_exists(__FILE__) ? filemtime(__FILE__) : '1.0.0';807 $script_version = file_exists(__FILE__) ? filemtime(__FILE__) : GLOBAL_METRION_PLUGIN_VERSION; 590 808 591 809 // Register a dummy script to ensure script execution … … 634 852 // Add item data to the basket items array 635 853 $basket_items[] = [ 636 'id' => $product->get_id(),637 'name' => $product->get_name(),638 'price' => $product->get_price(),639 'regular_price' => $product->get_regular_price(),640 'sku' => $product->get_sku(),854 'id' => strval($product->get_id()), 855 'name' => strval($product->get_name()), 856 'price' => strval($product->get_price()), 857 'regular_price' => strval($product->get_regular_price()), 858 'sku' => strval($product->get_sku()), 641 859 'url' => get_permalink($product->get_id()), 642 'quantity' => $cart_item['quantity'],860 'quantity' => strval($cart_item['quantity']), 643 861 'currency' => get_woocommerce_currency(), 644 'category_1' => $nested_categories[0] ??'',645 'category_2' => $nested_categories[1] ??'',646 'category_3' => $nested_categories[2] ??'',647 'category_4' => $nested_categories[3] ?? '',862 'category_1' => isset($nested_categories[0]) ? strval($nested_categories[0]) : '', 863 'category_2' => isset($nested_categories[1]) ? strval($nested_categories[1]) : '', 864 'category_3' => isset($nested_categories[2]) ? strval($nested_categories[2]) : '', 865 'category_4' => isset($nested_categories[3]) ? strval($nested_categories[3]) : '' 648 866 ]; 649 867 } … … 651 869 652 870 // Get the file modification time of this script for cache busting 653 $script_version = file_exists(__FILE__) ? filemtime(__FILE__) : '1.0.0';871 $script_version = file_exists(__FILE__) ? filemtime(__FILE__) : GLOBAL_METRION_PLUGIN_VERSION; 654 872 655 873 // Register a dummy script to ensure script execution -
metrion/trunk/includes/initial.php
r3300778 r3342931 2 2 3 3 if ( ! defined('ABSPATH') ) exit; // Exit if accessed directly 4 5 define( 'GET_METRION_WPFILTER_CSP_NONCE', 'get_metrion_csp_nonce' ); 4 6 5 7 // 1. ENDPOINT REGISTRATION AND HANDLING … … 79 81 'allow_cookie_placement_before_explicit_consent' => get_option('metrion_allow_cookie_placement_before_explicit_consent', 0), 80 82 81 // Google settings83 // Google Ads settings 82 84 'google_enable_tracking' => get_option('metrion_google_enable_tracking', 0), 83 85 'google_enforce_consent_mode' => get_option('metrion_enforce_google_consent_mode', 0), … … 94 96 'meta_test_event_code' => get_option('metrion_meta_test_event_code', ''), 95 97 98 // Elementor settings 96 99 'elementor_form_tracking' => get_option('metrion_enable_elementor_form_tracking', 0), 97 100 'elementor_excluded_forms' => $excluded_forms, 101 102 // Google Analytics settings 103 'google_analytics_enable_tracking' => get_option('metrion_google_analytics_enable_tracking', 0), 104 'google_analytics_measurement_id' => get_option('metrion_google_analytics_measurement_id', ''), 105 'google_analytcs_api_key' => get_option('metrion_google_analytcs_api_key', '') 98 106 ]; 99 107 } … … 251 259 ? sanitize_text_field( wp_unslash( $_COOKIE['_fbc'] ) ) 252 260 : ''; 261 $mapped_data['event_body']['_gcl_aw'] = isset($_COOKIE['_gcl_aw']) 262 ? sanitize_text_field( wp_unslash( $_COOKIE['_gcl_aw'] ) ) 263 : ''; 264 $mapped_data['event_body']['_gcl_dc'] = isset($_COOKIE['_gcl_dc']) 265 ? sanitize_text_field( wp_unslash( $_COOKIE['_gcl_dc'] ) ) 266 : ''; 267 $mapped_data['event_body']['_uetmsclkid'] = isset($_COOKIE['_uetmsclkid']) 268 ? sanitize_text_field( wp_unslash( $_COOKIE['_uetmsclkid'] ) ) 269 : ''; 253 270 $mapped_data['event_body']['client_ip'] = metrion_get_user_ip(); // Assumed to be sanitized already 254 271 $mapped_data['event_body']['user_agent'] = isset($_SERVER['HTTP_USER_AGENT']) 255 272 ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) 256 273 : 'Unknown User-Agent'; 274 275 // Metrion click-id values 276 $click_id_cookie_name = $options['click_ids_cookie_name']; 277 $click_ids_json_string = '{}'; // default fallback 278 279 if ( isset($_COOKIE[$click_id_cookie_name]) ) { 280 $raw_cookie = wp_unslash( $_COOKIE[$click_id_cookie_name] ); 281 $decoded_cookie_json = rawurldecode( $raw_cookie ); 282 283 if ( $decoded_cookie_json && is_string($decoded_cookie_json) ) { 284 $click_ids_array = json_decode( $decoded_cookie_json, true ); 285 286 if ( json_last_error() === JSON_ERROR_NONE && is_array($click_ids_array) ) { 287 $reencoded = json_encode( $click_ids_array ); 288 if ( $reencoded !== false ) { 289 $click_ids_json_string = $reencoded; 290 } 291 } 292 } 293 } 294 $mapped_data['event_body']['click_ids'] = $click_ids_json_string; 257 295 258 296 // Enforce consent … … 277 315 unset($mapped_data['event_body']['meta_fbp']); 278 316 unset($mapped_data['event_body']['meta_fbc']); 317 // Strip click id object 318 unset($mapped_data['event_body']['click_ids']); 279 319 } 280 320 … … 410 450 $expiration_timestamp = (time() + 86400 * $cookie_expiration) * 1000; 411 451 412 metrion_set_cookie("{$cookie_name}_js", $uuid, $cookie_expiration, false, false); 413 metrion_set_cookie($cookie_name, "{$uuid}--{$expiration_timestamp}", $cookie_expiration, true, true); 452 // DEFAULT = 0 (session counting logic is only done in the front-end code) 453 $session_cookie_number = 0; 454 metrion_set_cookie("{$cookie_name}_js", "{$uuid}--{$session_cookie_number}", $cookie_expiration, false, false); 455 metrion_set_cookie($cookie_name, "{$uuid}--{$expiration_timestamp}--{$session_cookie_number}", $cookie_expiration, true, true); 414 456 } 415 457 416 458 // Helper function to extend user id cookie 417 function metrion_extend_cookie($cookie_name, $uuid, $cookie_expiration ) {459 function metrion_extend_cookie($cookie_name, $uuid, $cookie_expiration, $user_session_number) { 418 460 $expiration_timestamp = (time() + 86400 * $cookie_expiration) * 1000; 419 461 420 metrion_set_cookie("{$cookie_name}_js", $uuid, $cookie_expiration, false, false);421 metrion_set_cookie($cookie_name, "{$uuid}--{$expiration_timestamp} ", $cookie_expiration, true, true);462 metrion_set_cookie("{$cookie_name}_js", "{$uuid}--{$user_session_number}", $cookie_expiration, false, false); 463 metrion_set_cookie($cookie_name, "{$uuid}--{$expiration_timestamp}--{$user_session_number}", $cookie_expiration, true, true); 422 464 } 423 465 424 466 // Helper function to update identification (user cookie) values 425 467 function metrion_update_identification_cookies(){ 426 $user_cookie_name = sanitize_key( get_option('metrion_user_cookie_name', 'mtrn_uid') );468 $user_cookie_name = sanitize_key( get_option('metrion_user_cookie_name', 'mtrn_uid')); 427 469 $user_cookie_expiration = (int) get_option('metrion_user_cookie_lifetime', 365); 428 470 429 471 if ( ! isset( $_COOKIE[ $user_cookie_name ] ) || empty( $_COOKIE[ $user_cookie_name ] ) ) { 430 metrion_refresh_cookie( $user_cookie_name, $user_cookie_expiration );472 metrion_refresh_cookie( $user_cookie_name, $user_cookie_expiration); 431 473 } else { 432 474 $user_cookie_value = isset($_COOKIE[$user_cookie_name]) ? sanitize_text_field(wp_unslash($_COOKIE[$user_cookie_name])) : ''; 433 $user_cookie_parts = explode('--', $user_cookie_value); 475 $user_cookie_parts = explode('--', $user_cookie_value); 476 $user_cookie_session_number = 0; 477 $frontend_user_cookie_name = sanitize_key( get_option('metrion_user_cookie_name', 'mtrn_uid')) . "_js"; 478 // The front-end cookie for user data is used for counting by the create session cookie logic 479 if ( isset($_COOKIE[$frontend_user_cookie_name]) && !empty($_COOKIE[$frontend_user_cookie_name]) ){ 480 $frontend_user_cookie_value = isset($_COOKIE[$frontend_user_cookie_name]) ? sanitize_text_field(wp_unslash($_COOKIE[$frontend_user_cookie_name])) : ''; 481 $frontend_user_cookie_value_parts = explode('--', $frontend_user_cookie_value); 482 483 // Ensure cookie has exactly two parts otherwise create a new one 484 if ( count( $frontend_user_cookie_value_parts ) !== 2 ) { 485 metrion_refresh_cookie( $user_cookie_name, $user_cookie_expiration ); 486 return; 487 } 488 489 if ( count( $frontend_user_cookie_value_parts ) === 2 ) { 490 $session_part_raw = $frontend_user_cookie_value_parts[1]; 491 $session_part = sanitize_text_field( trim( wp_unslash( $session_part_raw ) ) ); 492 if ( ctype_digit( $session_part ) ) { 493 $user_cookie_session_number = (int) $session_part; 494 } 495 } 496 } 434 497 435 // Ensure cookie has exactly two parts436 if ( count( $user_cookie_parts ) !== 2 ) {437 metrion_refresh_cookie( $user_cookie_name, $user_cookie_expiration );438 return;439 }440 441 498 list( $uuid, $expiration_timestamp ) = array_pad( $user_cookie_parts, 2, '' ); 442 499 $uuid = sanitize_text_field( $uuid ); // Sanitize UUID part … … 445 502 // Validate expiration timestamp 446 503 if ( time() * 1000 >= $expiration_timestamp ) { 447 metrion_refresh_cookie( $user_cookie_name, $user_cookie_expiration );504 metrion_refresh_cookie( $user_cookie_name, $user_cookie_expiration); 448 505 } else { 449 metrion_extend_cookie( $user_cookie_name, $uuid, $user_cookie_expiration );506 metrion_extend_cookie( $user_cookie_name, $uuid, $user_cookie_expiration, $user_cookie_session_number); 450 507 } 451 508 } … … 542 599 'installation_id' => get_option('metrion_installation_id', ''), 543 600 'user_cookie_name' => get_option('metrion_user_cookie_name', 'mtrn_uid'), 601 'user_cookie_lifetime_milliseconds' => get_option('metrion_user_cookie_lifetime', 365) * 86400000, 544 602 'session_cookie_name' => get_option('metrion_session_cookie_name', 'mtrn_sid'), 545 'cookie_expiration_milliseconds' => get_option('metrion_user_cookie_lifetime', 365) * 86400000,546 603 'session_cookie_lifetime_milliseconds' => get_option('metrion_session_cookie_lifetime', 30) * 60000, 547 604 'event_id_name' => get_option('metrion_event_id_name', 'mtrn_eid'), … … 575 632 'elementor_excluded_forms' => get_option('metrion_elementor_excluded_forms', ''), 576 633 'allow_pings' => get_option('metrion_allow_pre_consent_pings', 0), 577 'enable_detection' => get_option('metrion_enable_block_detection', 1) 634 'enable_detection' => get_option('metrion_enable_block_detection', 1), 635 'google_analytics_enable_tracking' => get_option('metrion_google_analytics_enable_tracking', 0), 636 'google_analytics_measurement_id' => get_option('metrion_google_analytics_measurement_id', ''), 637 'google_analytcs_api_key' => get_option('metrion_google_analytcs_api_key', '') 578 638 ]); 579 639 } -
metrion/trunk/includes/js_bundler.php
r3300778 r3342931 228 228 } 229 229 230 if (get_option('metrion_meta_ enable_tracking', false)) {230 if (get_option('metrion_meta_allow_front_end_pixel_tracking', false)) { 231 231 $source_files[] = $plugin_dir . 'js/meta/events.js'; 232 232 } … … 301 301 } 302 302 303 if (get_option('metrion_meta_ enable_tracking', false)) {303 if (get_option('metrion_meta_allow_front_end_pixel_tracking', false)) { 304 304 $source_files[] = $plugin_dir . 'js/meta/events.js'; 305 305 } … … 412 412 if (function_exists($callback)) { 413 413 $result = call_user_func($callback); 414 415 if (is_wp_error($result)) {416 error_log("[Metrion] Failed to generate $filename: " . $result->get_error_message());417 }418 414 } 419 415 } -
metrion/trunk/js/cmp/cmplz/logic.js
r3306539 r3342931 23 23 "unix": new Date().getTime() 24 24 }; 25 26 25 var encoded_cookie_value_based_on_cmplz = encodeURIComponent(JSON.stringify(cookie_data)); 27 28 // Set the marketing metrion cookie value for dynamic loading of destinations29 cmp_allow_marketing = window.metrion.helpers.get_cookie_value("cmplz_marketing") === "allow";30 26 31 27 window.metrion.helpers.set_cookie( … … 47 43 // Function that adds event listeners for the chosen CMP 48 44 window.metrion.consent_manager.cmp_update_listener = function() { 45 document.addEventListener("cmplz_enable_category", function(event) { 46 console.log(event) 47 var cmplz_banner_status = window.metrion.helpers.get_cookie_value("cmplz_banner-status"); 48 var cmplz_window_status = cmplz_has_consent('marketing'); 49 if ((cmplz_banner_status !== null && cmplz_banner_status === "dismissed") || cmplz_window_status === true) { 50 // CMP update is already handled, if so, exit this function 51 if (window.metrion.configuration.cmp_update_handled == true) { 52 // Extend timeout 53 window.metrion.consent_manager.timeout_consent_listener_updates(); 54 return; 55 } 56 var acceptedCategories = event.detail.categories; 57 var cmplz_allow_marketing = "0"; 58 var cmplz_allow_pii = "0" 59 if (acceptedCategories.indexOf('marketing') !== -1){ 60 cmplz_allow_marketing = "1"; 61 cmplz_allow_pii = "1"; 62 } 49 63 50 document.addEventListener("cmplz_enable_category", function(event) { 51 // CMP update is already handled, if so, exit this function 52 if (window.metrion.configuration.cmp_update_handled) { 53 // Extend timeout 54 window.metrion.consent_manager.timeout_consent_listener_updates(); 55 return; 64 var encoded_cookie_value_based_on_cmplz = encodeURIComponent(JSON.stringify({ 65 "allow_marketing": cmplz_allow_marketing, 66 "allow_pii": cmplz_allow_pii, 67 "allow_uid": "1", 68 "allow_sid": "1", 69 "b": window.metrion.configuration.blocking_detected, 70 "unix": Date.now() 71 })); 72 window.metrion.helpers.set_cookie( 73 window.metrion.configuration.consent_cookie_name, 74 encoded_cookie_value_based_on_cmplz, 75 window.metrion.configuration.cookie_expiration_milliseconds, 76 "/", 77 window.metrion.configuration.cookie_domain 78 ); 79 80 window.metrion.configuration.floodgate_open = true; 81 window.metrion.configuration.cmp_update_handled = true; 82 window.metrion.consent_manager.initial_consent_enforcement(); 56 83 } 57 console.log(event);58 var category = event.detail.category;59 var acceptedCategories = event.detail.categories;60 var cmplz_allow_marketing = "0";61 var cmplz_allow_pii = "0"62 if (acceptedCategories.indexOf('marketing') !== -1){63 cmplz_allow_marketing = "1";64 cmplz_allow_pii = "1";65 }66 67 var encoded_cookie_value_based_on_cmplz = encodeURIComponent(JSON.stringify({68 "allow_marketing": cmplz_allow_marketing,69 "allow_pii": cmplz_allow_pii,70 "allow_uid": "1",71 "allow_sid": "1",72 "b": window.metrion.configuration.blocking_detected,73 "unix": Date.now()74 }));75 window.metrion.helpers.set_cookie(76 window.metrion.configuration.consent_cookie_name,77 encoded_cookie_value_based_on_cmplz,78 window.metrion.configuration.cookie_expiration_milliseconds,79 "/",80 window.metrion.configuration.cookie_domain81 );82 83 window.metrion.configuration.floodgate_open = true;84 window.metrion.configuration.cmp_update_handled = true;85 window.metrion.consent_manager.initial_consent_enforcement();86 84 }); 87 85 -
metrion/trunk/js/core/events.js
r3307446 r3342931 3 3 configuration: { 4 4 init_unix_timestamp: Date.now(), 5 last_interaction_unix_timestamp_ms: Date.now(), 6 cookie_value_separator: "--", 5 7 user_cookie_name: metrion_api.user_cookie_name + "_js", 8 user_cookie_lifetime_milliseconds: metrion_api.user_cookie_lifetime_milliseconds, 6 9 session_cookie_name: metrion_api.session_cookie_name, 7 10 session_cookie_lifetime_milliseconds: Number(metrion_api.session_cookie_lifetime_milliseconds), … … 15 18 cmp_selection: metrion_api.cmp_selection, 16 19 cmp_update_handled: false, 20 session_start_handled: false, 17 21 floodgate_name: metrion_api.floodgate_name, 18 22 floodgate_open: false, … … 39 43 if (xhr.readyState === 4) { // 4 = request done 40 44 if (xhr.status === 200) { 41 window.metrion.helpers.log_debug("Metrion Cookie Status:", JSON.parse(xhr.responseText).status, "log"); 45 window.metrion.helpers.log_debug("Metrion Cookie Status: " + window.metrion.helpers.safe_to_string(JSON.parse(xhr.responseText).status), "log"); 46 if (!window.metrion.session_manager.session_cookie_exists()) { 47 window.metrion.session_manager.create_session_cookie(); 48 } 42 49 callback(); // Call the next function after success 43 50 } else { 44 window.metrion.helpers.log_debug("Metrion Cookie Error: ", xhr.statusText, "log");51 window.metrion.helpers.log_debug("Metrion Cookie Error: " + window.metrion.helpers.safe_to_string(xhr.statusText), "log"); 45 52 } 46 53 } 47 54 }; 48 55 xhr.send(); // Send request 49 } 56 }, 57 get_user_cookie_values: function(){ 58 // Return in this order: session id, session expiration time, session start time, session number 59 var user_cookie_value = window.metrion.helpers.get_cookie_value(window.metrion.configuration.user_cookie_name); 60 if(user_cookie_value !== null){ 61 var user_cookie_value_parts = user_cookie_value.split("--"); 62 return user_cookie_value_parts; 63 } 64 return [undefined, undefined]; 65 }, 50 66 }, 51 67 … … 70 86 }, 71 87 72 get_session_id: function () { 88 get_session_cookie_values: function(){ 89 // Return in this order: session id, session expiration time, session start time, session number 90 var session_cookie_value = window.metrion.helpers.get_cookie_value(window.metrion.configuration.session_cookie_name); 91 if(session_cookie_value !== null){ 92 var session_cookie_value_parts = session_cookie_value.split(window.metrion.configuration.cookie_value_separator); 93 return session_cookie_value_parts; 94 } 95 return [undefined, undefined, undefined, undefined]; 96 97 }, 98 99 create_session_cookie: function () { 100 window.metrion.helpers.log_debug("Session cookie creation started:", "log"); 101 var configuration = window.metrion.configuration; 102 var session_start_timestamp_seconds = Math.floor(Date.now() / 1000); 103 // Default value 104 var session_number = 1; 105 // If session number exists in the user cookie 106 var user_cookie_values = window.metrion.user_manager.get_user_cookie_values(); 107 // If only user exists, get it from the user and increment it with 1 (since this function is started to launch a new session) 108 if(user_cookie_values[1] !== undefined){ 109 session_number = window.metrion.helpers.safe_parse_int(user_cookie_values[1]) + 1; 110 } 111 var session_id = window.metrion.helpers.generate_uuid(); 112 var session_expiration = new Date().getTime() + configuration.session_cookie_lifetime_milliseconds; 113 var session_cookie_new_value = session_id + window.metrion.configuration.cookie_value_separator + session_expiration + window.metrion.configuration.cookie_value_separator + session_start_timestamp_seconds; 114 // Set the session cookie with the session start time 115 //{session id}--{session expiration}--{session start time} 116 window.metrion.helpers.set_cookie(configuration.session_cookie_name, session_cookie_new_value, configuration.session_cookie_lifetime_milliseconds, "/", configuration.cookie_domain); 117 // Update the user cookie with the session number variable 118 //{user id}--{session number} 119 var user_cookie_new_value = user_cookie_values[0] + "--" + session_number; 120 window.metrion.helpers.set_cookie(configuration.user_cookie_name, user_cookie_new_value, configuration.user_cookie_lifetime_milliseconds, "/", configuration.cookie_domain); 121 return session_id; 122 }, 123 124 extend_session_cookie_lifetime: function () { 73 125 var configuration = window.metrion.configuration; 74 126 … … 77 129 } 78 130 79 var session_cookie_value = window.metrion.helpers.get_cookie_value(configuration.session_cookie_name);80 return session_cookie_value.split("--")[0];81 },82 83 create_session_cookie: function () {84 var configuration = window.metrion.configuration;85 86 var session_id = window.metrion.helpers.generate_uuid();87 var session_expiration = new Date().getTime() + configuration.session_cookie_lifetime_milliseconds;88 var session_cookie_value = session_id + "--" + session_expiration;89 window.metrion.helpers.set_cookie(configuration.session_cookie_name, session_cookie_value, configuration.session_cookie_lifetime_milliseconds, "/", configuration.cookie_domain);90 91 window.metrion.configuration.session_start_trigger = true;92 window.metrion.configuration.session_start_reasons.push("new session id");93 94 return session_id;95 },96 97 extend_session_cookie_lifetime: function () {98 var configuration = window.metrion.configuration;99 100 if (!window.metrion.session_manager.session_cookie_exists()) {101 return undefined;102 }103 104 131 if (window.metrion.session_manager.is_session_cookie_expired()) { 105 132 return window.metrion.session_manager.create_session_cookie(); 106 133 } 107 108 var session_id = window.metrion.session_manager.get_session_id(); 109 var session_expiration = new Date().getTime() + configuration.session_cookie_lifetime_milliseconds; 110 111 var updated_session_cookie_value = session_id + "--" + session_expiration; 134 135 var session_cookie_values = window.metrion.session_manager.get_session_cookie_values(); 136 var new_session_expiration = new Date().getTime() + configuration.session_cookie_lifetime_milliseconds; 137 var updated_session_cookie_value = session_cookie_values[0] + window.metrion.configuration.cookie_value_separator + new_session_expiration + window.metrion.configuration.cookie_value_separator + session_cookie_values[2]; 112 138 window.metrion.helpers.set_cookie(configuration.session_cookie_name, updated_session_cookie_value, configuration.session_cookie_lifetime_milliseconds, "/", configuration.cookie_domain); 113 139 114 return session_ id;140 return session_cookie_values[0]; 115 141 } 116 142 }, … … 121 147 window.metrion.configuration.browser_support_safe_uuid = false; 122 148 return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) { 123 return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16);149 return (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> (c / 4))).toString(16); 124 150 }); 125 151 }, 126 127 152 generate_uuid_secure: function () { 128 153 window.metrion.configuration.browser_support_safe_uuid = true; 129 154 return crypto.randomUUID(); 130 155 }, 131 132 156 generate_uuid: function () { 133 157 try { … … 144 168 return Math.floor(100000000 + Math.random() * 900000000).toString() + "." + new Date().getTime().toString(); 145 169 }, 146 147 170 get_cookie_value: function (cookie_name) { 148 171 var value = "; " + document.cookie; … … 155 178 return null; 156 179 }, 157 158 180 set_cookie: function (cookie_name, cookie_value, cookie_lifetime_in_milliseconds, cookie_path, cookie_domain) { 159 181 var cookie_secure = ";secure"; … … 162 184 var d = new Date(); 163 185 d.setTime(d.getTime() + cookie_lifetime_in_milliseconds); 164 document.cookie = cookie_name + "=" + cookie_value + ";expires=" + d.toUTCString() + ";path=" + cookie_path + ";domain=" + cookie_domain + cookie_secure + ";samesite=" + cookie_samesite; 165 }, 166 186 document.cookie = cookie_name + "=" + cookie_value + ";expires=" + d.toUTCString() + ";path=" + cookie_path + ";domain=" + cookie_domain + cookie_secure + ";SameSite=" + cookie_samesite; 187 }, 167 188 get_url_parameter_value: function (url_parameter_name) { 168 189 var urlParams = new URLSearchParams(window.location.search); 169 190 return urlParams.get(url_parameter_name) || null; 170 191 }, 171 172 192 log_debug: function (message, type) { 173 193 type = type || "log"; // Default parameter handling for ES5 compatibility … … 189 209 } 190 210 }, 191 192 211 hash: async function (input) { 193 212 if (!input) { return "" } … … 198 217 } 199 218 }, 219 wait_for_jquery: function (callback){ 220 if (typeof jQuery !== 'undefined') { 221 callback(); // jQuery is available, proceed with logic 222 } else { 223 // Use DOMContentLoaded to ensure the document is loaded 224 document.addEventListener("DOMContentLoaded", function() { 225 if (typeof jQuery !== 'undefined') { 226 callback(); // jQuery is available, proceed with logic 227 } else { 228 console.error('jQuery is not loaded yet'); 229 } 230 }); 231 } 232 }, 233 safe_parse_float: function(value) { 234 try { 235 if (value === null || typeof value === 'undefined') { 236 return 0; 237 } 238 var parsed = parseFloat(value); 239 if (isNaN(parsed)) { 240 return 0; 241 } 242 return parsed; 243 } catch (e) { 244 return 0; 245 } 246 }, 247 safe_parse_int: function(value) { 248 try { 249 if (value === null || typeof value === 'undefined') { 250 return 0; 251 } 252 var parsed = parseInt(value); 253 if (isNaN(parsed)) { 254 return 0; 255 } 256 return parsed; 257 } catch (e) { 258 return 0; 259 } 260 }, 261 safe_to_string: function(value) { 262 if (value === null || typeof value === "undefined") { 263 return ''; 264 } 265 return String(value); 266 } 200 267 }, 201 268 … … 262 329 263 330 /// CMP logic here 264 window.metrion.consent_manager.cmp_init(); 331 if (typeof window.metrion.consent_manager.cmp_init === "function") { 332 window.metrion.consent_manager.cmp_init(); 333 } 334 265 335 266 336 // Evaluate floodgate after to trigger the Metrion events … … 297 367 window.metrion.helpers.log_debug(("Collected floodgated events: " + floodgate_events.length.toString()), "log"); 298 368 299 // Ensure session management logic executes early300 if (!window.metrion.session_manager.session_cookie_exists() || window.metrion.session_manager.is_session_cookie_expired()) {301 window.metrion.session_manager.create_session_cookie();302 } else {303 window.metrion.session_manager.extend_session_cookie_lifetime();304 }305 306 369 // Store session info if available 307 if (typeof window.metrion.session_info !== "undefined" && sessionStorage) {370 if (typeof window.metrion.session_info !== "undefined" && typeof sessionStorage !== "undefined") { 308 371 sessionStorage.setItem(window.metrion.configuration.session_info_storage_name, window.metrion.session_info); 309 372 } … … 341 404 window.metrion.helpers.log_debug(("Evaluation finished with floodgate status: " + window.metrion.configuration.floodgate_open.toString()), "log"); 342 405 // Ensure user cookie existence before sending events 343 if (window.metrion. helpers.get_cookie_value(metrion_api.user_cookie_name + "_js") === null) {406 if (window.metrion.user_manager.get_user_cookie_values()[0] === undefined) { 344 407 window.metrion.user_manager.ensure_user_cookie_existance(function () { 345 408 window.metrion.helpers.log_debug("Dynamic user cookie ensuration function called", "log"); … … 357 420 var metrion_consent_cookie = window.metrion.helpers.get_cookie_value(window.metrion.configuration.consent_cookie_name); 358 421 if (metrion_consent_cookie !== null) { 359 current_consent_object = JSON.parse(decodeURIComponent(metrion_consent_cookie));422 var current_consent_object = JSON.parse(decodeURIComponent(metrion_consent_cookie)); 360 423 window.metrion.configuration.blocking_detected = "0"; // No blocking detected by default 361 424 if(JSON.parse(decodeURIComponent(metrion_consent_cookie)).b === "1"){ 362 425 window.metrion.configuration.blocking_detected = "1"; 363 426 } 364 updated_consent_object = consent_object;427 var updated_consent_object = consent_object; 365 428 // Add the blocking parameter 366 429 updated_consent_object.b = window.metrion.configuration.blocking_detected; … … 389 452 var current_stored_event = stored_event; 390 453 var consent_cookie_value = window.metrion.helpers.get_cookie_value(window.metrion.configuration.consent_cookie_name); 391 var metrion_consent_cookie_value = JSON.parse(decodeURIComponent(consent_cookie_value)); 454 var metrion_consent_cookie_value = {}; 455 if (consent_cookie_value) { 456 try { 457 metrion_consent_cookie_value = JSON.parse(decodeURIComponent(consent_cookie_value)); 458 } catch (e) { 459 // handle parse error 460 } 461 } 392 462 var allow_uid = metrion_consent_cookie_value.allow_uid === "1"; 393 463 var allow_sid = metrion_consent_cookie_value.allow_sid === "1"; … … 395 465 // Apply consent settings on floodgated events 396 466 if (allow_uid) { 397 current_stored_event[metrion_api.user_cookie_name] = window.metrion.helpers.get_cookie_value(metrion_api.user_cookie_name + "_js"); 467 468 current_stored_event[metrion_api.user_cookie_name] = window.metrion.user_manager.get_user_cookie_values()[0]; 398 469 } 399 470 else { … … 401 472 } 402 473 if (allow_sid) { 403 current_stored_event[metrion_api.session_cookie_name] = window.metrion.session_manager.get_session_ id();474 current_stored_event[metrion_api.session_cookie_name] = window.metrion.session_manager.get_session_cookie_values()[0]; 404 475 } 405 476 else { … … 417 488 current_stored_event["event_body"]["floodgated"] = true; 418 489 current_stored_event["event_body"]["floodgate_release_unix_timestamp"] = Date.now(); 490 current_stored_event["event_body"]["session_number"] = window.metrion.user_manager.get_user_cookie_values()[1]; 491 current_stored_event["event_body"]["session_start_time"] = window.metrion.session_manager.get_session_cookie_values()[2]; 492 current_stored_event["event_body"]["engaged_time_ms"] = (current_stored_event["event_unix_timestamp"]) - window.metrion.configuration.last_interaction_unix_timestamp_ms; 493 window.metrion.configuration.last_interaction_unix_timestamp_ms = current_stored_event["event_unix_timestamp"]; 419 494 420 495 // Prepare for data sending to API … … 452 527 "query": window.location.search || "", 453 528 "hash": window.location.hash || "", 454 "referrer": document.referrer || "" 529 "referrer": document.referrer || "", 530 "title": document.title || "" 455 531 }; 456 532 event_data["event_body"] = event_body || {}; 457 533 event_data["event_body"]["browser_support_safe_uuid"] = window.metrion.configuration.browser_support_safe_uuid; 458 534 event_data["event_body"]["init_unix_timestamp"] = window.metrion.configuration.init_unix_timestamp; 535 event_data["event_body"]["session_number"] = window.metrion.user_manager.get_user_cookie_values()[1]; 536 event_data["event_body"]["session_start_time"] = window.metrion.session_manager.get_session_cookie_values()[2]; 537 event_data["event_body"]["engaged_time_ms"] = (event_data["event_unix_timestamp"]) - window.metrion.configuration.last_interaction_unix_timestamp_ms; 538 539 // Don't reset the engaged time if the event is a non-interaction event 540 if (event_data["event_body"].hasOwnProperty('non_interaction') && event_data["event_body"]['non_interaction'] !== '1') { 541 window.metrion.configuration.last_interaction_unix_timestamp_ms = event_data["event_unix_timestamp"]; 542 } 459 543 460 544 // If consent cookie is available and floodgate open, handle based on the metrion consent cookie. Otherwise the event will be floodgated later 461 545 window.metrion.helpers.log_debug(("Floodgate open: " + window.metrion.configuration.floodgate_open.toString()), "log"); 462 546 window.metrion.helpers.log_debug(("Consent cookie value: " + window.metrion.helpers.get_cookie_value(decodeURIComponent(window.metrion.configuration.consent_cookie_name))), "log"); 463 window.metrion.helpers.log_debug( "User cookie value: " + window.metrion.helpers.get_cookie_value(metrion_api.user_cookie_name + "_js"), "log");547 window.metrion.helpers.log_debug(("User cookie value: " + window.metrion.user_manager.get_user_cookie_values()[0]), "log"); 464 548 465 549 // Only push events to the metrion API if the floodgates are open! … … 467 551 // First check consent information 468 552 var consent_cookie_value = window.metrion.helpers.get_cookie_value(window.metrion.configuration.consent_cookie_name); 469 var metrion_consent_cookie_value = JSON.parse(decodeURIComponent(consent_cookie_value)); 553 var metrion_consent_cookie_value = {}; 554 if (consent_cookie_value) { 555 metrion_consent_cookie_value = JSON.parse(decodeURIComponent(consent_cookie_value)); 556 } 470 557 var allow_uid = metrion_consent_cookie_value.allow_uid === "1"; 471 558 var allow_sid = metrion_consent_cookie_value.allow_sid === "1"; 472 559 if (allow_uid) { 473 event_data[metrion_api.user_cookie_name] = window.metrion. helpers.get_cookie_value(metrion_api.user_cookie_name + "_js");560 event_data[metrion_api.user_cookie_name] = window.metrion.user_manager.get_user_cookie_values()[0]; 474 561 } 475 562 if (allow_sid) { 476 event_data[metrion_api.session_cookie_name] = window.metrion.session_manager.get_session_ id();563 event_data[metrion_api.session_cookie_name] = window.metrion.session_manager.get_session_cookie_values()[0]; 477 564 } 478 565 … … 505 592 // Floodgate closed, store event behind floodgate and send ping 506 593 else { 507 if ( metrion.configuration.allow_pings === "1"){594 if (window.metrion.configuration.allow_pings === "1"){ 508 595 //Trigger the ping 509 596 this.send_ping(event_name, event_data); … … 547 634 // JS session definition logic 548 635 session_event_logic: function () { 636 window.metrion.helpers.log_debug("Start session logic function", "log"); 637 549 638 // Reload session exclusion 550 if (performance.getEntriesByType("navigation")[0].type === "reload") { 639 var nav = []; 640 if (typeof performance !== "undefined" && typeof performance.getEntriesByType === "function") { 641 nav = performance.getEntriesByType("navigation"); 642 } 643 if (nav.length > 0 && nav[0] && nav[0].type === "reload") { 551 644 return; 552 645 } 646 553 647 // Payment session exclusions 554 648 var payment_referrer_exclusions = [ … … 603 697 "gclid", "hsCtaTracking", "mc_eid", "mkt_tok", "ml_subscriber", "ml_subscriber_hash", 604 698 "msclkid", "oly_anon_id", "oly_enc_id", "rb_clickid", "s_cid", "vero_conv", 605 "vero_id", "wickedid", "yclid" 699 "vero_id", "wickedid", "yclid", "gbraid", "scid", "ttclid", "li_fat_id", 700 "cnvsn_id", "nclid", "clickid", "tid" 606 701 ]; 607 702 … … 647 742 648 743 649 for ( advertising_param_i = 0; advertising_param_i < detected_advertising_params.length; advertising_param_i++) {744 for (var advertising_param_i = 0; advertising_param_i < detected_advertising_params.length; advertising_param_i++) { 650 745 click_id_cookie_value[detected_advertising_params[advertising_param_i]] = window.metrion.helpers.get_url_parameter_value(detected_advertising_params[advertising_param_i]); 651 746 } … … 675 770 var duplicate_session_start = false; 676 771 if (window.metrion.configuration.session_start_trigger 677 && sessionStorage772 && typeof sessionStorage !== "undefined" 678 773 && window.metrion.configuration.floodgate_open) { 679 774 var current_session_info = JSON.stringify({ … … 710 805 } 711 806 807 // No session id exists 808 if(window.metrion.helpers.get_cookie_value(window.metrion.configuration.session_cookie_name) === null){ 809 window.metrion.configuration.session_start_trigger = true; 810 window.metrion.configuration.session_start_reasons.push("no session id"); 811 } 812 813 712 814 // Metrion default session evaluation 713 if ( window.metrion.configuration.session_start_trigger &&!duplicate_session_start) {815 if (!duplicate_session_start) { 714 816 if (window.metrion.configuration.allow_cookie_placement_before_explicit_consent === "1" 715 817 && !window.metrion.configuration.floodgate_open 818 && window.metrion.configuration.session_start_trigger 716 819 ) { 717 820 window.metrion.session_manager.create_session_cookie(); 718 } 719 window.metrion.configuration.session_start_trigger = false; 720 window.metrion.send_event("session_start", { 721 "reason": window.metrion.configuration.session_start_reasons.toString(), 722 "trigger_type": "front-end" 723 }, {}) 724 } 821 822 } 823 else if(window.metrion.configuration.floodgate_open 824 && window.metrion.configuration.session_start_trigger){ 825 window.metrion.session_manager.create_session_cookie(); 826 } 827 window.metrion.helpers.log_debug("Eligible session_start: " + window.metrion.configuration.session_start_trigger.toString(), "log"); 828 window.metrion.helpers.log_debug("Eligible session_start reasons: " + window.metrion.configuration.session_start_reasons.toString(), "log"); 829 830 if(window.metrion.configuration.session_start_trigger){ 831 window.metrion.configuration.session_start_trigger = false; 832 window.metrion.send_event("session_start", { 833 "reason": window.metrion.configuration.session_start_reasons.toString(), 834 "trigger_type": "front-end" 835 }, {}) 836 } 837 } 838 // Cover the cookie if the session cookie is gone in a duplicate session state 839 else if(duplicate_session_start 840 && window.metrion.configuration.session_start_trigger 841 && window.metrion.helpers.get_cookie_value(window.metrion.configuration.session_cookie_name) === null 842 && window.metrion.configuration.floodgate_open){ 843 window.metrion.session_manager.create_session_cookie(); 844 } 845 725 846 }, 726 847 // JS pageview event logic -
metrion/trunk/js/detect/detect.js
r3300778 r3342931 8 8 is_privacy_browser: false, 9 9 google_analytics_blocked: false, 10 google_ads_blocked: false 10 google_ads_blocked: false, 11 non_interaction: "1" 11 12 }; 12 13 -
metrion/trunk/js/google_ads/events.js
r3307446 r3342931 1 1 //Prevent overwriting of objects and preserve existing properties 2 2 window.metrion.google_ads = window.metrion.google_ads || {}; 3 3 window.metrion.google_ads.initialized = false; 4 4 // Initialize the Google Ads tracking script 5 5 window.metrion.google_ads.init = function(){ 6 //Exit early if already initialized 7 if (window.metrion.google_ads.initialized){ 8 return; 9 } 6 10 // Ensure that Metrion's API and configuration are available before proceeding 7 11 if(window.metrion_api && window.metrion){ … … 19 23 // Check broker que for the initial events 20 24 if(window.metrion.configuration.event_broker_queue.length > 0){ 21 for( i=0;i<window.metrion.configuration.event_broker_queue.length;i ++){25 for(var i=0;i<window.metrion.configuration.event_broker_queue.length;i ++){ 22 26 // Get the specific event 23 27 var queued_event = window.metrion.configuration.event_broker_queue[i]; … … 39 43 // Check if gtag exist 40 44 if(gtag_script_loaded === false || typeof window.gtag === "undefined"){ 45 // Pre-define before loading gtag.js 46 window.dataLayer = window.dataLayer || []; 47 window.gtag = window.gtag || function(){ dataLayer.push(arguments); }; 48 41 49 // Dynamically and Async loading of gtag script 42 50 var gtag_script = document.createElement('script'); … … 45 53 document.body.appendChild(gtag_script); 46 54 47 // Initialize gtag once the script is loaded55 // Onload just initializes config and conversion 48 56 gtag_script.onload = function() { 49 window.dataLayer = window.dataLayer || [];50 window.gtag = function(){dataLayer.push(arguments);}51 57 window.gtag('js', new Date()); 52 window.gtag('config', (window.metrion_api.google_ads_tag_id));58 window.gtag('config', window.metrion_api.google_ads_tag_id); 53 59 start_google_ads_event_handling(); 54 } 60 }; 55 61 } 56 62 else{ 57 window.gtag('js', new Date()); 63 if (!window.metrion.google_ads.check_if_gtag_js_is_already_in_datalayer()) { 64 window.gtag('js', new Date()); 65 } 58 66 window.gtag('config', (window.metrion_api.google_ads_tag_id)); 59 67 start_google_ads_event_handling(); 60 68 } 61 } 69 70 // End initialization with changing the init variable 71 window.metrion.google_ads.initialized = true; 72 } 73 62 74 }; 63 75 64 window.metrion.google_ads.check_if_gtag_script_is_loaded = function(url_to_check){ 65 var scripts = document.getElementsByTagName("script"); 76 // Checks if the gtag script is alreayd loaded 77 window.metrion.google_ads.check_if_gtag_script_is_loaded = function(base_url) { 78 base_url = base_url || 'https://www.googletagmanager.com/gtag/js'; 79 var scripts = document.getElementsByTagName('script'); 80 66 81 for (var i = 0; i < scripts.length; i++) { 67 if (scripts[i].src.indexOf(url_to_check) !== -1) { 82 var script = scripts[i]; 83 84 if (script.src && script.src.indexOf(base_url) !== -1) { 68 85 return true; 69 86 } 70 87 } 88 71 89 return false; 72 90 }; 91 92 // Checks if the 'js' event is already available in the dataLayer 93 window.metrion.google_ads.check_if_gtag_js_is_already_in_datalayer = function() { 94 if (!window.dataLayer || !Array.isArray(window.dataLayer)) { 95 return false; 96 } 97 98 for (var i = 0; i < window.dataLayer.length; i++) { 99 var entry = window.dataLayer[i]; 100 if (entry && entry[0] === 'js') { 101 return true; 102 } 103 } 104 105 return false; 106 } 73 107 74 108 // Function to monitor event queue and trigger callback when new events are pushed … … 80 114 arr.push = function(e) { 81 115 var google_ads_events_of_interest = [ 82 "purchase",116 //"purchase", > Handled directly in the purchase script outside of broker 83 117 "form_submit" 84 118 ]; … … 86 120 // See list here: https://support.google.com/google-ads/answer/7305793?hl=en 87 121 if(window.metrion_api.google_ads_enable_dynamic_remarketing === "1"){ 88 google_ads_events_of_interest .concat([122 google_ads_events_of_interest = google_ads_events_of_interest.concat([ 89 123 "view_search_results", 90 124 "view_item", … … 117 151 if(window.metrion_api && window.metrion && typeof window.gtag != "undefined"){ 118 152 153 // ENHANCED PURCHASE 154 // Process purchase events 155 if(event_name === "purchase"){ 156 // Send conversion event to Google Ads 157 window.metrion.google_ads.purchase_triggered = window.metrion.google_ads.purchase_triggered || false; 158 if(window.metrion.google_ads.purchase_triggered === false){ 159 window.gtag('event', 'conversion', { 160 'send_to': (window.metrion_api.google_ads_tag_id + "/" + window.metrion_api.google_ads_purchase_enhanced_conversion_label), 161 'value': event_data.event_body.order_total, 162 'currency': event_data.event_body.currency, 163 'transaction_id': event_data.event_body.order_id 164 }); 165 window.metrion.google_ads.purchase_triggered = true; 166 167 // GOOGLE ADS CONTEXT CHECKS 168 // First Check if recent relevant click-ids are stored 169 var google_ads_click_id = undefined; 170 try{ 171 //Parse the cookie if it exists 172 var parsed_click_ids = JSON.parse(decodeURIComponent(window.metrion.helpers.get_cookie_value(window.metrion_api.click_ids_cookie_name))); 173 if(parsed_click_ids !== null && typeof parsed_click_ids.gclid !== "undefined"){ 174 google_ads_click_id = parsed_click_ids.gclid; 175 } 176 }catch(e){}; 177 178 // If block dectection is not enabled set the value to undefined to remove the variable from the conversion 179 var block_detected = "0"; 180 if(typeof event_data.consent.b !== "undefined" && event_data.consent.b === "1"){ 181 block_detected = "1"; 182 } 183 184 // Allways send enhanced conversion event for deduplication 185 // If this event does not exist, this gtag script has failed. 186 // If this event contains a blocking intent (1), don't deduplicate for untagged conversions 187 window.metrion.helpers.log_debug("Google Ads conversion send through broker", 'log'); 188 window.metrion.send_event("google_ads_gtag_purchase_triggered", { 189 'send_to': (window.metrion_api.google_ads_tag_id + "/" + window.metrion_api.google_ads_purchase_enhanced_conversion_label), 190 'value': event_data.event_body.order_total, 191 'currency': event_data.event_body.currency, 192 'transaction_id': event_data.event_body.order_id, 193 'gclid': google_ads_click_id, 194 'enable_detection': window.metrion_api.enable_detection, 195 'b': block_detected, 196 'trigger_type': "front-end", 197 'trigger_mechanism': "broker", 198 'non_interaction': "1" 199 }, {}); 200 } 201 else{ 202 window.metrion.helpers.log_debug("Google Ads conversion already triggered, not activated using broker", 'log'); 203 } 204 } 205 206 // Enhanced leads 207 if(event_name === "form_submit"){ 208 window.gtag('event', 'lead', { 209 'send_to': (window.metrion_api.google_ads_tag_id + "/" + window.metrion_api.google_ads_purchase_enhanced_conversion_label), 210 'transaction_id': event_data.event_body.email 211 }); 212 213 var metrion_click_ids = {}; 214 try { 215 var metrion_click_ids = JSON.parse(decodeURIComponent(window.metrion.helpers.get_cookie_value("mtrn_cids"))); 216 } catch(e) {}; 217 218 var google_ads_click_id = ""; 219 if(metrion_click_ids !== null && typeof metrion_click_ids.gclid !== "undefined"){ 220 google_ads_click_id = metrion_click_ids.gclid; 221 } 222 223 window.metrion.send_event("google_ads_gtag_lead_triggered", { 224 'send_to': (window.metrion_api.google_ads_tag_id + "/" + window.metrion_api.google_ads_purchase_enhanced_conversion_label), 225 'transaction_id': event_data.event_body.email, 226 'gclid': google_ads_click_id, 227 'non_interaction': "1" 228 }, {}); 229 } 230 119 231 // DYNAMIC REMARKETING 120 232 // Check if dynamic remarketing is enabled if that is the case, send the remarketing tag … … 158 270 if(typeof event_data.event_body.items !== "undefined" && event_data.event_body.items.length > 0){ 159 271 collective_currency = event_data.event_body.items[0].currency; 160 for( google_ads_item_i = 0; google_ads_item_i < event_data.event_body.items.length; google_ads_item_i ++ ){272 for(var google_ads_item_i = 0; google_ads_item_i < event_data.event_body.items.length; google_ads_item_i ++ ){ 161 273 google_ads_items.push({ 162 274 id: event_data.event_body.items[google_ads_item_i].id, … … 184 296 if(typeof event_data.event_body.items !== "undefined" && event_data.event_body.items.length > 0){ 185 297 collective_currency = event_data.event_body.items[0].currency; 186 for( google_ads_item_i = 0; google_ads_item_i < event_data.event_body.items.length; google_ads_item_i ++ ){298 for(var google_ads_item_i = 0; google_ads_item_i < event_data.event_body.items.length; google_ads_item_i ++ ){ 187 299 google_ads_items.push({ 188 300 id: event_data.event_body.items[google_ads_item_i].id, … … 206 318 var collective_value = 0; 207 319 // Loop through all items to get the collective parameters necessary for Google Ads dynamic remarketing 208 for( google_ads_item_i = 0; google_ads_item_i < event_data.event_body.items.length; google_ads_item_i ++ ){320 for(var google_ads_item_i = 0; google_ads_item_i < event_data.event_body.items.length; google_ads_item_i ++ ){ 209 321 google_ads_items.push({ 210 322 id: event_data.event_body.items[google_ads_item_i].id, … … 226 338 // Loop through all items to get the collective parameters necessary for Google Ads dynamic remarketing 227 339 var google_ads_items = []; 228 for(google_ads_item_i = 0; google_ads_item_i < event_data.event_body.items.length; google_ads_item_i ++ ){ 340 var collective_value = 0; 341 for(var google_ads_item_i = 0; google_ads_item_i < event_data.event_body.items.length; google_ads_item_i ++ ){ 229 342 google_ads_items.push({ 230 343 id: event_data.event_body.items[google_ads_item_i].id, … … 243 356 } 244 357 } 245 246 // ENHANCED PURCHASE247 // Process purchase events248 if(event_name === "purchase"){249 // Send conversion event to Google Ads250 window.gtag('event', 'conversion', {251 'send_to': (window.metrion_api.google_ads_tag_id + "/" + window.metrion_api.google_ads_purchase_enhanced_conversion_label),252 'value': event_data.event_body.order_total,253 'currency': event_data.event_body.currency,254 'transaction_id': event_data.event_body.order_id255 });256 257 // GOOGLE ADS CONTEXT CHECKS258 // First Check if recent relevant click-ids are stored259 var google_ads_click_id = undefined;260 261 try{262 //Parse the cookie if it exists263 var parsed_click_ids = JSON.parse(decodeURIComponent(window.metrion.helpers.get_cookie_value(window.metrion_api.click_ids_cookie_name)));264 if(parsed_click_ids !== null && typeof parsed_click_ids.gclid !== "undefined"){265 google_ads_click_id = parsed_click_ids.gclid;266 }267 }catch(e){};268 269 // If block dectection is not enabled set the value to undefined to remove the variable from the conversion270 var block_detected = "0";271 if(typeof event_data.consent.b !== "undefined" && event_data.consent.b === "1"){272 block_detected = "1";273 }274 275 // Allways send enhanced conversion event for deduplication276 // If this event does not exist, this gtag script has failed.277 // If this event contains a blocking intent (1), don't deduplicate for untagged conversions278 window.metrion.helpers.log_debug("Google Ads conversion send through gtag", 'log');279 window.metrion.send_event("google_ads_gtag_purchase_triggered", {280 'send_to': (window.metrion_api.google_ads_tag_id + "/" + window.metrion_api.google_ads_purchase_enhanced_conversion_label),281 'value': event_data.event_body.order_total,282 'currency': event_data.event_body.currency,283 'transaction_id': event_data.event_body.order_id,284 'gclid': google_ads_click_id,285 'enable_detection': window.metrion_api.enable_detection,286 'b': block_detected,287 'trigger_type': "front-end"288 }, {});289 }290 291 if(event_name === "form_submit"){292 window.gtag('event', 'lead', {293 'send_to': (window.metrion_api.google_ads_tag_id + "/" + window.metrion_api.google_ads_purchase_enhanced_conversion_label),294 'transaction_id': event_data.event_body.email295 });296 297 var metrion_click_ids = JSON.parse(decodeURIComponent(window.metrion.helpers.get_cookie_value("mtrn_cids")));298 var google_ads_click_id = "";299 if(metrion_click_ids !== null && typeof metrion_click_ids.gclid !== "undefined"){300 google_ads_click_id = metrion_click_ids.gclid;301 }302 303 window.metrion.send_event("google_ads_gtag_lead_triggered", {304 'send_to': (window.metrion_api.google_ads_tag_id + "/" + window.metrion_api.google_ads_purchase_enhanced_conversion_label),305 'transaction_id': event_data.event_body.email,306 'gclid': google_ads_click_id307 }, {});308 }309 358 } 310 359 }; -
metrion/trunk/js/meta/events.js
r3316153 r3342931 81 81 collective_currency = event_data.event_body.items[0].currency; // Get from the first item 82 82 // Loop through all items to get the collective parameters necessary for Meta 83 for(meta_item_i = 0; meta_item_i < event_data.event_body.items.length; meta_item_i ++ ){ 83 for(var meta_item_i = 0; meta_item_i < event_data.event_body.items.length; meta_item_i ++ ){ 84 var current_item_quantity = window.metrion.helpers.safe_parse_int(event_data.event_body.items[meta_item_i].quantity); 85 var current_item_price = window.metrion.helpers.safe_parse_float(event_data.event_body.items[meta_item_i].price); 84 86 item_contents.push({ 85 87 id: event_data.event_body.items[meta_item_i].id, 86 quantity: event_data.event_body.items[meta_item_i].quantity88 quantity: current_item_quantity 87 89 }); 88 90 item_content_ids.push(event_data.event_body.items[meta_item_i].id); 89 item_count = parseInt(item_count) + parseInt(event_data.event_body.items[meta_item_i].quantity);90 collective_value = parseFloat(collective_value) + ( parseFloat(event_data.event_body.items[meta_item_i].price) * parseInt(event_data.event_body.items[meta_item_i].quantity));91 item_count = parseInt(item_count) + current_item_quantity; 92 collective_value = parseFloat(collective_value) + (current_item_price * current_item_quantity); 91 93 } 92 94 } … … 117 119 content_ids: [event_data.event_body.items[0].id], 118 120 content_type: event_data.event_body.items[0].type, 119 value: event_data.event_body.items[0].price,121 value: window.metrion.helpers.safe_parse_float(event_data.event_body.items[0].price), 120 122 currency: event_data.event_body.items[0].currency, 121 123 contents: [{ 122 124 id: event_data.event_body.items[0].id, 123 quantity: event_data.event_body.items[0].quantity 124 }] }, 125 quantity: window.metrion.helpers.safe_parse_int(event_data.event_body.items[0].quantity) 126 }] 127 }, 125 128 { 126 129 eventID: event_data[window.metrion_api.event_id_name] … … 137 140 content_ids: [event_data.event_body.items[0].id], 138 141 content_type: event_data.event_body.items[0].type, 139 value: event_data.event_body.items[0].price,142 value: window.metrion.helpers.safe_parse_float(event_data.event_body.items[0].price), 140 143 currency: event_data.event_body.items[0].currency, 141 144 contents: [{ 142 145 id: event_data.event_body.items[0].id, 143 quantity: event_data.event_body.items[0].quantity146 quantity: 1 // Set to 1 144 147 }] 145 148 }, … … 158 161 var collective_currency = event_data.event_body.items[0].currency; // Get from the first item 159 162 // Loop through all items to get the collective parameters necessary for Meta 160 for(meta_item_i = 0; meta_item_i < event_data.event_body.items.length; meta_item_i ++ ){ 163 for(var meta_item_i = 0; meta_item_i < event_data.event_body.items.length; meta_item_i ++ ){ 164 var current_item_quantity = window.metrion.helpers.safe_parse_int(event_data.event_body.items[meta_item_i].quantity); 165 var current_item_price = window.metrion.helpers.safe_parse_float(event_data.event_body.items[meta_item_i].price); 161 166 item_contents.push({ 162 167 id: event_data.event_body.items[meta_item_i].id, 163 quantity: event_data.event_body.items[meta_item_i].quantity168 quantity: current_item_quantity 164 169 }); 165 170 item_content_ids.push(event_data.event_body.items[meta_item_i].id); 166 item_count = parseInt(item_count) + parseInt(event_data.event_body.items[meta_item_i].quantity);167 collective_value = parseFloat(collective_value) + ( parseFloat(event_data.event_body.items[meta_item_i].price) * parseInt(event_data.event_body.items[meta_item_i].quantity));171 item_count = parseInt(item_count) + current_item_quantity; 172 collective_value = parseFloat(collective_value) + (current_item_price * current_item_quantity); 168 173 } 169 174 window.fbq('trackSingle', window.metrion_api.meta_pixel_id, "InitiateCheckout", { … … 191 196 192 197 // Loop through all items to get the collective parameters necessary for Meta 193 for(meta_item_i = 0; meta_item_i < event_data.event_body.items.length; meta_item_i ++ ){ 198 for(var meta_item_i = 0; meta_item_i < event_data.event_body.items.length; meta_item_i ++ ){ 199 var current_item_quantity = window.metrion.helpers.safe_parse_int(event_data.event_body.items[meta_item_i].quantity); 200 var current_item_price = window.metrion.helpers.safe_parse_float(event_data.event_body.items[meta_item_i].price); 194 201 item_contents.push({ 195 202 id: event_data.event_body.items[meta_item_i].id, 196 quantity: event_data.event_body.items[meta_item_i].quantity203 quantity: current_item_quantity 197 204 }); 198 205 item_content_ids.push(event_data.event_body.items[meta_item_i].id); 199 item_count = parseInt(item_count) + parseInt(event_data.event_body.items[meta_item_i].quantity);200 collective_value = parseFloat(collective_value) + ( parseFloat(event_data.event_body.items[meta_item_i].price) * parseInt(event_data.event_body.items[meta_item_i].quantity));206 item_count = parseInt(item_count) + current_item_quantity; 207 collective_value = parseFloat(collective_value) + (current_item_price * current_item_quantity); 201 208 } 202 209 … … 212 219 }, 213 220 { 214 eventID: event_data[window.metrion_api.event_id_name], 221 // Use the order id instead of the event id for purchase events 222 eventID: event_data.event_body.order_id, 215 223 }); 216 224 } -
metrion/trunk/js/microsoft_ads/events.js
r3290502 r3342931 9 9 10 10 //If consent mode is to be enforced by Metrion 11 if(window.metrion_api.microsoft_ads_enforce_consent_mode = Number(true).toString() && typeof window.metrion.microsoft_ads.set_consent_mode_to_granted !== "undefined"){11 if(window.metrion_api.microsoft_ads_enforce_consent_mode == Number(true).toString() && typeof window.metrion.microsoft_ads.set_consent_mode_to_granted !== "undefined"){ 12 12 // Update consent mode to granted (this script can only be loaded if consent mode is granted) 13 13 window.metrion.microsoft_ads.set_consent_mode_to_granted(); … … 239 239 "enable_detection": window.metrion_api.enable_detection, 240 240 "b": block_detected, 241 "trigger_type": "front-end" 241 "trigger_type": "front-end", 242 "non_interaction": "1" 242 243 }, {}); 243 244 } -
metrion/trunk/js/settings/settings.js
r3300778 r3342931 49 49 meta_ads_button.textContent = `Meta Ads Configuration Settings ${isHiddenMetaAds ? '▲' : '▼'}`; 50 50 }); 51 52 // Google Analytics options 53 var google_analytics_button = document.getElementById('google-analytics-settings-toggle'); 54 var google_analytics_settings = document.getElementById('google-analytics-settings'); 55 56 google_analytics_button.addEventListener('click', function() { 57 const isHiddenMetaAds = google_analytics_settings.style.display === 'none'; 58 google_analytics_settings.style.display = isHiddenMetaAds ? 'block' : 'none'; 59 google_analytics_button.textContent = `Google Analytics Configuration Settings ${isHiddenMetaAds ? '▲' : '▼'}`; 60 }); 51 61 }); -
metrion/trunk/js/woo/other_events.js
r3300778 r3342931 4 4 // JS Woocommerce other event logic 5 5 window.metrion.woocommerce_event_logic = function () { 6 // jQuery is required for Woocommerce 7 jQuery(function ($) { 8 // Add-to-cart listener 9 $("body").on("click", ".add_to_cart_button, .single_add_to_cart_button", function (event) { 10 try { 11 var product_id, product_name, product_price, product_regular_price, product_sku, quantity = 1; 12 var currency = $(this).data("currency") || "EUR"; // Default currency 13 14 // Determine the source of the metrion_item_data span 15 var product_data_span; 16 17 if ($(this).hasClass("single_add_to_cart_button")) { 18 // For single product pages, get the span from the footer 19 product_data_span = $("#metrion_item_data_single").find(".metrion_item_data_single"); 20 } else { 21 // For product loops, get the span from the closest product container 22 product_data_span = $(this).closest(".product").find(".metrion_item_data_loop"); 23 } 24 25 // Ensure the span exists before proceeding 26 if (!product_data_span.length || product_data_span.length <= 0) { 27 console.error("No metrion_item_data span found for this product."); 28 return; 29 } 30 31 // Extract data correctly 32 product_id = product_data_span.attr("data-item_id"); 33 product_name = product_data_span.attr("data-item_name"); 34 product_price = product_data_span.attr("data-item_price"); 35 product_regular_price = product_data_span.attr("data-item_regular_price"); 36 product_sku = product_data_span.attr("data-item_sku"); 37 var category_1 = product_data_span.attr("data-item_category_1") || null; 38 var category_2 = product_data_span.attr("data-item_category_2") || null; 39 var category_3 = product_data_span.attr("data-item_category_3") || null; 40 var category_4 = product_data_span.attr("data-item_category_4") || null; 41 42 // If a quantity input exists, update the quantity 43 var quantity_input = $(this).closest("form.cart").find("input.qty"); 44 if (quantity_input.length) { 45 quantity = parseInt(quantity_input.val()) || 1; 46 } 47 48 // Ensure we have the necessary data 49 if (!product_id || !product_name || !product_price) { 50 console.error("Item data is missing. Cannot send event to Metrion."); 51 return; 52 } 53 54 var product_data = { 55 "type": "product", 56 "id": product_id, 57 "name": product_name, 58 "price": product_price, 59 "regular_price": product_regular_price, 60 "quantity": quantity, 61 "sku": product_sku, 62 "url": window.location.href, 63 "currency": currency, 64 "category_1": category_1, 65 "category_2": category_2, 66 "category_3": category_3, 67 "category_4": category_4 68 }; 69 70 // Send data to Metrion 71 if (typeof metrion !== "undefined" && typeof metrion.send_event === "function") { 72 metrion.send_event("add_to_cart", { 73 "items": [product_data], 74 "trigger_type": "front-end" 75 }); 76 } else { 77 console.error("Metrion is not available or send_event function is missing."); 78 } 79 } catch (error) { 80 console.error("Error in Add to Cart event:", error); 81 } 82 }); 83 84 // Item view event for single product pages 85 if ($("body").hasClass("single-product")) { 86 try { 87 var product_id, product_name, product_price, product_sku; 88 var quantity = 1; 89 var currency = "EUR"; // Default currency 90 91 // Get data from the metrion_item_data_single span in the footer 92 var product_data_span = $("#metrion_item_data_single").find(".metrion_item_data_single"); 93 94 if (product_data_span.length) { 95 product_id = product_data_span.data("item_id"); 96 product_name = product_data_span.data("item_name"); 97 product_price = product_data_span.data("item_price"); 98 product_regular_price = product_data_span.data("item_regular_price"); 99 product_sku = product_data_span.data("item_sku"); 100 category_1 = product_data_span.data("item_category_1") || null; 101 category_2 = product_data_span.data("item_category_2") || null; 102 category_3 = product_data_span.data("item_category_3") || null; 103 category_4 = product_data_span.data("item_category_4") || null; 104 currency = product_data_span.data("currency") || currency; 105 } 106 107 // Ensure we have the necessary data 108 if (product_id && product_name && product_price) { 6 // Wait to check if jQuery is ready 7 window.metrion.helpers.wait_for_jquery(function(){ 8 // jQuery is required for Woocommerce 9 jQuery(function ($) { 10 // Add-to-cart listener 11 $("body").on("click", ".add_to_cart_button, .single_add_to_cart_button", function (event) { 12 try { 13 var product_id, product_name, product_price, product_regular_price, product_sku, quantity = 1; 14 var currency = $(this).data("currency") || "EUR"; // Default currency 15 16 // Determine the source of the metrion_item_data span 17 var product_data_span; 18 19 if ($(this).hasClass("single_add_to_cart_button")) { 20 // For single product pages, get the span from the footer 21 product_data_span = $("#metrion_item_data_single").find(".metrion_item_data_single"); 22 } else { 23 // For product loops, get the span from the closest product container 24 product_data_span = $(this).closest(".product").find(".metrion_item_data_loop"); 25 } 26 27 // Ensure the span exists before proceeding 28 if (!product_data_span.length || product_data_span.length <= 0) { 29 console.error("No metrion_item_data span found for this product."); 30 return; 31 } 32 33 // Extract data correctly 34 product_id = product_data_span.attr("data-item_id"); 35 product_name = product_data_span.attr("data-item_name"); 36 product_price = product_data_span.attr("data-item_price"); 37 product_regular_price = product_data_span.attr("data-item_regular_price"); 38 product_sku = product_data_span.attr("data-item_sku"); 39 var category_1 = product_data_span.attr("data-item_category_1") || null; 40 var category_2 = product_data_span.attr("data-item_category_2") || null; 41 var category_3 = product_data_span.attr("data-item_category_3") || null; 42 var category_4 = product_data_span.attr("data-item_category_4") || null; 43 44 // If a quantity input exists, update the quantity 45 var quantity_input = $(this).closest("form.cart").find("input.qty"); 46 if (quantity_input.length) { 47 quantity = parseInt(quantity_input.val()) || 1; 48 } 49 50 // Ensure we have the necessary data 51 if (!product_id || !product_name || !product_price) { 52 console.error("Item data is missing. Cannot send event to Metrion."); 53 return; 54 } 55 109 56 var product_data = { 110 57 "type": "product", 111 "id": product_id,112 "name": product_name,113 "price": product_price,114 "regular_price": product_regular_price,115 "quantity": quantity,116 "sku": product_sku,117 "url": window.location.href, // The URL of the item page58 "id": window.metrion.helpers.safe_to_string(product_id), 59 "name": window.metrion.helpers.safe_to_string(product_name), 60 "price": window.metrion.helpers.safe_to_string(product_price), 61 "regular_price": window.metrion.helpers.safe_to_string(product_regular_price), 62 "quantity": window.metrion.helpers.safe_to_string(quantity), 63 "sku": window.metrion.helpers.safe_to_string(product_sku), 64 "url": window.location.href, 118 65 "currency": currency, 119 66 "category_1": category_1, … … 122 69 "category_4": category_4 123 70 }; 124 125 // Send data to Metrion for item view event71 72 // Send data to Metrion 126 73 if (typeof metrion !== "undefined" && typeof metrion.send_event === "function") { 127 metrion.send_event(" item_view", {74 metrion.send_event("add_to_cart", { 128 75 "items": [product_data], 129 76 "trigger_type": "front-end" … … 132 79 console.error("Metrion is not available or send_event function is missing."); 133 80 } 134 } else { 135 console.error("Item data is missing. Cannot send event to Metrion."); 136 } 137 } catch (error) { 138 console.error("Error in Item View event:", error); 139 } 140 } 141 142 // Item lists / search results 143 if (typeof window.metrion_loop !== "undefined" 144 && typeof window.metrion_basket_items === "undefined" 145 && typeof window.metrion_checkout_items === "undefined" 146 && typeof window.metrion_purchase_data === "undefined") { 147 // Event name logic 148 var loop_event_name = "view_item_list"; 149 if (window.metrion_loop.is_search_page) { 150 loop_event_name = "view_search_results"; 151 } 152 153 // Event body logic 154 var loop_event_body = { 155 "items": window.metrion_loop.loop_items, 156 "trigger_type": "front-end" 157 } 158 // Category page context 159 if (window.window.metrion_is_category_page) { 160 loop_event_body["is_category_page"] = window.metrion_is_category_page; 161 if (window.metrion_category_hierarchy && window.metrion_category_hierarchy.length > 0) { 162 loop_event_body["category_hierarchy"] = window.metrion_category_hierarchy.join(", "); 163 164 } 165 } 166 // Search page context 167 if (window.metrion_loop.is_search_page && typeof window.metrion_loop.search_term !== "undefined") { 168 loop_event_body["is_search_page"] = window.metrion_loop.is_search_page; 169 loop_event_body["search_term"] = window.metrion_loop.search_term; 170 } 171 172 // Trigger the event 173 window.metrion.send_event(loop_event_name, loop_event_body); 174 175 } 176 177 // Basket view 178 // Ensure metrion_basket_items is available 179 if (typeof window.metrion_basket_items !== "undefined") { 180 window.metrion.send_event("basket_view", { 181 "items": window.metrion_basket_items.items, 182 "trigger_type": "front-end" 81 } catch (error) { 82 console.error("Error in Add to Cart event:", error); 83 } 183 84 }); 184 } else { 185 window.metrion.helpers.log_debug("No checkout items available for begin_checkout.", "log"); 186 } 187 188 // Begin checkout 189 // Ensure metrion_checkout_items is available 190 if (typeof window.metrion_checkout_items !== "undefined") { 191 window.metrion.send_event("begin_checkout", { 192 "items": window.metrion_checkout_items.items, 193 "trigger_type": "front-end" 194 }); 195 } else { 196 window.metrion.helpers.log_debug("No checkout items available for begin_checkout.", "log"); 197 } 85 86 // Item view event for single product pages 87 if ($("body").hasClass("single-product")) { 88 try { 89 var product_id, product_name, product_price, product_sku; 90 var quantity = 1; 91 var currency = "EUR"; // Default currency 92 93 // Get data from the metrion_item_data_single span in the footer 94 var product_data_span = $("#metrion_item_data_single").find(".metrion_item_data_single"); 95 96 if (product_data_span.length) { 97 product_id = window.metrion.helpers.safe_to_string(product_data_span.data("item_id")); 98 product_name = window.metrion.helpers.safe_to_string(product_data_span.data("item_name")); 99 product_price = window.metrion.helpers.safe_to_string(product_data_span.data("item_price")); 100 product_regular_price = window.metrion.helpers.safe_to_string(product_data_span.data("item_regular_price")); 101 product_sku = window.metrion.helpers.safe_to_string(product_data_span.data("item_sku")); 102 category_1 = product_data_span.data("item_category_1") || null; 103 category_2 = product_data_span.data("item_category_2") || null; 104 category_3 = product_data_span.data("item_category_3") || null; 105 category_4 = product_data_span.data("item_category_4") || null; 106 currency = product_data_span.data("currency") || currency; 107 } 108 109 // Ensure we have the necessary data 110 if (product_id && product_name && product_price) { 111 var product_data = { 112 "type": "product", 113 "id": window.metrion.helpers.safe_to_string(product_id), 114 "name": window.metrion.helpers.safe_to_string(product_name), 115 "price": window.metrion.helpers.safe_to_string(product_price), 116 "regular_price": window.metrion.helpers.safe_to_string(product_regular_price), 117 "quantity": window.metrion.helpers.safe_to_string(quantity), 118 "sku": window.metrion.helpers.safe_to_string(product_sku), 119 "url": window.location.href, // The URL of the item page 120 "currency": currency, 121 "category_1": category_1, 122 "category_2": category_2, 123 "category_3": category_3, 124 "category_4": category_4 125 }; 126 127 // Send data to Metrion for item view event 128 if (typeof metrion !== "undefined" && typeof metrion.send_event === "function") { 129 metrion.send_event("item_view", { 130 "items": [product_data], 131 "trigger_type": "front-end" 132 }); 133 } else { 134 console.error("Metrion is not available or send_event function is missing."); 135 } 136 } else { 137 console.error("Item data is missing. Cannot send event to Metrion."); 138 } 139 } catch (error) { 140 console.error("Error in Item View event:", error); 141 } 142 } 143 144 // Item lists / search results 145 if (typeof window.metrion_loop !== "undefined" 146 && typeof window.metrion_basket_items === "undefined" 147 && typeof window.metrion_checkout_items === "undefined" 148 && typeof window.metrion_purchase_data === "undefined") { 149 // Event name logic 150 var loop_event_name = "view_item_list"; 151 if (window.metrion_loop.is_search_page) { 152 loop_event_name = "view_search_results"; 153 } 154 155 // Event body logic 156 var loop_event_body = { 157 "items": window.metrion_loop.loop_items, 158 "trigger_type": "front-end" 159 } 160 // Category page context 161 if (window.window.metrion_is_category_page) { 162 loop_event_body["is_category_page"] = window.metrion_is_category_page; 163 if (window.metrion_category_hierarchy && window.metrion_category_hierarchy.length > 0) { 164 loop_event_body["category_hierarchy"] = window.metrion_category_hierarchy.join(", "); 165 166 } 167 } 168 // Search page context 169 if (window.metrion_loop.is_search_page && typeof window.metrion_loop.search_term !== "undefined") { 170 loop_event_body["is_search_page"] = window.metrion_loop.is_search_page; 171 loop_event_body["search_term"] = window.metrion_loop.search_term; 172 } 173 174 // Trigger the event 175 window.metrion.send_event(loop_event_name, loop_event_body); 176 177 } 178 179 // Basket view 180 // Ensure metrion_basket_items is available 181 if (typeof window.metrion_basket_items !== "undefined") { 182 window.metrion.send_event("basket_view", { 183 "items": window.metrion_basket_items.items, 184 "trigger_type": "front-end" 185 }); 186 } else { 187 window.metrion.helpers.log_debug("No checkout items available for begin_checkout.", "log"); 188 } 189 190 // Begin checkout 191 // Ensure metrion_checkout_items is available 192 if (typeof window.metrion_checkout_items !== "undefined") { 193 window.metrion.send_event("begin_checkout", { 194 "items": window.metrion_checkout_items.items, 195 "trigger_type": "front-end" 196 }); 197 } else { 198 window.metrion.helpers.log_debug("No checkout items available for begin_checkout.", "log"); 199 } 200 }); 198 201 }); 199 202 }; -
metrion/trunk/js/woo/purchase_event.js
r3300778 r3342931 1 1 // Prevent overwriting of objects and preserve existing properties 2 2 window.metrion = window.metrion || {}; 3 3 // Set the flag globally on the window to retain its state across page reloads 4 window.metrion.woocommerce_purchase_logic_triggered = false; 4 5 // Woocommerce Purchase event logic 5 6 window.metrion.woocommerce_purchase_logic = function (){ 6 // jQuery is required for Woocommerce 7 jQuery(function ($) { 7 8 // Wait to check if jQuery is ready 9 // Function to check if metrion_purchase_data is available 10 function check_purchase_data() { 11 // Early exit if no purchase data exists 12 if (typeof window.metrion_purchase_data === "undefined") { 13 return; 14 } 15 8 16 // Purchase 9 17 // Ensure purchase_data is available … … 18 26 "coupons": window.metrion_purchase_data.coupons 19 27 } 20 //Add destination specific logic21 if (window.metrion_api.google_enable_tracking === "1") {22 if (window.metrion_purchase_data.hasOwnProperty("google_ads")) {23 purchase_event_body["google_ads"] = window.metrion_purchase_data.google_ads;24 }25 }26 28 27 29 // Example: Send purchase data to an analytics system 28 30 window.metrion.send_event("purchase", purchase_event_body); 31 window.metrion.woocommerce_purchase_logic_triggered = true; 29 32 } else { 30 33 window.metrion.helpers.log_debug("Purchase data is not available.", "log"); 31 34 } 35 } 36 37 // Wait for DOMContentLoaded first 38 if (document.readyState === "loading") { 39 document.addEventListener("DOMContentLoaded", function () { 40 if(!window.metrion.woocommerce_purchase_logic_triggered){ 41 check_purchase_data(); // Call the function once DOM is ready 42 } 43 }); 44 } else { 45 if(!window.metrion.woocommerce_purchase_logic_triggered){ 46 // If DOM is already loaded, just run the function immediately 47 check_purchase_data(); 48 } 49 } 50 // Fallback: In case DOMContentLoaded isn't triggered (very rare case), use window.onload 51 window.onload = function () { 52 if(!window.metrion.woocommerce_purchase_logic_triggered){ 53 check_purchase_data(); 54 } 55 }; 56 57 // Final trigger method is after jQuery is ready 58 window.metrion.helpers.wait_for_jquery(function(){ 59 if(!window.metrion.woocommerce_purchase_logic_triggered){ 60 check_purchase_data(); 61 } 32 62 }); 63 33 64 }; 34 65 // Call the function -
metrion/trunk/main.php
r3316153 r3342931 3 3 * Plugin Name: Metrion 4 4 * Description: Skip manual implementation, sync data directly tailored to destinations like Google Ads and Meta Ads. 5 * Version: 1.5. 35 * Version: 1.5.5 6 6 * Author: Metrion 7 7 * Author URI: https://getmetrion.com … … 12 12 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly 13 13 14 define('GLOBAL_METRION_PLUGIN_VERSION', '1.5. 3');14 define('GLOBAL_METRION_PLUGIN_VERSION', '1.5.5'); 15 15 16 16 // Register plugin settings for webhook URL, API path, debug mode, cookie name, and expiration time … … 75 75 add_option('metrion_microsoft_ads_tag_id', ''); // Open field for Microsoft Ads UET Tag ID 76 76 77 // Google Ads destination options 78 add_option('metrion_google_analytics_enable_tracking', 0); // Default setting for enabling Google Analytics 79 add_option('metrion_google_analytics_measuremet_id', ''); // Open field for the measurement ID 80 add_option('metrion_google_analytcs_api_key', ''); // Open field for the API key 81 77 82 // Register the Metrion settings 78 83 register_setting('metrion_options_group', 'metrion_data_collection', ['sanitize_callback' => 'rest_sanitize_boolean']); … … 139 144 register_setting('metrion_options_group', 'metrion_meta_test_event_code', ['sanitize_callback' => 'sanitize_text_field']); 140 145 146 // Register the Google Analytics destination settings 147 register_setting('metrion_options_group', 'metrion_google_analytics_enable_tracking', ['sanitize_callback' => 'rest_sanitize_boolean']); 148 register_setting('metrion_options_group', 'metrion_google_analytics_measuremet_id', ['sanitize_callback' => 'sanitize_text_field']); 149 register_setting('metrion_options_group', 'metrion_google_analytcs_api_key', ['sanitize_callback' => 'sanitize_text_field']); 141 150 } 142 151 -
metrion/trunk/readme.txt
r3316153 r3342931 4 4 Requires at least: 3.8 5 5 Tested up to: 6.8 6 Stable tag: 1.5. 36 Stable tag: 1.5.5 7 7 Requires PHP: 7.1 8 8 License: GPLv3 or later … … 38 38 * Microsoft Ads consent mode 39 39 * Microsoft Ads dynamic remarketing list functionality 40 * Google Analytics 4 sever-side 40 41 41 42 == Installation == … … 86 87 87 88 == Changelog == 89 90 = 1.5.5 = 91 - Google Analytics beta 92 - Improve advertising click-id retention 93 - Labeled non-interaction events for GA4 94 95 = 1.5.4 = 96 - Updated Google Ads front-end tracking logic and trigger priority 97 - Updated handling of jQuery loading irregularities 98 - Changed the Meta Ads tracking settings options to enable more tracking options: front-end only, server-side only and combined tracking. 88 99 89 100 = 1.5.3 = -
metrion/trunk/views/settings.php
r3300778 r3342931 373 373 <table class="metrion-settings-meta-ads metrion-settings-advanced"> 374 374 <tr valign="top"> 375 <th scope="row"><label for="metrion_meta_enable_tracking">Enable Meta tracking</label></th>375 <th scope="row"><label for="metrion_meta_enable_tracking">Enable server-side Meta tracking</label></th> 376 376 <td> 377 377 <label class="switch"> … … 458 458 </table> 459 459 </div> 460 <p> 461 <a href="javascript:void(0);" id="google-analytics-settings-toggle"> 462 Google Analytics Configuration Settings ▼ 463 </a> 464 </p> 465 <div id="google-analytics-settings" style="display: none;"> 466 <h2>Google Analytics settings BETA</h2> 467 <p>Configure the fields below to match your Google Analytics tracking needs.</p> 468 <table class="metrion-settings-google-analytics metrion-settings-advanced"> 469 <tr valign="top"> 470 <th scope="row"><label for="metrion_google_analytics_enable_tracking">Enable Google Analytics tracking</label></th> 471 <td> 472 <label class="switch"> 473 <input type="checkbox" id="metrion_google_analytics_enable_tracking" name="metrion_google_analytics_enable_tracking" value="1" <?php checked(1, get_option('metrion_google_analytics_enable_tracking', 0)); ?> > 474 <span class="slider round"></span> 475 </label> 476 </td> 477 </tr> 478 <tr valign="top"> 479 <th scope="row"><label for="metrion_google_analytics_measurement_id">Google Analytics Measurement ID</label></th> 480 <td> 481 <input type="text" id="metrion_google_analytics_measurement_id" name="metrion_google_analytics_measurement_id" 482 value="<?php echo esc_attr(get_option('metrion_google_analytics_measurement_id', '')); ?>" /> 483 </td> 484 </tr> 485 <tr valign="top"> 486 <th scope="row"><label for="metrion_google_analytcs_api_key">Google Analytics API key</label></th> 487 <td> 488 <input type="text" id="metrion_google_analytcs_api_key" name="metrion_google_analytcs_api_key" 489 value="<?php echo esc_attr(get_option('metrion_google_analytcs_api_key', '')); ?>" /> 490 </td> 491 </tr> 492 </table> 493 </div> 494 460 495 461 496 <?php submit_button(); ?>
Note: See TracChangeset
for help on using the changeset viewer.