Plugin Directory

Changeset 3342931


Ignore:
Timestamp:
08/11/2025 02:06:50 PM (7 months ago)
Author:
metriondev
Message:

Version 1.5.5

Location:
metrion
Files:
53 added
15 edited

Legend:

Unmodified
Added
Removed
  • metrion/trunk/includes/event_capture.php

    r3300778 r3342931  
    1515}
    1616
     17add_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
    1727// Add tracking function to both hooks with appropriate source information
    1828add_action('woocommerce_checkout_order_processed', function($order_id) {
     
    2333    metrion_order_tracking($order_id, 'woocommerce_thankyou');
    2434}, 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 */
     42function 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
     54function 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
     61function 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
    25185
    26186function metrion_woocommerce_webhook_purchase($order_id, $triggered_by_hook = '') {
     
    167327    $meta_fbc = isset($_COOKIE['_fbc']) ? sanitize_text_field(wp_unslash($_COOKIE['_fbc'])) : '';
    168328
     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
    169362    // VAT/TAX calculations
    170363    $order_total = floatval($order->get_total());
     
    173366    $shipping_tax = floatval($order->get_shipping_tax());
    174367    $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    }
    175406
    176407    return array(
     
    200431        'meta_fbp'                  => $meta_fbp,
    201432        '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
    202438    );
    203439}
     
    308544        // Add detailed item data
    309545        $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()),
    315551            'url'           => get_permalink($product->get_id()),
    316             'quantity'      => $item->get_quantity(),
     552            'quantity'      => strval($item->get_quantity()),
    317553            '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]) : ''
    322558        ];
    323559    }
    324560
    325     // Google Ads Enhanced Purchase Conversion Tracking
    326     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 
    340561    // 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;
    342563
    343564    // Register a dummy script to ensure script execution
     
    354575}
    355576
    356 
    357 
    358577$purchase_only_tracking = get_option('metrion_purchase_only_tracking', 1);
    359 
    360578
    361579// Only trigger in non purchase-only mode
     
    440658            if($is_loop_item){
    441659                $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' => $currency
     660                    '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
    454672                ];
    455673                $metrion_loop_items[] = $product_data;
     
    458676            // Output the metrion_item_data span
    459677            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())) . '"
    465683                data-item_url="' . esc_url(get_permalink($product->get_id())) . '"
    466684                data-item_category_1="' . esc_attr(isset($nested_categories[0]) ? $nested_categories[0] : '') . '"
     
    517735   
    518736            // 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;
    520738   
    521739            // Register a dummy script to attach inline localized data
     
    556774        // If the cart is not empty, process cart items
    557775        if (!empty($cart)) {
    558             foreach ($cart as $cart_item) {
     776            foreach ($cart as $cart_item) { 
    559777                $product = $cart_item['data'];
    560778
     
    570788                // Add item data to the checkout items array
    571789                $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']),
    579797                    '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]) : ''
    584802                ];
    585803            }
     
    587805
    588806        // 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;
    590808
    591809        // Register a dummy script to ensure script execution
     
    634852                // Add item data to the basket items array
    635853                $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()),
    641859                    'url'           => get_permalink($product->get_id()),
    642                     'quantity'      => $cart_item['quantity'],
     860                    'quantity'      => strval($cart_item['quantity']),
    643861                    '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]) : ''
    648866                ];
    649867            }
     
    651869
    652870        // 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;
    654872
    655873        // Register a dummy script to ensure script execution
  • metrion/trunk/includes/initial.php

    r3300778 r3342931  
    22
    33if ( ! defined('ABSPATH') ) exit; // Exit if accessed directly
     4
     5define( 'GET_METRION_WPFILTER_CSP_NONCE', 'get_metrion_csp_nonce' );
    46
    57// 1. ENDPOINT REGISTRATION AND HANDLING
     
    7981        'allow_cookie_placement_before_explicit_consent' => get_option('metrion_allow_cookie_placement_before_explicit_consent', 0),
    8082
    81         // Google settings
     83        // Google Ads settings
    8284        'google_enable_tracking' => get_option('metrion_google_enable_tracking', 0),
    8385        'google_enforce_consent_mode' => get_option('metrion_enforce_google_consent_mode', 0),
     
    9496        'meta_test_event_code' => get_option('metrion_meta_test_event_code', ''),
    9597
     98        // Elementor settings
    9699        'elementor_form_tracking' => get_option('metrion_enable_elementor_form_tracking', 0),
    97100        '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', '')
    98106    ];
    99107}
     
    251259        ? sanitize_text_field( wp_unslash( $_COOKIE['_fbc'] ) )
    252260        : '';
     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        : '';
    253270    $mapped_data['event_body']['client_ip'] = metrion_get_user_ip(); // Assumed to be sanitized already
    254271    $mapped_data['event_body']['user_agent'] = isset($_SERVER['HTTP_USER_AGENT'])
    255272        ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) )
    256273        : '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;
    257295
    258296    // Enforce consent
     
    277315        unset($mapped_data['event_body']['meta_fbp']);
    278316        unset($mapped_data['event_body']['meta_fbc']);
     317        // Strip click id object
     318        unset($mapped_data['event_body']['click_ids']);
    279319    }
    280320
     
    410450    $expiration_timestamp = (time() + 86400 * $cookie_expiration) * 1000;
    411451
    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);
    414456}
    415457
    416458// Helper function to extend user id cookie
    417 function metrion_extend_cookie($cookie_name, $uuid, $cookie_expiration) {
     459function metrion_extend_cookie($cookie_name, $uuid, $cookie_expiration, $user_session_number) {
    418460    $expiration_timestamp = (time() + 86400 * $cookie_expiration) * 1000;
    419461
    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);
    422464}
    423465
    424466// Helper function to update identification (user cookie) values
    425467function 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'));
    427469    $user_cookie_expiration = (int) get_option('metrion_user_cookie_lifetime', 365);
    428470
    429471    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);
    431473    } else {
    432474        $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        }
    434497       
    435         // Ensure cookie has exactly two parts
    436         if ( count( $user_cookie_parts ) !== 2 ) {
    437             metrion_refresh_cookie( $user_cookie_name, $user_cookie_expiration );
    438             return;
    439         }
    440 
    441498        list( $uuid, $expiration_timestamp ) = array_pad( $user_cookie_parts, 2, '' );
    442499        $uuid = sanitize_text_field( $uuid ); // Sanitize UUID part
     
    445502        // Validate expiration timestamp
    446503        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);
    448505        } 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);
    450507        }
    451508    }
     
    542599        'installation_id' => get_option('metrion_installation_id', ''),
    543600        'user_cookie_name' => get_option('metrion_user_cookie_name', 'mtrn_uid'),
     601        'user_cookie_lifetime_milliseconds' => get_option('metrion_user_cookie_lifetime', 365) * 86400000,
    544602        'session_cookie_name' => get_option('metrion_session_cookie_name', 'mtrn_sid'),
    545         'cookie_expiration_milliseconds' => get_option('metrion_user_cookie_lifetime', 365) * 86400000,
    546603        'session_cookie_lifetime_milliseconds' => get_option('metrion_session_cookie_lifetime', 30) * 60000,
    547604        'event_id_name' => get_option('metrion_event_id_name', 'mtrn_eid'),
     
    575632        'elementor_excluded_forms' => get_option('metrion_elementor_excluded_forms', ''),
    576633        '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', '')
    578638    ]);
    579639}
  • metrion/trunk/includes/js_bundler.php

    r3300778 r3342931  
    228228    }
    229229
    230     if (get_option('metrion_meta_enable_tracking', false)) {
     230    if (get_option('metrion_meta_allow_front_end_pixel_tracking', false)) {
    231231        $source_files[] = $plugin_dir . 'js/meta/events.js';
    232232    }
     
    301301    }
    302302
    303     if (get_option('metrion_meta_enable_tracking', false)) {
     303    if (get_option('metrion_meta_allow_front_end_pixel_tracking', false)) {
    304304        $source_files[] = $plugin_dir . 'js/meta/events.js';
    305305    }
     
    412412            if (function_exists($callback)) {
    413413                $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                 }
    418414            }
    419415        }
  • metrion/trunk/js/cmp/cmplz/logic.js

    r3306539 r3342931  
    2323            "unix": new Date().getTime()
    2424        };
    25        
    2625        var encoded_cookie_value_based_on_cmplz = encodeURIComponent(JSON.stringify(cookie_data));
    27        
    28         // Set the marketing metrion cookie value for dynamic loading of destinations
    29         cmp_allow_marketing = window.metrion.helpers.get_cookie_value("cmplz_marketing") === "allow";
    3026
    3127        window.metrion.helpers.set_cookie(
     
    4743// Function that adds event listeners for the chosen CMP
    4844window.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            }
    4963
    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();
    5683        }
    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_domain
    81         );
    82 
    83         window.metrion.configuration.floodgate_open = true;
    84         window.metrion.configuration.cmp_update_handled = true;
    85         window.metrion.consent_manager.initial_consent_enforcement();
    8684    });
    8785
  • metrion/trunk/js/core/events.js

    r3307446 r3342931  
    33    configuration: {
    44        init_unix_timestamp: Date.now(),
     5        last_interaction_unix_timestamp_ms: Date.now(),
     6        cookie_value_separator: "--",
    57        user_cookie_name: metrion_api.user_cookie_name + "_js",
     8        user_cookie_lifetime_milliseconds: metrion_api.user_cookie_lifetime_milliseconds,
    69        session_cookie_name: metrion_api.session_cookie_name,
    710        session_cookie_lifetime_milliseconds: Number(metrion_api.session_cookie_lifetime_milliseconds),
     
    1518        cmp_selection: metrion_api.cmp_selection,
    1619        cmp_update_handled: false,
     20        session_start_handled: false,
    1721        floodgate_name: metrion_api.floodgate_name,
    1822        floodgate_open: false,
     
    3943                if (xhr.readyState === 4) { // 4 = request done
    4044                    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                        }
    4249                        callback(); // Call the next function after success
    4350                    } 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");
    4552                    }
    4653                }
    4754            };
    4855            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        },
    5066    },
    5167
     
    7086        },
    7187
    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 () {
    73125            var configuration = window.metrion.configuration;
    74126
     
    77129            }
    78130
    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 
    104131            if (window.metrion.session_manager.is_session_cookie_expired()) {
    105132                return window.metrion.session_manager.create_session_cookie();
    106133            }
    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];
    112138            window.metrion.helpers.set_cookie(configuration.session_cookie_name, updated_session_cookie_value, configuration.session_cookie_lifetime_milliseconds, "/", configuration.cookie_domain);
    113139
    114             return session_id;
     140            return session_cookie_values[0];
    115141        }
    116142    },
     
    121147            window.metrion.configuration.browser_support_safe_uuid = false;
    122148            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);
    124150            });
    125151        },
    126 
    127152        generate_uuid_secure: function () {
    128153            window.metrion.configuration.browser_support_safe_uuid = true;
    129154            return crypto.randomUUID();
    130155        },
    131 
    132156        generate_uuid: function () {
    133157            try {
     
    144168            return Math.floor(100000000 + Math.random() * 900000000).toString() + "." + new Date().getTime().toString();
    145169        },
    146 
    147170        get_cookie_value: function (cookie_name) {
    148171            var value = "; " + document.cookie;
     
    155178            return null;
    156179        },
    157 
    158180        set_cookie: function (cookie_name, cookie_value, cookie_lifetime_in_milliseconds, cookie_path, cookie_domain) {
    159181            var cookie_secure = ";secure";
     
    162184            var d = new Date();
    163185            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        },
    167188        get_url_parameter_value: function (url_parameter_name) {
    168189            var urlParams = new URLSearchParams(window.location.search);
    169190            return urlParams.get(url_parameter_name) || null;
    170191        },
    171 
    172192        log_debug: function (message, type) {
    173193            type = type || "log"; // Default parameter handling for ES5 compatibility
     
    189209            }
    190210        },
    191 
    192211        hash: async function (input) {
    193212            if (!input) { return "" }
     
    198217            }
    199218        },
     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        }
    200267    },
    201268
     
    262329           
    263330            /// 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               
    265335           
    266336            // Evaluate floodgate after to trigger the Metrion events
     
    297367            window.metrion.helpers.log_debug(("Collected floodgated events: " + floodgate_events.length.toString()), "log");
    298368
    299             // Ensure session management logic executes early
    300             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 
    306369            // 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") {
    308371                sessionStorage.setItem(window.metrion.configuration.session_info_storage_name, window.metrion.session_info);
    309372            }
     
    341404            window.metrion.helpers.log_debug(("Evaluation finished with floodgate status: " + window.metrion.configuration.floodgate_open.toString()), "log");
    342405            // 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) {
    344407                window.metrion.user_manager.ensure_user_cookie_existance(function () {
    345408                    window.metrion.helpers.log_debug("Dynamic user cookie ensuration function called", "log");
     
    357420            var metrion_consent_cookie = window.metrion.helpers.get_cookie_value(window.metrion.configuration.consent_cookie_name);
    358421            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));
    360423                window.metrion.configuration.blocking_detected = "0";                    // No blocking detected by default
    361424                if(JSON.parse(decodeURIComponent(metrion_consent_cookie)).b === "1"){
    362425                    window.metrion.configuration.blocking_detected = "1";
    363426                }
    364                 updated_consent_object = consent_object;
     427                var updated_consent_object = consent_object;
    365428                // Add the blocking parameter
    366429                updated_consent_object.b = window.metrion.configuration.blocking_detected;
     
    389452        var current_stored_event = stored_event;
    390453        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        }
    392462        var allow_uid = metrion_consent_cookie_value.allow_uid === "1";
    393463        var allow_sid = metrion_consent_cookie_value.allow_sid === "1";
     
    395465        // Apply consent settings on floodgated events
    396466        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];
    398469        }
    399470        else {
     
    401472        }
    402473        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];
    404475        }
    405476        else {
     
    417488        current_stored_event["event_body"]["floodgated"] = true;
    418489        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"];
    419494
    420495        // Prepare for data sending to API
     
    452527            "query": window.location.search || "",
    453528            "hash": window.location.hash || "",
    454             "referrer": document.referrer || ""
     529            "referrer": document.referrer || "",
     530            "title": document.title || ""
    455531        };
    456532        event_data["event_body"] = event_body || {};
    457533        event_data["event_body"]["browser_support_safe_uuid"] = window.metrion.configuration.browser_support_safe_uuid;
    458534        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        }
    459543
    460544        // If consent cookie is available and floodgate open, handle based on the metrion consent cookie. Otherwise the event will be floodgated later
    461545        window.metrion.helpers.log_debug(("Floodgate open:  " + window.metrion.configuration.floodgate_open.toString()), "log");
    462546        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");
    464548
    465549        // Only push events to the metrion API if the floodgates are open!
     
    467551            // First check consent information
    468552            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            }
    470557            var allow_uid = metrion_consent_cookie_value.allow_uid === "1";
    471558            var allow_sid = metrion_consent_cookie_value.allow_sid === "1";
    472559            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];
    474561            }
    475562            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];
    477564            }
    478565
     
    505592        // Floodgate closed, store event behind floodgate and send ping
    506593        else {
    507             if (metrion.configuration.allow_pings === "1"){
     594            if (window.metrion.configuration.allow_pings === "1"){
    508595                //Trigger the ping
    509596                this.send_ping(event_name, event_data);
     
    547634    // JS session definition logic
    548635    session_event_logic: function () {
     636        window.metrion.helpers.log_debug("Start session logic function", "log");
     637
    549638        // 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") {
    551644            return;
    552645        }
     646
    553647        // Payment session exclusions
    554648        var payment_referrer_exclusions = [
     
    603697            "gclid", "hsCtaTracking", "mc_eid", "mkt_tok", "ml_subscriber", "ml_subscriber_hash",
    604698            "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"
    606701        ];
    607702
     
    647742
    648743
    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++) {
    650745                click_id_cookie_value[detected_advertising_params[advertising_param_i]] = window.metrion.helpers.get_url_parameter_value(detected_advertising_params[advertising_param_i]);
    651746            }
     
    675770        var duplicate_session_start = false;
    676771        if (window.metrion.configuration.session_start_trigger
    677             && sessionStorage
     772            && typeof sessionStorage !== "undefined"
    678773            && window.metrion.configuration.floodgate_open) {
    679774            var current_session_info = JSON.stringify({
     
    710805        }
    711806
     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
    712814        // Metrion default session evaluation
    713         if (window.metrion.configuration.session_start_trigger && !duplicate_session_start) {
     815        if (!duplicate_session_start) {
    714816            if (window.metrion.configuration.allow_cookie_placement_before_explicit_consent === "1"
    715817                && !window.metrion.configuration.floodgate_open
     818                && window.metrion.configuration.session_start_trigger
    716819            ) {
    717820                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
    725846    },
    726847    // JS pageview event logic
  • metrion/trunk/js/detect/detect.js

    r3300778 r3342931  
    88    is_privacy_browser: false,
    99    google_analytics_blocked: false,
    10     google_ads_blocked: false
     10    google_ads_blocked: false,
     11    non_interaction: "1"
    1112};
    1213
  • metrion/trunk/js/google_ads/events.js

    r3307446 r3342931  
    11//Prevent overwriting of objects and preserve existing properties
    22window.metrion.google_ads = window.metrion.google_ads || {};
    3 
     3window.metrion.google_ads.initialized = false;
    44// Initialize the Google Ads tracking script
    55window.metrion.google_ads.init = function(){
     6    //Exit early if already initialized
     7    if (window.metrion.google_ads.initialized){
     8        return;
     9    }
    610    // Ensure that Metrion's API and configuration are available before proceeding
    711    if(window.metrion_api && window.metrion){
     
    1923            // Check broker que for the initial events
    2024            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 ++){
    2226                    // Get the specific event
    2327                    var queued_event = window.metrion.configuration.event_broker_queue[i];
     
    3943        // Check if gtag exist
    4044        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
    4149            // Dynamically and Async loading of gtag script
    4250            var gtag_script = document.createElement('script');
     
    4553            document.body.appendChild(gtag_script);
    4654           
    47             // Initialize gtag once the script is loaded
     55            // Onload just initializes config and conversion
    4856            gtag_script.onload = function() {
    49                 window.dataLayer = window.dataLayer || [];
    50                 window.gtag = function(){dataLayer.push(arguments);}
    5157                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);
    5359                start_google_ads_event_handling();
    54             }
     60            };
    5561        }
    5662        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            }
    5866            window.gtag('config', (window.metrion_api.google_ads_tag_id));
    5967            start_google_ads_event_handling();
    6068        }
    61     }
     69
     70        // End initialization with changing the init variable
     71        window.metrion.google_ads.initialized = true;
     72    }
     73   
    6274};
    6375
    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
     77window.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   
    6681    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) {
    6885            return true;
    6986        }
    7087    }
     88
    7189    return false;
    7290};
     91
     92// Checks if the 'js' event is already available in the dataLayer
     93window.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}
    73107
    74108// Function to monitor event queue and trigger callback when new events are pushed
     
    80114    arr.push = function(e) {
    81115        var google_ads_events_of_interest = [
    82             "purchase",
     116            //"purchase", > Handled directly in the purchase script outside of broker
    83117            "form_submit"
    84118        ];
     
    86120        // See list here: https://support.google.com/google-ads/answer/7305793?hl=en
    87121        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([
    89123                "view_search_results",
    90124                "view_item",
     
    117151    if(window.metrion_api && window.metrion && typeof window.gtag != "undefined"){
    118152
     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
    119231        // DYNAMIC REMARKETING
    120232        // Check if dynamic remarketing is enabled if that is the case, send the remarketing tag
     
    158270                if(typeof event_data.event_body.items !== "undefined" && event_data.event_body.items.length > 0){
    159271                    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 ++ ){
    161273                        google_ads_items.push({
    162274                            id: event_data.event_body.items[google_ads_item_i].id,
     
    184296                if(typeof event_data.event_body.items !== "undefined" && event_data.event_body.items.length > 0){
    185297                    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 ++ ){
    187299                        google_ads_items.push({
    188300                            id: event_data.event_body.items[google_ads_item_i].id,
     
    206318                var collective_value = 0;
    207319                // 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 ++ ){
    209321                    google_ads_items.push({
    210322                        id: event_data.event_body.items[google_ads_item_i].id,
     
    226338                // Loop through all items to get the collective parameters necessary for Google Ads dynamic remarketing
    227339                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 ++ ){
    229342                    google_ads_items.push({
    230343                        id: event_data.event_body.items[google_ads_item_i].id,
     
    243356            }
    244357        }   
    245      
    246         // ENHANCED PURCHASE
    247         // Process purchase events
    248         if(event_name === "purchase"){
    249             // Send conversion event to Google Ads
    250             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_id
    255             });
    256 
    257             // GOOGLE ADS CONTEXT CHECKS
    258             // First Check if recent relevant click-ids are stored
    259             var google_ads_click_id = undefined;
    260 
    261             try{
    262                 //Parse the cookie if it exists
    263                 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 conversion
    270             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 deduplication
    276             // 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 conversions
    278             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.email
    295             });
    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_id
    307             }, {});
    308         }
    309358    }
    310359};
  • metrion/trunk/js/meta/events.js

    r3316153 r3342931  
    8181                collective_currency = event_data.event_body.items[0].currency; // Get from the first item
    8282                // 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);
    8486                    item_contents.push({
    8587                        id: event_data.event_body.items[meta_item_i].id,
    86                         quantity: event_data.event_body.items[meta_item_i].quantity
     88                        quantity: current_item_quantity
    8789                    });
    8890                    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);
    9193                }
    9294            }
     
    117119                    content_ids: [event_data.event_body.items[0].id],
    118120                    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),
    120122                    currency: event_data.event_body.items[0].currency,
    121123                    contents: [{
    122124                        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                },
    125128                {
    126129                    eventID: event_data[window.metrion_api.event_id_name]
     
    137140                    content_ids: [event_data.event_body.items[0].id],
    138141                    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),
    140143                    currency: event_data.event_body.items[0].currency,
    141144                    contents: [{
    142145                        id: event_data.event_body.items[0].id,
    143                         quantity: event_data.event_body.items[0].quantity
     146                        quantity: 1 // Set to 1
    144147                    }]
    145148                },
     
    158161                var collective_currency = event_data.event_body.items[0].currency; // Get from the first item
    159162                // 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);
    161166                    item_contents.push({
    162167                        id: event_data.event_body.items[meta_item_i].id,
    163                         quantity: event_data.event_body.items[meta_item_i].quantity
     168                        quantity: current_item_quantity
    164169                    });
    165170                    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);
    168173                }
    169174                window.fbq('trackSingle', window.metrion_api.meta_pixel_id, "InitiateCheckout", {
     
    191196               
    192197                // 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);
    194201                    item_contents.push({
    195202                        id: event_data.event_body.items[meta_item_i].id,
    196                         quantity: event_data.event_body.items[meta_item_i].quantity
     203                        quantity: current_item_quantity
    197204                    });
    198205                    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);
    201208                }
    202209
     
    212219                },
    213220                {
    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,
    215223                });
    216224            }
  • metrion/trunk/js/microsoft_ads/events.js

    r3290502 r3342931  
    99       
    1010        //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"){
    1212            // Update consent mode to granted (this script can only be loaded if consent mode is granted)
    1313            window.metrion.microsoft_ads.set_consent_mode_to_granted();
     
    239239            "enable_detection": window.metrion_api.enable_detection,
    240240            "b": block_detected,
    241             "trigger_type": "front-end"
     241            "trigger_type": "front-end",
     242            "non_interaction": "1"
    242243        }, {});
    243244    }
  • metrion/trunk/js/settings/settings.js

    r3300778 r3342931  
    4949        meta_ads_button.textContent = `Meta Ads Configuration Settings ${isHiddenMetaAds ? '▲' : '▼'}`;
    5050    });
     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    });
    5161});
  • metrion/trunk/js/woo/other_events.js

    r3300778 r3342931  
    44// JS Woocommerce other event logic
    55window.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       
    10956                    var product_data = {
    11057                        "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 page
     58                        "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,
    11865                        "currency": currency,
    11966                        "category_1": category_1,
     
    12269                        "category_4": category_4
    12370                    };
    124 
    125                     // Send data to Metrion for item view event
     71       
     72                    // Send data to Metrion
    12673                    if (typeof metrion !== "undefined" && typeof metrion.send_event === "function") {
    127                         metrion.send_event("item_view", {
     74                        metrion.send_event("add_to_cart", {
    12875                            "items": [product_data],
    12976                            "trigger_type": "front-end"
     
    13279                        console.error("Metrion is not available or send_event function is missing.");
    13380                    }
    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                }
    18384            });
    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        });
    198201    });
    199202};
  • metrion/trunk/js/woo/purchase_event.js

    r3300778 r3342931  
    11// Prevent overwriting of objects and preserve existing properties
    22window.metrion = window.metrion || {};
    3 
     3// Set the flag globally on the window to retain its state across page reloads
     4window.metrion.woocommerce_purchase_logic_triggered = false;
    45// Woocommerce Purchase event logic
    56window.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
    816        // Purchase
    917        // Ensure purchase_data is available
     
    1826                "coupons": window.metrion_purchase_data.coupons
    1927            }
    20             //Add destination specific logic
    21             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             }
    2628
    2729            // Example: Send purchase data to an analytics system
    2830            window.metrion.send_event("purchase", purchase_event_body);
     31            window.metrion.woocommerce_purchase_logic_triggered = true;
    2932        } else {
    3033            window.metrion.helpers.log_debug("Purchase data is not available.", "log");
    3134        }
     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        }
    3262    });
     63
    3364};
    3465// Call the function
  • metrion/trunk/main.php

    r3316153 r3342931  
    33* Plugin Name:          Metrion
    44* Description:          Skip manual implementation, sync data directly tailored to destinations like Google Ads and Meta Ads.
    5 * Version:              1.5.3
     5* Version:              1.5.5
    66* Author:               Metrion
    77* Author URI:           https://getmetrion.com
     
    1212if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
    1313
    14 define('GLOBAL_METRION_PLUGIN_VERSION', '1.5.3');
     14define('GLOBAL_METRION_PLUGIN_VERSION', '1.5.5');
    1515
    1616// Register plugin settings for webhook URL, API path, debug mode, cookie name, and expiration time
     
    7575    add_option('metrion_microsoft_ads_tag_id', '');                                         // Open field for Microsoft Ads UET Tag ID
    7676
     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
    7782    // Register the Metrion settings
    7883    register_setting('metrion_options_group', 'metrion_data_collection', ['sanitize_callback' => 'rest_sanitize_boolean']);
     
    139144    register_setting('metrion_options_group', 'metrion_meta_test_event_code', ['sanitize_callback' => 'sanitize_text_field']);
    140145
     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']);
    141150}
    142151
  • metrion/trunk/readme.txt

    r3316153 r3342931  
    44Requires at least: 3.8
    55Tested up to: 6.8
    6 Stable tag: 1.5.3
     6Stable tag: 1.5.5
    77Requires PHP: 7.1
    88License: GPLv3 or later
     
    3838* Microsoft Ads consent mode
    3939* Microsoft Ads dynamic remarketing list functionality
     40* Google Analytics 4 sever-side
    4041
    4142== Installation ==
     
    8687
    8788== 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.
    8899
    89100= 1.5.3 =
  • metrion/trunk/views/settings.php

    r3300778 r3342931  
    373373            <table class="metrion-settings-meta-ads metrion-settings-advanced">
    374374                <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>
    376376                    <td>
    377377                        <label class="switch">
     
    458458            </table>
    459459        </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
    460495
    461496        <?php submit_button(); ?>
Note: See TracChangeset for help on using the changeset viewer.