Index: /kluvos/tags/2.1.0/assets/js/kluvos-checkout.js
===================================================================
--- /kluvos/tags/2.1.0/assets/js/kluvos-checkout.js	(revision 3406442)
+++ /kluvos/tags/2.1.0/assets/js/kluvos-checkout.js	(revision 3406442)
@@ -0,0 +1,186 @@
+/**
+ * Kluvos Checkout Tracking
+ *
+ * Sends checkout events to the Kluvos tracking API.
+ * Checkout data is passed from PHP via wp_localize_script.
+ */
+(function() {
+    'use strict';
+
+    /**
+     * Helper to read a cookie value.
+     * @param {string} name Cookie name.
+     * @returns {string} Cookie value or empty string.
+     */
+    function getCookie(name) {
+        var value = '; ' + document.cookie;
+        var parts = value.split('; ' + name + '=');
+        if (parts.length === 2) {
+            return parts.pop().split(';').shift();
+        }
+        return '';
+    }
+
+    /**
+     * Extract Klaviyo Exchange ID from URL parameter or cookie.
+     * @returns {string} Exchange ID string.
+     */
+    function getKlaviyoExchangeId() {
+        try {
+            var urlParams = new URLSearchParams(window.location.search);
+            var kxParam = urlParams.get('_kx');
+            if (kxParam) {
+                return kxParam.trim();
+            }
+        } catch (error) {
+            // Ignore URL parsing errors silently.
+        }
+
+        try {
+            var klaviyoCookie = document.cookie.split('; ').find(function(cookie) {
+                return cookie.indexOf('__kla_id=') === 0;
+            });
+
+            if (klaviyoCookie) {
+                var cookieValue = klaviyoCookie.split('__kla_id=')[1];
+                if (cookieValue) {
+                    var decoded = atob(cookieValue);
+                    var data = JSON.parse(decoded);
+                    if (data && data.$exchange_id) {
+                        return data.$exchange_id.toString().trim();
+                    }
+                }
+            }
+        } catch (error) {
+            // Ignore cookie parsing errors silently.
+        }
+
+        return '';
+    }
+
+    /**
+     * Normalize checkout payload for API submission.
+     * @param {Object} checkoutData Localized checkout data from PHP.
+     * @returns {Object|null} Payload ready to send or null if invalid.
+     */
+    function buildCheckoutPayload(checkoutData) {
+        if (!checkoutData || !checkoutData.property_token) {
+            return null;
+        }
+
+        var sessionCookie = getCookie('_kpixel_s');
+        var fbc = (getCookie('_fbc') || '').trim();
+        var fbp = (getCookie('_fbp') || '').trim();
+        var ltCookie = (getCookie('_kpixel_lt') || '').trim();
+        var kx = getKlaviyoExchangeId();
+
+        var metadata = {
+            fbc: fbc,
+            kx: kx,
+            fbp: fbp,
+            lt_cookie: ltCookie
+        };
+
+        var cartItems = Array.isArray(checkoutData.cart_items) ? checkoutData.cart_items : [];
+        var normalizedItems = cartItems.map(function(item) {
+            return {
+                key: item && item.key ? item.key : '',
+                product_id: item && item.product_id ? parseInt(item.product_id, 10) || 0 : 0,
+                variation_id: item && item.variation_id ? parseInt(item.variation_id, 10) || 0 : 0,
+                sku: item && item.sku ? item.sku : '',
+                name: item && item.name ? item.name : '',
+                variation_name: item && item.variation_name ? item.variation_name : '',
+                quantity: item && item.quantity ? parseInt(item.quantity, 10) || 0 : 0,
+                unit_price: item && item.unit_price ? item.unit_price : '',
+                line_subtotal: item && item.line_subtotal ? item.line_subtotal : '',
+                line_total: item && item.line_total ? item.line_total : '',
+                line_tax: item && item.line_tax ? item.line_tax : '',
+                product_url: item && item.product_url ? item.product_url : '',
+                image_url: item && item.image_url ? item.image_url : '',
+                attributes: item && item.attributes ? item.attributes : {}
+            };
+        });
+
+        var cartTotals = checkoutData.cart_totals || {};
+        var currencyCode = checkoutData.currency_code || 'USD';
+        var currencySymbol = checkoutData.currency_symbol || '';
+        var categories = Array.isArray(checkoutData.categories) ? checkoutData.categories : [];
+
+        return {
+            property_token: checkoutData.property_token,
+            origin: checkoutData.origin || window.location.href,
+            metadata: metadata,
+            session_cookie: sessionCookie || checkoutData.session_cookie || '',
+            time_utc: new Date().toISOString(),
+            Currency: currencyCode,
+            CurrencySymbol: currencySymbol,
+            Categories: categories,
+            checkout_data: {
+                store_url: checkoutData.store_url || '',
+                checkout_url: checkoutData.checkout_url || '',
+                currency_code: currencyCode,
+                cart_items: normalizedItems,
+                cart_totals: cartTotals,
+                customer: checkoutData.customer || {}
+            }
+        };
+    }
+
+    /**
+     * Send checkout payload to API endpoint.
+     * @param {Object} payload Checkout payload.
+     * @returns {Promise<void>}
+     */
+    function sendCheckoutPayload(payload) {
+        if (!payload || !payload.property_token) {
+            return;
+        }
+
+        var apiBaseUrl = (typeof kluvosCheckoutConfig !== 'undefined' && kluvosCheckoutConfig.apiBaseUrl)
+            ? kluvosCheckoutConfig.apiBaseUrl
+            : 'https://track.kluvos.com';
+
+        var endpoint = apiBaseUrl.replace(/\/+$/, '') + '/api/v1/woocommerce_events/checkouts';
+
+        if (typeof window.Kluvos !== 'undefined' && typeof window.Kluvos.track === 'function') {
+            window.Kluvos.track('checkout_started', payload);
+            return;
+        }
+
+        fetch(endpoint, {
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json; charset=utf-8'
+            },
+            body: JSON.stringify(payload)
+        }).catch(function(error) {
+            // Surface the error only in debug scenarios to avoid breaking checkout UX.
+            if (window.console && console.error) {
+                console.error('Kluvos: Error sending checkout event', error);
+            }
+        });
+    }
+
+    window.addEventListener('load', function() {
+        if (typeof kluvosCheckoutConfig === 'undefined' || !kluvosCheckoutConfig.checkoutData) {
+            return;
+        }
+
+        var payload = buildCheckoutPayload(kluvosCheckoutConfig.checkoutData);
+        if (!payload) {
+            return;
+        }
+
+        // Require at least one customer identifier before sending.
+        var hasEmail = payload.checkout_data && payload.checkout_data.customer && payload.checkout_data.customer.email;
+        var hasSession = payload.session_cookie && payload.session_cookie.length > 0;
+        var hasKx = payload.metadata && payload.metadata.kx;
+
+        if (!hasEmail && !hasSession && !hasKx) {
+            return;
+        }
+
+        sendCheckoutPayload(payload);
+    });
+})();
+
Index: /kluvos/tags/2.1.0/assets/js/kluvos-viewed-product.js
===================================================================
--- /kluvos/tags/2.1.0/assets/js/kluvos-viewed-product.js	(revision 3406442)
+++ /kluvos/tags/2.1.0/assets/js/kluvos-viewed-product.js	(revision 3406442)
@@ -0,0 +1,196 @@
+/**
+ * Kluvos Viewed Product Tracking
+ *
+ * Tracks product view events using Kluvos tracking API.
+ * Product data is passed via wp_localize_script from PHP.
+ *
+ * @typedef {Object} kluvosProductData
+ *   @property {string} url - Product permalink
+ *   @property {string} store_url - Store base URL (used as origin and for property lookup)
+ *   @property {string} name - Product name
+ *   @property {string} variant_name - Product variant name
+ *   @property {string} brand - Site brand name
+ *   @property {float} price - Product price
+ *   @property {string} image_url - Product image URL
+ *   @property {array} categories - Product categories (array of strings)
+ *   @property {int} product_id - Product ID
+ *   @property {float} compare_at_price - Product compare at price
+ *   @property {string} property_token - Kluvos property token
+ */
+
+(function() {
+    'use strict';
+
+    /**
+     * Helper function to get cookie value
+     * @param {string} name - Cookie name
+     * @returns {string} Cookie value or empty string
+     */
+    function getCookie(name) {
+        var value = "; " + document.cookie;
+        var parts = value.split("; " + name + "=");
+        if (parts.length === 2) {
+            return parts.pop().split(";").shift();
+        }
+        return '';
+    }
+
+    /**
+     * Get Klaviyo Exchange ID (kx) value
+     * Priority 1: Check for _kx URL parameter
+     * Priority 2: Extract $exchange_id from Klaviyo's __kla_id cookie
+     * @returns {string} Exchange ID or empty string if not found
+     */
+    function getKlaviyoExchangeId() {
+        // Priority 1: Check for _kx URL parameter (Klaviyo Exchange ID from email links)
+        try {
+            var urlParams = new URLSearchParams(window.location.search);
+            var kxParam = urlParams.get('_kx');
+            if (kxParam) {
+                return kxParam.trim();
+            }
+        } catch (error) {
+            // Silently fail - URLSearchParams might not be available in older browsers
+        }
+
+        // Priority 2: Extract $exchange_id from Klaviyo's __kla_id cookie
+        // Cookie format: base64-encoded JSON with $exchange_id field
+        try {
+            var klaviyoCookie = document.cookie.split('; ').find(function(c) {
+                return c.indexOf('__kla_id=') === 0;
+            });
+
+            if (klaviyoCookie) {
+                var cookieValue = klaviyoCookie.split('__kla_id=')[1];
+                if (cookieValue) {
+                    var decoded = atob(cookieValue);
+                    var data = JSON.parse(decoded);
+                    var exchangeId = data.$exchange_id;
+
+                    if (exchangeId) {
+                        return exchangeId.toString().trim();
+                    }
+                }
+            }
+        } catch (error) {
+            // Silently fail - cookie might be malformed or not exist
+        }
+
+        // Return empty string if nothing found (matches metadata structure)
+        return '';
+    }
+
+    /**
+     * Track product view event
+     * @param {kluvosProductData} productData - Product data from PHP
+     * Note: wp_localize_script converts all values to strings, so we need to
+     * re-parse ints and floats (like Klaviyo does)
+     */
+    function trackProductView(productData) {
+        // Check if property_token is set
+        if (!productData || !productData.property_token) {
+            return;
+        }
+
+        // Get session cookie
+        var sessionCookie = getCookie('_kpixel_s');
+
+        // Extract metadata cookies (sanitize by trimming whitespace)
+        var fbc = (getCookie('_fbc') || '').trim();
+        var fbp = (getCookie('_fbp') || '').trim();
+        var ltCookie = (getCookie('_kpixel_lt') || '').trim();
+        var kx = getKlaviyoExchangeId(); // Get Klaviyo Exchange ID from URL param or cookie
+
+        // Build metadata object
+        var metadata = {
+            fbc: fbc,
+            kx: kx,
+            fbp: fbp,
+            lt_cookie: ltCookie
+            // Note: ip_address and user_agent are handled server-side
+        };
+
+        // Parse numeric values (wp_localize_script converts everything to strings)
+        var productId = parseInt(productData.product_id, 10);
+        var price = parseFloat(productData.price) || 0;
+        var compareAtPrice = parseFloat(productData.compare_at_price) || 0;
+
+        // Prepare flattened payload structure (all product data at top level)
+        var storeUrl = productData.store_url || '';
+        var currencyCode = productData.currency_code || 'USD';
+
+        // Build payload structure with product_data object containing flattened product fields
+        var payload = {
+            property_token: productData.property_token || '',
+            origin: storeUrl || '',
+            metadata: metadata,
+            session_cookie: sessionCookie || '',
+            time_utc: new Date().toISOString(),
+            product_data: {
+                url: productData.url || '',
+                name: productData.name || '',
+                brand: productData.brand || '',
+                price: price.toString(),
+                image_url: productData.image_url || '',
+                categories: productData.categories || [],
+                product_id: productId,
+                variant_name: productData.variant_name || '',
+                compare_at_price: compareAtPrice ? compareAtPrice.toString() : '',
+                sku: productData.sku || '',
+                currency_code: currencyCode
+            }
+        };
+
+        // Check if Kluvos tracking API is available
+        if (typeof window.Kluvos !== 'undefined' && typeof window.Kluvos.track === 'function') {
+            // Use Kluvos tracking API - pass the flattened payload
+            window.Kluvos.track('product_view', payload);
+        } else {
+            // Fallback: Send directly via fetch to Rails API endpoint
+            // Get API URL from config (passed from PHP) or fallback to production
+            var apiBaseUrl = (typeof kluvosConfig !== 'undefined' && kluvosConfig.apiBaseUrl) 
+                ? kluvosConfig.apiBaseUrl 
+                : 'https://track.kluvos.com';
+            
+            fetch(apiBaseUrl + '/api/v1/woocommerce_events/product_views', {
+                method: 'POST',
+                headers: {
+                    'Content-Type': 'application/json; charset=utf-8'
+                },
+                body: JSON.stringify(payload)
+            }).catch(function(error) {
+                console.error('Kluvos: Error sending product view event', error);
+            });
+        }
+    }
+
+    // Wait for page load and track product view
+    window.addEventListener('load', function() {
+        // Check if kluvosConfig.productData is available (passed via wp_localize_script)
+        if (typeof kluvosConfig !== 'undefined' && kluvosConfig.productData) {
+            // If Kluvos API is available, use it (it handles cookie timing)
+            if (typeof window.Kluvos !== 'undefined' && typeof window.Kluvos.track === 'function') {
+                trackProductView(kluvosConfig.productData);
+            } else {
+                // Wait for the external script to load and set cookies
+                // This handles the first-page-load case where the cookie isn't set yet
+                var retries = 0;
+                var maxRetries = 10; // Try for up to 2 seconds (10 * 300ms)
+                var retryInterval = 300; // Check every 300ms
+                
+                var checkCookie = setInterval(function() {
+                    retries++;
+                    var sessionCookie = getCookie('_kpixel_s');
+                    
+                    if (sessionCookie || retries >= maxRetries) {
+                        clearInterval(checkCookie);
+                        // Send the event (even if cookie is still missing after retries)
+                        trackProductView(kluvosConfig.productData);
+                    }
+                }, retryInterval);
+            }
+        }
+    });
+
+})();
+
Index: /kluvos/tags/2.1.0/kluvos.php
===================================================================
--- /kluvos/tags/2.1.0/kluvos.php	(revision 3406442)
+++ /kluvos/tags/2.1.0/kluvos.php	(revision 3406442)
@@ -0,0 +1,1250 @@
+<?php
+/*
+* Plugin Name: Kluvos
+* Description: Official plugin for Kluvos.
+* Author: Kluvos, LLC
+* Version: 2.1.0
+* Requires at least: 1.0
+* Tested up to: 6.9
+* Stable tag: 2.1.0
+* Requires PHP: 7.0
+* License: GPLv2 or later
+* License URI: https://www.gnu.org/licenses/gpl-2.0.html
+*/
+
+if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
+
+// ========== API CONFIGURATION ==========
+// Kluvos API Base URL Configuration
+// Defaults to production. Override in wp-config.php for local development:
+// define('KLUVOS_API_BASE_URL', 'https://dev.track.kluvos.com');
+if (!defined('KLUVOS_API_BASE_URL')) {
+    define('KLUVOS_API_BASE_URL', 'https://track.kluvos.com');
+}
+
+/**
+ * Get Kluvos API base URL with validation
+ * Validates the constant value and falls back to production if invalid
+ * 
+ * @return string API base URL (always returns a valid URL)
+ */
+function kluvos_get_api_base_url() {
+    // Get the constant value
+    $url = defined('KLUVOS_API_BASE_URL') ? KLUVOS_API_BASE_URL : 'https://track.kluvos.com';
+    
+    // Validate it's a non-empty string
+    if (empty($url) || !is_string($url)) {
+        return 'https://track.kluvos.com'; // Fallback to production
+    }
+    
+    // Basic URL validation (ensure it starts with http:// or https://)
+    if (!preg_match('#^https?://#', $url)) {
+        return 'https://track.kluvos.com'; // Fallback if invalid format
+    }
+    
+    return $url;
+}
+// =======================================
+
+add_action('wp_loaded', 'kluvos_init_plugin');
+add_action('admin_notices', 'kluvos_plugin_admin_notice' );
+add_action('rest_api_init', function () {
+    register_rest_route('kluvos/v1', '/save-options', array(
+        'methods' => 'POST',
+        'callback' => 'kluvos_save_options',
+        'permission_callback' => '__return_true', // No permission check for simplicity
+    ));
+});
+
+
+
+
+
+function kluvos_init_plugin() {
+
+    // Fetch the entire options array
+    $options = get_option('kluvos_plugin_options');
+
+
+
+    // Access the property_id and property_token from the options array
+    $property_id = isset($options['property_id']) ? $options['property_id'] : '';
+    $property_token = isset($options['property_token']) ? $options['property_token'] : '';
+
+
+    // Check if both property_id and property_token are set
+    if ( empty($property_id) || empty($property_token) ) {
+        // You can also add an admin notice here if needed
+        return;
+    }
+
+      // Check for WooCommerce dependency
+      if (!function_exists('WC')) {
+        return;
+    }
+
+    if (!is_admin()) {
+        kluvos_enqueue_woocommerce_script($property_token);
+    }
+
+    // Hook to enqueue script on frontend only (wp_enqueue_scripts doesn't fire in admin)
+    add_action( 'wp_enqueue_scripts', 'kluvos_enqueue_woocommerce_script' );
+
+    add_filter( 'script_loader_tag', 'kluvos_customize_script_tag', 10, 3 );
+
+    add_action('woocommerce_add_to_cart', 'kluvos_send_add_to_cart_data_to_server', 10, 6);
+    add_action('woocommerce_thankyou', 'kluvos_send_order_to_server', 10, 1);
+
+    add_action('wp_enqueue_scripts', 'kluvos_output_checkout_data_for_js');
+    // Hook into wp_enqueue_scripts to enqueue product view tracking (works with caching)
+    add_action('wp_enqueue_scripts', 'kluvos_output_product_data_for_js');
+
+}
+
+##
+##ALERT NOTICES
+##
+
+function kluvos_plugin_admin_notice() {
+    // Fetch the entire options array
+    $options = get_option('kluvos_plugin_options');
+
+    // Access the property_id and property_token from the options array
+    $property_id = isset($options['property_id']) ? $options['property_id'] : '';
+    $property_token = isset($options['property_token']) ? $options['property_token'] : '';
+
+
+    // Check if WooCommerce is not active
+    if (!class_exists('WooCommerce')) {
+        ?>
+        <div class="notice notice-warning is-dismissible">
+            <p><?php esc_html_e('Error: WooCommerce is not active. The Kluvos plugin requires WooCommerce to function.', 'kluvos'); ?></p>
+            <p>
+                <a href="https://kluvos.com" class="button button-primary"><?php esc_html_e('Visit Kluvos', 'kluvos'); ?></a>
+            </p>
+        </div>
+        <?php
+    } elseif (empty($property_id) || empty($property_token)) {
+        // Check if both property_id and property_token are set
+        ?>
+        <div class="notice notice-error is-dismissible">
+            <h2><?php esc_html_e('Kluvos Plugin', 'kluvos'); ?></h2>
+            <p><?php esc_html_e('In order to use the Kluvos plugin, you must have a Kluvos account. If you do not have one, setting one up is quick and easy!', 'kluvos'); ?></p>
+            <p> <a href="https://kluvos.com/users/sign_up" class="button button-primary"><?php esc_html_e('Create Account', 'kluvos'); ?></a>
+            </p>
+            <p> <?php esc_html_e('Otherwise, please authenticate Kluvos with your WooCommerce store. This can be done in the Set-Up menu inside your Kluvos dashboard.', 'kluvos'); ?></p>
+        </div>
+        <?php
+    }
+
+}
+
+###API 
+
+function kluvos_save_options(WP_REST_Request $request) {
+    $options = $request->get_param('kluvos_plugin_options');
+
+    if (!is_array($options)) {
+        return new WP_Error('rest_invalid_param', 'Invalid options format', array('status' => 400));
+    }
+
+    // Define the expected structure of the options array
+    $expected_options = array(
+        'property_id' => 'intval',
+        'property_token' => 'sanitize_text_field',
+    );
+
+    $sanitized_options = array();
+
+    foreach ($expected_options as $key => $sanitize_callback) {
+        if (isset($options[$key])) {
+            // Sanitize the value
+            $sanitized_options[$key] = call_user_func($sanitize_callback, $options[$key]);
+        } else {
+            return new WP_Error('rest_invalid_param', "Missing required option: $key", array('status' => 400));
+        }
+    }
+
+    update_option('kluvos_plugin_options', $sanitized_options);
+
+    return new WP_REST_Response('Options saved', 200);
+}
+
+/**
+ * Format decimal values consistently for localization/JS usage
+ *
+ * @param mixed $value Numeric value to format
+ * @return string Formatted decimal string
+ */
+function kluvos_format_decimal_for_js($value) {
+    $numeric_value = floatval($value);
+
+    if (function_exists('wc_format_decimal')) {
+        $decimals = function_exists('wc_get_price_decimals') ? wc_get_price_decimals() : 2;
+        return wc_format_decimal($numeric_value, $decimals);
+    }
+
+    return number_format($numeric_value, 2, '.', '');
+}
+
+###
+##MAIN FUNCTIONS 
+###
+
+function kluvos_enqueue_woocommerce_script($property_token = null) {
+    // If called from hook, get property_token from options
+    if ($property_token === null) {
+        $options = get_option('kluvos_plugin_options');
+        $property_token = isset($options['property_token']) ? $options['property_token'] : '';
+    }
+    
+    // Validate property_token
+    $property_token = sanitize_text_field($property_token);
+    if (empty($property_token)) {
+        return; // Don't enqueue if invalid
+    }
+    
+        $api_base_url = kluvos_get_api_base_url();
+    $script_url = rtrim($api_base_url, '/') . '/v2/scripts/woocommerce/' . rawurlencode($property_token) . '.js';
+        wp_enqueue_script( 'kluvos-site-script', $script_url, array(), null, true );
+}
+
+// Enqueue product view tracking script
+function kluvos_enqueue_viewed_product_script($product_data) {
+    $plugin_url = plugin_dir_url(__FILE__);
+    wp_enqueue_script(
+        'kluvos-viewed-product',
+        $plugin_url . 'assets/js/kluvos-viewed-product.js',
+        array(),
+        '1.0.0',
+        true
+    );
+    
+    // Pass product data and API URL to JavaScript via wp_localize_script
+    wp_localize_script(
+        'kluvos-viewed-product',
+        'kluvosConfig',
+        array(
+            'productData' => $product_data,
+            'apiBaseUrl' => kluvos_get_api_base_url()
+        )
+    );
+}
+
+
+
+
+
+function kluvos_customize_script_tag( $tag, $handle, $src ) {
+// Fetch the entire options array
+$options = get_option('kluvos_plugin_options');
+
+// Access property_token from the options array
+$property_token = isset($options['property_token']) ? $options['property_token'] : '';
+
+    if ( $handle === 'kluvos-site-script' ) {
+        // Add the data attribute
+        $data_attribute = ' data-kluvos-verification="' . esc_attr($property_token) . '"';
+        
+        // Choose between async or defer
+        $async_or_defer = ' defer'; 
+
+        // Modify the script tag
+        $tag = str_replace( ' src', $data_attribute . $async_or_defer . ' src', $tag );
+    }
+
+    return $tag;
+}
+
+
+function kluvos_send_add_to_cart_data_to_server($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data) {
+
+    // Sanitize and validate inputs
+    $cart_item_key = sanitize_text_field($cart_item_key);
+    $product_id = absint($product_id);
+    $quantity = absint($quantity);
+    $variation_id = !empty($variation_id) ? absint($variation_id) : 0;
+
+    // Check if the cookie exists and sanitize it
+    if (!isset($_COOKIE['_kpixel_s'])) {
+        return;
+    }
+
+    // Initialize cart_token
+    $cart_token = '';
+    if (isset($_COOKIE['_kpixel_lt'])) {
+        $ltCookie = sanitize_text_field(wp_unslash($_COOKIE['_kpixel_lt']));
+        $pos = strpos($ltCookie, ':');
+        if ($pos !== false && $pos >= 0) {
+            $ltCookie = substr($ltCookie, $pos + 1);
+            $ltCookie = sanitize_text_field($ltCookie);
+        }
+        $cart_token = sanitize_text_field(str_replace(':', '', $ltCookie));
+    }
+
+    $session_cookie = sanitize_text_field(wp_unslash($_COOKIE['_kpixel_s']));
+
+    // Extract metadata cookies (same as product_view / checkout / purchase)
+    $fbc = isset($_COOKIE['_fbc']) ? sanitize_text_field(wp_unslash($_COOKIE['_fbc'])) : '';
+    $fbp = isset($_COOKIE['_fbp']) ? sanitize_text_field(wp_unslash($_COOKIE['_fbp'])) : '';
+    $lt_cookie = isset($_COOKIE['_kpixel_lt']) ? sanitize_text_field(wp_unslash($_COOKIE['_kpixel_lt'])) : '';
+
+    $kx = '';
+    // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- URL parameter, not form data
+    if (isset($_GET['_kx'])) {
+        $kx = sanitize_text_field(wp_unslash($_GET['_kx']));
+    } elseif (isset($_COOKIE['__kla_id'])) {
+        $kla_cookie_raw = sanitize_text_field(wp_unslash($_COOKIE['__kla_id']));
+        $decoded_cookie = base64_decode($kla_cookie_raw, true);
+        if (false !== $decoded_cookie) {
+            $kla_data = json_decode($decoded_cookie, true);
+            if (is_array($kla_data) && !empty($kla_data['$exchange_id'])) {
+                $kx = sanitize_text_field($kla_data['$exchange_id']);
+            }
+        }
+    }
+
+    // Build metadata object
+    $metadata = array(
+        'fbc' => $fbc,
+        'fbp' => $fbp,
+        'lt_cookie' => $lt_cookie,
+    );
+
+    if ($kx !== '') {
+        $metadata['kx'] = $kx;
+    }
+
+    // Get the product object for the item that was just added
+    $product = null;
+    if ($variation_id) {
+        $product = wc_get_product($variation_id);
+    }
+    if (!$product) {
+        $product = wc_get_product($product_id);
+    }
+
+    if (!$product || !is_object($product)) {
+        return;
+    }
+
+    // Build item data for the item that was just added
+    $image_id = 0;
+    if (method_exists($product, 'get_image_id')) {
+        $image_id = absint($product->get_image_id());
+    }
+    $image_url = '';
+    if ($image_id) {
+        $image_url = esc_url_raw(wp_get_attachment_image_url($image_id, 'full'));
+    }
+
+    $product_name = '';
+    if (method_exists($product, 'get_name')) {
+        $product_name = wp_strip_all_tags($product->get_name());
+    }
+    $product_url = esc_url_raw(get_permalink($product_id));
+    
+    $product_price = 0;
+    if (method_exists($product, 'get_price')) {
+        $product_price = floatval($product->get_price()); // Product price, not cart total
+    }
+
+    // Get product SKU if available
+    $product_sku = '';
+    if (method_exists($product, 'get_sku')) {
+        $sku_value = $product->get_sku();
+        if ($sku_value) {
+            $product_sku = wp_strip_all_tags($sku_value);
+        }
+    }
+
+    // Build variation name from variation attributes if available
+    $variation_name = '';
+    if ($variation_id && !empty($variation) && is_array($variation)) {
+        $variation_parts = array();
+        foreach ($variation as $attr_name => $attr_value) {
+            $variation_parts[] = wp_strip_all_tags($attr_value);
+        }
+        $variation_name = implode(', ', $variation_parts);
+    }
+
+    // Build AddedItem object (the item that was just added)
+    $added_item = array(
+        'product_id' => $product_id,
+        'variation_id' => $variation_id ? $variation_id : null,
+        'quantity' => $quantity,
+        'product_name' => $product_name,
+        'variation_name' => $variation_name,
+        'image_url' => $image_url,
+        'product_url' => $product_url,
+        'price' => $product_price,
+        'sku' => $product_sku
+    );
+
+    // Get full cart state after adding the item
+    // Validate WooCommerce cart is available
+    if (!function_exists('WC') || !WC()->cart || !is_object(WC()->cart)) {
+        return;
+    }
+    $cart = WC()->cart;
+
+    // Calculate totals to ensure line item totals are populated
+    // Wrap in try-catch to prevent crashes if calculation fails
+    try {
+    $cart->calculate_totals();
+    } catch (Exception $e) {
+        // Continue anyway - totals may already be calculated
+        // Only log in debug mode to avoid cluttering production logs
+        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging only when WP_DEBUG is enabled
+        if (defined('WP_DEBUG') && WP_DEBUG) {
+            error_log('Kluvos: Cart calculation error - ' . $e->getMessage());
+        }
+    }
+
+    $cart_contents = $cart->get_cart();
+
+    // Validate cart_contents before proceeding
+    if (empty($cart_contents) || !is_array($cart_contents)) {
+        return; // Exit if cart is empty or invalid
+    }
+
+    // Use existing optimized helper function to get cart items with details
+    $cart_items_with_details = kluvos_add_variant_details_to_cart_items($cart_contents);
+    
+    // Validate cart_items_with_details is an array
+    if (!is_array($cart_items_with_details)) {
+        return;
+    }
+
+    // Add tax and pricing info to each cart item (from WooCommerce cart data)
+    foreach ($cart_items_with_details as $item_key => $item) {
+        if (isset($cart_contents[$item_key])) {
+            $cart_item = $cart_contents[$item_key];
+            $cart_items_with_details[$item_key]['line_total'] = floatval($cart_item['line_total']); // Price after discounts
+            $cart_items_with_details[$item_key]['line_subtotal'] = floatval($cart_item['line_subtotal']); // Price before discounts
+            $cart_items_with_details[$item_key]['tax'] = floatval($cart_item['line_tax']); // Tax for this line item
+            $cart_items_with_details[$item_key]['subtotal_tax'] = floatval($cart_item['line_subtotal_tax']); // Tax before discounts
+        }
+    }
+
+    // Build CartTotals object with method existence checks
+    $item_count = 0;
+    if (method_exists($cart, 'get_cart_contents_count')) {
+        $item_count = absint($cart->get_cart_contents_count());
+    }
+    
+    $items_subtotal = 0;
+    if (method_exists($cart, 'get_subtotal')) {
+        $items_subtotal = floatval($cart->get_subtotal());
+    }
+    
+    $total_discount = 0;
+    if (method_exists($cart, 'get_cart_discount_total')) {
+        $total_discount = floatval($cart->get_cart_discount_total());
+    }
+    
+    $cart_tax = 0;
+    if (method_exists($cart, 'get_cart_tax')) {
+        $cart_tax = floatval($cart->get_cart_tax());
+    }
+    
+    $total = 0;
+    if (method_exists($cart, 'get_total')) {
+        $total = floatval($cart->get_total('edit'));
+    }
+    
+    $cart_totals = array(
+        'item_count' => $item_count,
+        'items_subtotal' => $items_subtotal, // Cart subtotal (before discounts, before tax)
+        'total_discount' => $total_discount,
+        'cart_tax' => $cart_tax, // Total tax
+        'total' => $total, // Final total including tax
+        'items' => $cart_items_with_details // All items in cart with details
+    );
+
+    // Fetch plugin options
+    $options = get_option('kluvos_plugin_options');
+    $property_token = isset($options['property_token']) ? sanitize_text_field($options['property_token']) : '';
+
+    if (empty($property_token)) {
+        return;
+    }
+
+    // Prepare payload with AddedItem and CartTotals nested inside items
+    // Also include required fields at top level for Rails strong params
+    $currency = 'USD'; // Default fallback
+    if (function_exists('get_woocommerce_currency')) {
+        $currency = get_woocommerce_currency();
+    }
+    
+    $data = array(
+        'property_token' => $property_token,
+        'session_cookie' => $session_cookie,
+        'currency' => sanitize_text_field($currency),
+        'item_count' => $cart_totals['item_count'], // Required by Rails strong params
+        'items_subtotal_price' => $cart_totals['items_subtotal'], // Required by Rails strong params
+        'original_total_price' => $cart_totals['items_subtotal'], // Same as items_subtotal_price
+        'total_discount' => $cart_totals['total_discount'], // Required by Rails strong params
+        'total_price' => $cart_totals['total'], // Required by Rails strong params
+        'time_utc' => sanitize_text_field(current_time('c')),
+        'cart_token' => sanitize_text_field($cart_token),
+        'cart_attributes' => array(),
+        'client_event_id' => '',
+        'metadata' => $metadata,
+        'items' => array(
+            'AddedItem' => $added_item, // The item that was just added
+            'CartTotals' => $cart_totals // Full cart state with all items and totals
+        )
+    );
+
+    // Send POST request to new Rails API endpoint
+    $url = kluvos_get_api_base_url() . '/api/v1/woocommerce_events/add_to_carts';
+    $response = wp_remote_post($url, array(
+        'method' => 'POST',
+        'headers' => array('Content-Type' => 'application/json; charset=utf-8'),
+        'body' => wp_json_encode($data),
+        'data_format' => 'body',
+        'timeout' => 5
+    ));
+
+    // Handle errors silently in production (fail gracefully)
+    if (is_wp_error($response)) {
+        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging only when WP_DEBUG is enabled
+        if (defined('WP_DEBUG') && WP_DEBUG) {
+            error_log('Kluvos: Failed to send add to cart data - ' . $response->get_error_message());
+        }
+        return; // Fail silently in production
+    }
+}
+
+/**
+ * Output checkout data for client-side tracking
+ */
+function kluvos_output_checkout_data_for_js() {
+    if (!function_exists('is_checkout') || !is_checkout()) {
+        return;
+    }
+
+    if (function_exists('is_wc_endpoint_url') && is_wc_endpoint_url('order-received')) {
+        return;
+    }
+
+    if (!function_exists('WC') || !WC()->cart || !is_object(WC()->cart)) {
+        return;
+    }
+
+    $options = get_option('kluvos_plugin_options');
+    $property_token = isset($options['property_token']) ? sanitize_text_field($options['property_token']) : '';
+
+    if (empty($property_token)) {
+        return;
+    }
+
+    $cart = WC()->cart;
+    $cart_contents = $cart->get_cart();
+    if (!is_array($cart_contents)) {
+        $cart_contents = array();
+    }
+
+    $cart_items_with_details = kluvos_add_variant_details_to_cart_items($cart_contents);
+    if (!is_array($cart_items_with_details)) {
+        $cart_items_with_details = array();
+    }
+
+    $items_for_js = array();
+    $all_categories = array();
+
+    foreach ($cart_items_with_details as $cart_item_key => $cart_item) {
+        $product_id = isset($cart_item['product_id']) ? absint($cart_item['product_id']) : 0;
+        $variation_id = isset($cart_item['variation_id']) ? absint($cart_item['variation_id']) : 0;
+        $quantity = isset($cart_item['quantity']) ? absint($cart_item['quantity']) : 0;
+
+        $product = isset($cart_item['data']) && is_object($cart_item['data']) ? $cart_item['data'] : null;
+        $sku = '';
+        if ($product && method_exists($product, 'get_sku')) {
+            $sku_value = $product->get_sku();
+            if ($sku_value) {
+                $sku = wp_strip_all_tags($sku_value);
+            }
+        }
+
+        $line_subtotal_value = isset($cart_item['line_subtotal']) ? floatval($cart_item['line_subtotal']) : 0;
+        $line_total_value = isset($cart_item['line_total']) ? floatval($cart_item['line_total']) : 0;
+        $line_tax_value = isset($cart_item['line_tax']) ? floatval($cart_item['line_tax']) : 0;
+
+        $unit_price_value = $quantity > 0 ? $line_total_value / $quantity : $line_total_value;
+
+        $line_subtotal = kluvos_format_decimal_for_js($line_subtotal_value);
+        $line_total = kluvos_format_decimal_for_js($line_total_value);
+        $line_tax = kluvos_format_decimal_for_js($line_tax_value);
+        $unit_price = kluvos_format_decimal_for_js($unit_price_value);
+
+        $variation_attributes = array();
+        if (isset($cart_item['variation']) && is_array($cart_item['variation'])) {
+            foreach ($cart_item['variation'] as $attribute_name => $attribute_value) {
+                $attribute_name = sanitize_title_with_dashes(str_replace('attribute_', '', $attribute_name));
+                $attribute_value = sanitize_text_field($attribute_value);
+                if (!empty($attribute_name)) {
+                    $variation_attributes[$attribute_name] = $attribute_value;
+                }
+            }
+        }
+
+        $variation_extra = array();
+        if (isset($cart_item['variation']) && is_array($cart_item['variation'])) {
+            foreach ($cart_item['variation'] as $attribute_name => $attribute_value) {
+                $normalized_name = str_replace(array('attribute_pa_', 'attribute_'), '', $attribute_name);
+                $normalized_key = 'attribute_' . sanitize_key($normalized_name);
+                $variation_extra[$normalized_key] = sanitize_text_field($attribute_value);
+            }
+        }
+
+        $item_categories = array();
+        $product_terms = wp_get_post_terms($product_id, 'product_cat', array('fields' => 'names'));
+        if (!is_wp_error($product_terms) && is_array($product_terms)) {
+            foreach ($product_terms as $term_name) {
+                $clean_term = wp_strip_all_tags($term_name);
+                if ($clean_term !== '') {
+                    $item_categories[] = $clean_term;
+                }
+            }
+        }
+
+        $item_entry = array(
+            'key' => sanitize_text_field($cart_item_key),
+            'product_id' => $product_id,
+            'variation_id' => $variation_id,
+            'sku' => $sku,
+            'name' => isset($cart_item['product_name']) ? $cart_item['product_name'] : '',
+            'variation_name' => isset($cart_item['variation_name']) ? $cart_item['variation_name'] : '',
+            'quantity' => $quantity,
+            'unit_price' => $unit_price,
+            'line_subtotal' => $line_subtotal,
+            'line_total' => $line_total,
+            'line_tax' => $line_tax,
+            'product_url' => isset($cart_item['product_url']) ? $cart_item['product_url'] : '',
+            'image_url' => isset($cart_item['image_url']) ? $cart_item['image_url'] : '',
+            'attributes' => $variation_attributes,
+            'categories' => $item_categories,
+        );
+
+        $items_for_js[] = $item_entry;
+
+        $all_categories = array_merge($all_categories, $item_categories);
+
+    }
+
+    $unique_categories = array();
+    if (!empty($all_categories)) {
+        $unique_categories = array_values(array_unique(array_filter($all_categories, function ($category) {
+            return $category !== '';
+        })));
+    }
+
+    $currency_code = 'USD';
+    if (function_exists('get_woocommerce_currency')) {
+        $currency_code = sanitize_text_field(get_woocommerce_currency());
+    }
+
+    $currency_symbol = '';
+    if (function_exists('get_woocommerce_currency_symbol')) {
+        $currency_symbol = wp_strip_all_tags(get_woocommerce_currency_symbol($currency_code));
+    }
+
+    $store_url = esc_url_raw(home_url('/'));
+    $checkout_url = $store_url;
+    if (function_exists('wc_get_checkout_url')) {
+        $checkout_url = esc_url_raw(wc_get_checkout_url());
+    }
+
+    // Build cart totals with method existence checks to prevent fatal errors
+    $items_subtotal = 0;
+    if (method_exists($cart, 'get_subtotal')) {
+        $items_subtotal = floatval($cart->get_subtotal());
+    }
+    
+    $items_subtotal_tax = 0;
+    if (method_exists($cart, 'get_subtotal_tax')) {
+        $items_subtotal_tax = floatval($cart->get_subtotal_tax());
+    }
+    
+    $discount_total = 0;
+    if (method_exists($cart, 'get_discount_total')) {
+        $discount_total = floatval($cart->get_discount_total());
+    }
+    
+    $discount_tax = 0;
+    if (method_exists($cart, 'get_discount_tax')) {
+        $discount_tax = floatval($cart->get_discount_tax());
+    }
+    
+    $shipping_total = 0;
+    if (method_exists($cart, 'get_shipping_total')) {
+        $shipping_total = floatval($cart->get_shipping_total());
+    }
+    
+    $shipping_tax = 0;
+    if (method_exists($cart, 'get_shipping_tax')) {
+        $shipping_tax = floatval($cart->get_shipping_tax());
+    }
+    
+    $fee_total = 0;
+    if (method_exists($cart, 'get_fee_total')) {
+        $fee_total = floatval($cart->get_fee_total());
+    }
+    
+    $total_tax = 0;
+    if (method_exists($cart, 'get_total_tax')) {
+        $total_tax = floatval($cart->get_total_tax());
+    }
+    
+    $total = 0;
+    if (method_exists($cart, 'get_total')) {
+        $total = floatval($cart->get_total('edit'));
+    }
+    
+    $item_count = 0;
+    if (method_exists($cart, 'get_cart_contents_count')) {
+        $item_count = absint($cart->get_cart_contents_count());
+    }
+    
+    $cart_totals = array(
+        'items_subtotal' => kluvos_format_decimal_for_js($items_subtotal),
+        'items_subtotal_tax' => kluvos_format_decimal_for_js($items_subtotal_tax),
+        'discount_total' => kluvos_format_decimal_for_js($discount_total),
+        'discount_tax' => kluvos_format_decimal_for_js($discount_tax),
+        'shipping_total' => kluvos_format_decimal_for_js($shipping_total),
+        'shipping_tax' => kluvos_format_decimal_for_js($shipping_tax),
+        'fee_total' => kluvos_format_decimal_for_js($fee_total),
+        'total_tax' => kluvos_format_decimal_for_js($total_tax),
+        'total' => kluvos_format_decimal_for_js($total),
+        'item_count' => $item_count,
+    );
+
+    $cart_hash = '';
+    if (method_exists($cart, 'get_cart_hash')) {
+        $cart_hash = sanitize_text_field($cart->get_cart_hash());
+    }
+
+    if (!empty($cart_hash)) {
+        $cart_totals['cart_hash'] = $cart_hash;
+    }
+
+    $session_cookie = '';
+    if (isset($_COOKIE['_kpixel_s'])) {
+        $session_cookie = sanitize_text_field(wp_unslash($_COOKIE['_kpixel_s']));
+    }
+
+    $customer_data = array();
+    if (is_user_logged_in()) {
+        $current_user = wp_get_current_user();
+        if ($current_user && $current_user->ID) {
+            $customer_data['id'] = absint($current_user->ID);
+        }
+        if (!empty($current_user->user_email)) {
+            $customer_data['email'] = sanitize_email($current_user->user_email);
+        }
+        if (!empty($current_user->first_name)) {
+            $customer_data['first_name'] = wp_strip_all_tags($current_user->first_name);
+        }
+        if (!empty($current_user->last_name)) {
+            $customer_data['last_name'] = wp_strip_all_tags($current_user->last_name);
+        }
+    }
+
+    if (function_exists('WC') && WC()->customer && is_object(WC()->customer)) {
+        $customer = WC()->customer;
+        if (method_exists($customer, 'get_billing_email')) {
+            $billing_email = $customer->get_billing_email();
+            if (!empty($billing_email)) {
+                $customer_data['email'] = sanitize_email($billing_email);
+            }
+        }
+        if (method_exists($customer, 'get_billing_first_name')) {
+            $first_name = $customer->get_billing_first_name();
+            if (!empty($first_name)) {
+                $customer_data['first_name'] = wp_strip_all_tags($first_name);
+            }
+        }
+        if (method_exists($customer, 'get_billing_last_name')) {
+            $last_name = $customer->get_billing_last_name();
+            if (!empty($last_name)) {
+                $customer_data['last_name'] = wp_strip_all_tags($last_name);
+            }
+        }
+    }
+
+    $checkout_data = array(
+        'property_token' => $property_token,
+        'store_url' => $store_url,
+        'checkout_url' => $checkout_url,
+        'currency_code' => $currency_code,
+        'currency_symbol' => $currency_symbol,
+        'service' => 'woocommerce',
+        'categories' => $unique_categories,
+        'cart_items' => $items_for_js,
+        'cart_totals' => $cart_totals,
+        'customer' => $customer_data,
+        'session_cookie' => $session_cookie,
+        'origin' => $checkout_url,
+    );
+
+    $plugin_url = plugin_dir_url(__FILE__);
+    wp_enqueue_script(
+        'kluvos-checkout',
+        $plugin_url . 'assets/js/kluvos-checkout.js',
+        array(),
+        '1.0.0',
+        true
+    );
+
+    wp_localize_script(
+        'kluvos-checkout',
+        'kluvosCheckoutConfig',
+        array(
+            'apiBaseUrl' => kluvos_get_api_base_url(),
+            'checkoutData' => $checkout_data,
+        )
+    );
+}
+
+####viewed product
+
+// Enqueue script and output product data for client-side JavaScript tracking
+function kluvos_output_product_data_for_js() {
+    // Only run on WooCommerce product pages
+    if (!function_exists('is_product') || !is_product()) {
+        return;
+    }
+
+    // Get the product object directly (avoid global variable)
+    $product = null;
+    if (function_exists('wc_get_product')) {
+        $product_id = get_the_ID();
+        if ($product_id) {
+            $product = wc_get_product($product_id);
+        }
+    }
+
+    // Validate that we have a valid WooCommerce product object
+    // Check if it's an object and has the methods we need
+    if (!$product || !is_object($product)) {
+        return;
+    }
+    
+    // Check if it's a WooCommerce product object (has the get_id method)
+    if (!method_exists($product, 'get_id')) {
+        return;
+    }
+
+    // Fetch plugin options
+    $options = get_option('kluvos_plugin_options');
+    $property_token = isset($options['property_token']) ? sanitize_text_field($options['property_token']) : '';
+
+    if (empty($property_token)) {
+        return;
+    }
+
+    // Get product details (same as original function)
+    $product_id = 0;
+    if (method_exists($product, 'get_id')) {
+    $product_id = absint($product->get_id());
+    }
+    if (!$product_id) {
+        return; // Can't proceed without valid product ID
+    }
+    
+    $product_name = '';
+    if (method_exists($product, 'get_name')) {
+    $product_name = wp_strip_all_tags($product->get_name());
+    }
+    $product_url = esc_url_raw(get_permalink($product_id));
+    
+    $product_price = 0;
+    if (method_exists($product, 'get_price')) {
+    $product_price = floatval($product->get_price());
+    }
+    
+    $product_compare_at_price = 0;
+    if (method_exists($product, 'get_regular_price')) {
+    $product_compare_at_price = floatval($product->get_regular_price());
+    }
+    
+    // Get categories and sanitize
+    $product_categories_raw = wp_get_post_terms($product_id, 'product_cat', array('fields' => 'names'));
+    $product_categories = array();
+    if (!is_wp_error($product_categories_raw) && is_array($product_categories_raw)) {
+        foreach ($product_categories_raw as $category) {
+            $product_categories[] = wp_strip_all_tags($category);
+        }
+    }
+
+    // Handle variable products (select first variation like original)
+    $image_id = null;
+    $variant_name = '';
+    if (method_exists($product, 'is_type') && $product->is_type('variable')) {
+        if (method_exists($product, 'get_available_variations')) {
+        $variations = $product->get_available_variations();
+            if (!empty($variations) && is_array($variations) && isset($variations[0]['variation_id'])) {
+            $variation_id = absint($variations[0]['variation_id']);
+            $variation_product = wc_get_product($variation_id);
+                if ($variation_product && is_object($variation_product)) {
+                    if (method_exists($variation_product, 'get_image_id')) {
+                $image_id = absint($variation_product->get_image_id());
+                    }
+                
+                // Extract only attribute values for variant name
+                    if (method_exists($variation_product, 'get_attributes')) {
+                $attributes = $variation_product->get_attributes();
+                $variant_name_parts = array();
+                if (is_array($attributes)) {
+                    foreach ($attributes as $attribute_value) {
+                        $variant_name_parts[] = wp_strip_all_tags($attribute_value);
+                    }
+                }
+                $variant_name = implode(', ', $variant_name_parts);
+                    }
+                }
+            }
+        }
+    }
+
+    // Fallback to main product image if no variant image is found
+    if (!$image_id && method_exists($product, 'get_image_id')) {
+        $image_id = absint($product->get_image_id());
+    }
+
+    $product_image_url = '';
+    if ($image_id) {
+        $product_image_url = esc_url_raw(wp_get_attachment_image_url($image_id, 'full'));
+    }
+
+    // Sanitize brand name
+    $brand = wp_strip_all_tags(get_bloginfo('name'));
+
+    // Get store base URL for property identification
+    $store_url = esc_url_raw(home_url('/'));
+    
+    // Get currency code
+    $currency_code = 'USD'; // Default fallback
+    if (function_exists('get_woocommerce_currency')) {
+        $currency_code = get_woocommerce_currency();
+    }
+
+    // Get product SKU if available
+    $product_sku = '';
+    if (method_exists($product, 'get_sku')) {
+        $sku_value = $product->get_sku();
+        if ($sku_value) {
+            $product_sku = wp_strip_all_tags($sku_value);
+        }
+    }
+
+    // Prepare product data structure with all sanitized values
+    // Note: wp_localize_script converts all values to strings, so we'll need to 
+    // re-parse ints and floats in JavaScript (like Klaviyo does)
+    $product_data = array(
+        'url' => $product_url, // Product page URL
+        'store_url' => $store_url, // Store base URL for property lookup (also used as origin)
+        'name' => $product_name,
+        'variant_name' => $variant_name,
+        'brand' => $brand,
+        'price' => $product_price,
+        'image_url' => $product_image_url,
+        'categories' => $product_categories,
+        'product_id' => $product_id,
+        'compare_at_price' => $product_compare_at_price,
+        'sku' => $product_sku,
+        'currency_code' => $currency_code,
+        'property_token' => $property_token
+    );
+
+    // Enqueue script and pass product data via wp_localize_script
+    kluvos_enqueue_viewed_product_script($product_data);
+}
+
+
+
+
+
+#########
+
+function kluvos_send_order_to_server( $order_id ) {
+    if ( ! function_exists( 'wc_get_order' ) ) {
+        return;
+    }
+
+    $order = wc_get_order( $order_id );
+    if ( ! $order || ! is_object( $order ) ) {
+        return;
+    }
+
+    $options        = get_option( 'kluvos_plugin_options' );
+    $property_id    = isset( $options['property_id'] ) ? absint( $options['property_id'] ) : 0;
+    $property_token = isset( $options['property_token'] ) ? sanitize_text_field( $options['property_token'] ) : '';
+
+    if ( empty( $property_token ) ) {
+        return;
+    }
+
+    $session_cookie = '';
+    if ( isset( $_COOKIE['_kpixel_s'] ) ) {
+        $session_cookie = sanitize_text_field( wp_unslash( $_COOKIE['_kpixel_s'] ) );
+    }
+
+    $lt_cookie = '';
+    if ( isset( $_COOKIE['_kpixel_lt'] ) ) {
+        $lt_cookie = sanitize_text_field( wp_unslash( $_COOKIE['_kpixel_lt'] ) );
+    }
+
+    $metadata = array();
+
+    $cookie_map = array(
+        'fbc'       => '_fbc',
+        'fbp'       => '_fbp',
+        'lt_cookie' => '_kpixel_lt',
+    );
+
+    foreach ( $cookie_map as $meta_key => $cookie_name ) {
+        if ( isset( $_COOKIE[ $cookie_name ] ) ) {
+            $cookie_value = sanitize_text_field( wp_unslash( $_COOKIE[ $cookie_name ] ) );
+            if ( '' !== $cookie_value ) {
+                $metadata[ $meta_key ] = $cookie_value;
+            }
+        }
+    }
+
+    $kx_value = '';
+    // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- URL parameter, not form data
+    if ( isset( $_GET['_kx'] ) ) {
+        $kx_value = sanitize_text_field( wp_unslash( $_GET['_kx'] ) );
+    } elseif ( isset( $_COOKIE['__kla_id'] ) ) {
+        $kla_cookie_raw = sanitize_text_field( wp_unslash( $_COOKIE['__kla_id'] ) );
+        $decoded_cookie = base64_decode( $kla_cookie_raw, true );
+        if ( false !== $decoded_cookie ) {
+            $kla_data = json_decode( $decoded_cookie, true );
+            if ( is_array( $kla_data ) && ! empty( $kla_data['$exchange_id'] ) ) {
+                $kx_value = sanitize_text_field( $kla_data['$exchange_id'] );
+            }
+        }
+    }
+
+    if ( '' !== $kx_value ) {
+        $metadata['kx'] = $kx_value;
+    }
+
+    $time_utc = '';
+    if ( method_exists( $order, 'get_date_created' ) ) {
+        $date_created = $order->get_date_created();
+        if ( $date_created instanceof WC_DateTime ) {
+            $time_utc = sanitize_text_field( $date_created->date( 'c' ) );
+        }
+    }
+    if ( '' === $time_utc ) {
+        $time_utc = sanitize_text_field( current_time( 'c' ) );
+    }
+
+    $currency_code = 'USD';
+    if ( method_exists( $order, 'get_currency' ) ) {
+        $currency = $order->get_currency();
+        if ( $currency ) {
+            $currency_code = sanitize_text_field( $currency );
+        }
+    }
+
+    $customer_data   = array();
+    $customer_id     = method_exists( $order, 'get_customer_id' ) ? absint( $order->get_customer_id() ) : 0;
+    if ( $customer_id > 0 ) {
+        $customer_data['id'] = $customer_id;
+    }
+
+    if ( method_exists( $order, 'get_billing_email' ) ) {
+        $billing_email = $order->get_billing_email();
+        if ( $billing_email ) {
+            $customer_data['email'] = sanitize_email( $billing_email );
+        }
+    }
+
+    if ( method_exists( $order, 'get_billing_first_name' ) ) {
+        $billing_first_name = $order->get_billing_first_name();
+        if ( $billing_first_name ) {
+            $customer_data['first_name'] = wp_strip_all_tags( $billing_first_name );
+        }
+    }
+
+    if ( method_exists( $order, 'get_billing_last_name' ) ) {
+        $billing_last_name = $order->get_billing_last_name();
+        if ( $billing_last_name ) {
+            $customer_data['last_name'] = wp_strip_all_tags( $billing_last_name );
+        }
+    }
+
+    if ( method_exists( $order, 'get_billing_phone' ) ) {
+        $billing_phone = $order->get_billing_phone();
+        if ( $billing_phone ) {
+            $customer_data['phone'] = sanitize_text_field( $billing_phone );
+        }
+    }
+
+    if ( method_exists( $order, 'get_customer_ip_address' ) ) {
+        $customer_ip = $order->get_customer_ip_address();
+        if ( $customer_ip ) {
+            $metadata['ip_address'] = sanitize_text_field( $customer_ip );
+        }
+    }
+
+    if ( method_exists( $order, 'get_customer_user_agent' ) ) {
+        $customer_agent = $order->get_customer_user_agent();
+        if ( $customer_agent ) {
+            $metadata['user_agent'] = sanitize_text_field( $customer_agent );
+        }
+    }
+
+    $order_number   = method_exists( $order, 'get_order_number' ) ? sanitize_text_field( $order->get_order_number() ) : '';
+    $order_key      = method_exists( $order, 'get_order_key' ) ? sanitize_text_field( $order->get_order_key() ) : '';
+    $total_price    = method_exists( $order, 'get_total' ) ? floatval( $order->get_total() ) : 0;
+
+    $purchase_payload = array(
+        'property_token'  => $property_token,
+        'property_id'     => $property_id,
+        'session_cookie'  => $session_cookie,
+        'lt_cookie'       =>  $lt_cookie,
+        'source_name'     => 'web',
+        'order_id'        => sanitize_text_field( 'wc_' . $order_id ),
+        'order_number'    => $order_number,
+        'order_key'       => $order_key,
+        'currency'        => $currency_code,
+        'time_utc'        => $time_utc,
+        'total_price'     => $total_price,
+        'platform'        => 'woocommerce',
+        'metadata'        => $metadata,
+        'customer'        => $customer_data,
+    );
+
+    $request_options = array(
+        'method'      => 'POST',
+        'headers'     => array(
+            'Content-Type' => 'application/json; charset=utf-8',
+        ),
+        'body'        => wp_json_encode( $purchase_payload ),
+        'data_format' => 'body',
+        'timeout'     => 5,
+    );
+
+    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
+        $request_options['headers']['ngrok-skip-browser-warning'] = 'true';
+    }
+
+    $url      = kluvos_get_api_base_url() . '/api/v1/woocommerce_events/purchases';
+    $response = wp_remote_post( $url, $request_options );
+
+    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging only when WP_DEBUG is enabled
+    if ( is_wp_error( $response ) && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
+        error_log( 'Kluvos: Failed to send order data - ' . $response->get_error_message() );
+    }
+}
+
+
+
+
+
+// Function to add variant details to each cart item
+function kluvos_add_variant_details_to_cart_items($cart_items) {
+    
+    foreach ($cart_items as $cart_item_key => $cart_item) {
+        // Sanitize product and variation IDs
+        $product_id = isset($cart_item['product_id']) ? absint($cart_item['product_id']) : 0;
+        $variation_id = isset($cart_item['variation_id']) ? absint($cart_item['variation_id']) : null;
+
+        if (!$product_id) {
+            continue; // Skip invalid product IDs
+        }
+
+        // Get the correct product object
+        $product = null;
+        if ($variation_id) {
+            // If it's a variation, get the variation product object
+            $product = wc_get_product($variation_id);
+        }
+        
+        if (!$product) {
+            // Otherwise, get the main product object
+            $product = wc_get_product($product_id);
+        }
+
+        if (!$product || !is_object($product)) {
+            continue; // Skip if product not found
+        }
+
+        // Retrieve the image ID associated with the product or variation
+        $image_id = 0;
+        if (method_exists($product, 'get_image_id')) {
+            $image_id = absint($product->get_image_id());
+        }
+
+        // Get the image URL and sanitize it
+        $image_url = '';
+        if ($image_id) {
+            $image_url = esc_url_raw(wp_get_attachment_image_url($image_id, 'full'));
+        }
+
+        // Get the product name and sanitize it
+        $product_name = '';
+        if (method_exists($product, 'get_name')) {
+            $product_name = wp_strip_all_tags($product->get_name());
+        }
+
+        // Get the variation name if it exists
+        $variation_name = '';
+        if (!$product_name && $variation_id) {
+            $variation = wc_get_product($variation_id);
+            if ($variation && is_object($variation) && method_exists($variation, 'get_name')) {
+                $variation_name = wp_strip_all_tags($variation->get_name());
+            }
+        }
+
+        // Get the product permalink and sanitize it
+        $product_permalink = esc_url_raw(get_permalink($product_id));
+
+        // If this is a variation, append attribute parameters to the URL
+        if ($variation_id && isset($cart_item['variation']) && is_array($cart_item['variation']) && !empty($cart_item['variation'])) {
+            $variation_attributes = $cart_item['variation'];
+            $query_params = array();
+            
+            // Build query parameters from variation attributes
+            foreach ($variation_attributes as $attr_name => $attr_value) {
+                // Sanitize attribute name and value
+                $attr_name = sanitize_text_field($attr_name);
+                $attr_value = sanitize_text_field($attr_value);
+                
+                if (!empty($attr_name) && !empty($attr_value)) {
+                    $query_params[$attr_name] = $attr_value;
+                }
+            }
+            
+            // Append query parameters to the URL if we have any
+            if (!empty($query_params)) {
+                // Check if URL already has query parameters
+                $separator = (strpos($product_permalink, '?') !== false) ? '&' : '?';
+                $product_permalink = esc_url_raw($product_permalink . $separator . http_build_query($query_params));
+            }
+        }
+
+        // Sanitize quantity if present
+        $quantity = isset($cart_item['quantity']) ? absint($cart_item['quantity']) : 0;
+
+        // Add the details to the cart item (all sanitized)
+        $cart_items[$cart_item_key]['image_url'] = $image_url;
+        $cart_items[$cart_item_key]['product_name'] = $product_name;
+        $cart_items[$cart_item_key]['variation_name'] = $variation_name;
+        $cart_items[$cart_item_key]['product_url'] = $product_permalink;
+        $cart_items[$cart_item_key]['quantity'] = $quantity; // Ensure quantity is sanitized
+        $cart_items[$cart_item_key]['product_id'] = $product_id; // Ensure product_id is sanitized
+        if ($variation_id) {
+            $cart_items[$cart_item_key]['variation_id'] = $variation_id; // Ensure variation_id is sanitized
+        }
+
+    }
+
+    return $cart_items;
+}
Index: /kluvos/tags/2.1.0/readme.txt
===================================================================
--- /kluvos/tags/2.1.0/readme.txt	(revision 3406442)
+++ /kluvos/tags/2.1.0/readme.txt	(revision 3406442)
@@ -0,0 +1,97 @@
+=== Kluvos ===
+Contributors: kluvos
+Tags: analytics, attribution, kluvos
+Requires at least: 1.0
+Tested up to: 6.9
+Stable tag: 2.1.0
+Requires PHP: 7.0
+License: GPLv2 or later
+License URI: https://www.gnu.org/licenses/gpl-2.0.html
+
+== Description ==
+
+Integrate Kluvos easily with your WooCommerce store! Kluvos is your powerful data partner for modern ecommerce businesses.
+
+This powerful plugin provides comprehensive analytics and attribution insights -- helping you see more about what's happening on your store and everything that has contributed to a sale. Kluvos' official plugin for WooCommerce/Wordpress. 
+
+Please note that to use this plugin, you must have a Kluvos account and be running WooCommerce.
+
+
+== Features ==
+
+- **Advanced Analytics:** Gain deep insights into your store's traffic allowing you to make informed decisions to grow your business.
+
+- **Attribution Tracking:** Understand the effectiveness of your marketing campaigns and discover which channels contribute most to your sales.
+
+- **Easy Setup:** Get started quickly with a straightforward installation process. Just sign up for a Kluvos account, and you're ready to go.
+
+== Installation ==
+
+1. Sign up for a Kluvos account at [https://kluvos.com/users/sign_up](https://kluvos.com).
+
+2. Install and activate the Kluvos plugin on your WordPress site.
+
+3. Authenticate Kluvos with WooCommerce in the Kluvos "Set-Up" section.
+
+== Support ==
+
+For any questions or assistance, please email our support team at [support@kluvos.com](mailto:support@kluvos.com).
+
+
+== Screenshots ==
+
+1. Detailed session analysis and attribution behind every purchase (attribution.png). Screenshots are stored in the /assets directory.
+2. Understand which marketing channels are driving sales (channel_productivity.png). Screenshots are stored in the /assets directory.
+3. Comprehensive reporting and conversion pathways (detailed_conversion_pathways.png). Screenshots are stored in the /assets directory.
+
+
+== Frequently Asked Questions ==
+
+= How do I create a Kluvos account =
+
+To create an account, click here: [https://kluvos.com/users/sign_up](https://kluvos.com/users/sign_up).
+
+= Will this plugin work for standard websites? =
+
+This is a plugin designed only for ecommerce sites and requires WooCommerce be installed on your store.
+
+= Where can I find my dashboard? =
+
+Your store data will show up in your Kluvos dashboard on [https://kluvos.com](https://kluvos.com).
+
+== Third-Party Services ==
+
+This plugin adds scripts from and sends data to an externally-hosted service at [https://kluvos.com](https://kluvos.com). These scripts are necessary for the functionality of this plugin. All data is collected, stored, and processed by Kluvos, LLC. Additional details can be seen in our privacy policy: [https://kluvos.com/pages/privacy](https://kluvos.com/pages/privacy)
+
+== Changelog ==
+= 2.1.0 =
+* WordPress 9.0 release
+* Minor updates
+
+= 2.0.1 =
+* Minor updates
+
+= 2.0.0 =
+
+* Major updates and improvements.
+* Enhancements to identity reconciliation infrastructure.
+* Improved viewed product event trigger with client-side tracking for better caching compatibility.
+* Enhanced add to cart event with comprehensive cart context and item details.
+
+= 1.1.2 =
+
+* WooCommerce Cart bug fixes.
+
+= 1.1.1 =
+
+* Integration enhancements.
+* New Authentication requirements.
+
+
+= 1.1.0 =
+
+* Added viewed product event.
+* Improved data collected during events.
+* Improved existing add to cart events.
+
+* Initial release
