Changeset 3240206
- Timestamp:
- 02/13/2025 03:09:47 PM (14 months ago)
- Location:
- usermaven
- Files:
-
- 10 edited
- 1 copied
-
tags/1.1.3 (copied) (copied from usermaven/trunk)
-
tags/1.1.3/README.txt (modified) (1 diff)
-
tags/1.1.3/includes/class-usermaven-api.php (modified) (1 diff)
-
tags/1.1.3/includes/class-usermaven-woocommerce.php (modified) (16 diffs)
-
tags/1.1.3/includes/class-usermaven.php (modified) (1 diff)
-
tags/1.1.3/usermaven.php (modified) (2 diffs)
-
trunk/README.txt (modified) (1 diff)
-
trunk/includes/class-usermaven-api.php (modified) (1 diff)
-
trunk/includes/class-usermaven-woocommerce.php (modified) (16 diffs)
-
trunk/includes/class-usermaven.php (modified) (1 diff)
-
trunk/usermaven.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
usermaven/tags/1.1.3/README.txt
r3221608 r3240206 6 6 Tested up to: 6.7.1 7 7 Requires PHP: 5.6 8 Stable tag: 1.1. 18 Stable tag: 1.1.3 9 9 License: Massachusetts Institute of Technology (MIT) license 10 10 License URI: https://opensource.org/licenses/MIT -
usermaven/tags/1.1.3/includes/class-usermaven-api.php
r3217559 r3240206 9 9 $this->api_key = get_option('usermaven_api_key'); 10 10 $this->api_url = "$tracking_host/api/v1/s2s/event"; 11 } 12 13 public function identify($user_data, $company_data = []) { 14 $url = $this->api_url . "?token=$this->api_key.$this->server_token"; 15 16 // Get current timestamp in milliseconds 17 $current_timestamp_ms = round(microtime(true) * 1000); 18 $doc_encoding = get_bloginfo('charset'); 19 20 $data = [ 21 'api_key' => $this->api_key, 22 'event_type' => 'user_identify', 23 '_timestamp' => (string)$current_timestamp_ms, 24 'user' => $user_data, 25 'company' => [ 26 'id' => $company_data['id'] ?? '', 27 'name' => $company_data['name'] ?? '', 28 ], 29 'src' => 'http', 30 'url' => $_SERVER['HTTP_REFERER'] ?? '', 31 'page_title' => wp_get_document_title(), 32 'doc_path' => $_SERVER['REQUEST_URI'] ?? '', 33 'doc_host' => $_SERVER['HTTP_HOST'] ?? '', 34 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 35 'user_language' => $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '', 36 'doc_encoding' => (string) $doc_encoding, 37 ]; 38 39 $response = wp_remote_post($url, [ 40 'body' => json_encode($data), 41 'headers' => ['Content-Type' => 'application/json'] 42 ]); 43 44 if (is_wp_error($response)) { 45 error_log('Usermaven API Error: ' . $response->get_error_message()); 46 return false; 47 } 48 49 $body = wp_remote_retrieve_body($response); 50 $result = json_decode($body, true); 51 return $result['status'] === 'ok'; 11 52 } 12 53 -
usermaven/tags/1.1.3/includes/class-usermaven-woocommerce.php
r3221608 r3240206 31 31 */ 32 32 private function init_hooks() { 33 // Track on WooCommerce specific login 34 add_action('woocommerce_login_credentials', array($this, 'identify_wc_user'), 10, 2); 35 33 36 // Product Viewing 34 37 add_action('template_redirect', array($this, 'track_product_view')); 35 38 36 39 // Cart Actions 37 40 add_action('woocommerce_add_to_cart', array($this, 'track_add_to_cart'), 10, 6); 38 41 add_action('woocommerce_cart_item_removed', array($this, 'track_remove_from_cart'), 10, 2); 39 42 add_action('woocommerce_after_cart_item_quantity_update', array($this, 'track_cart_update'), 10, 4); 40 41 // Checkout Process 42 add_action('woocommerce_before_checkout_form', array($this, 'track_initiate_checkout'), 10); 43 add_action('woocommerce_checkout_order_processed', array($this, 'track_order_submission'), 10, 3); 44 43 44 // Checkout Process - Consolidated tracking 45 // add_action('woocommerce_before_checkout_form', array($this, 'track_initiate_checkout'), 10); // Removed this because it was not triggering for custom checkout pages 46 add_action('wp', array($this, 'maybe_track_checkout_init')); 47 // add_action('woocommerce_checkout_order_processed', array($this, 'track_order_submission'), 10, 3); // Removed this because it was not triggering for custom checkout pages 48 add_action('woocommerce_new_order', array($this, 'track_order_submission'), 10, 1); 49 45 50 // Order Status and Completion 46 51 // add_action('woocommerce_payment_complete', array($this, 'track_order_completed')); … … 54 59 add_action('woocommerce_order_status_refunded', array($this, 'track_order_refunded'), 10, 2); 55 60 add_action('woocommerce_order_status_draft', array($this, 'track_order_draft'), 10, 1); 56 61 57 62 // Track customer creation 58 63 add_action('woocommerce_created_customer', array($this, 'track_customer_created'), 10, 3); 59 60 // Reset the tracking flag when the cart is updated or order completes/fails 61 add_action('woocommerce_cart_updated', array($this, 'reset_initiate_checkout_tracking')); 62 add_action('woocommerce_thankyou', array($this, 'track_order_thankyou'), 10); 64 65 // Reset tracking state for cart updates 66 add_action('woocommerce_cart_updated', array($this, 'reset_checkout_tracking')); 67 add_action('woocommerce_cart_emptied', array($this, 'reset_checkout_tracking')); 68 add_action('woocommerce_after_cart_item_quantity_update', array($this, 'reset_checkout_tracking')); 69 70 // Reset tracking for order completion/failure 63 71 add_action('woocommerce_order_status_completed', array($this, 'reset_initiate_checkout_tracking')); 64 72 add_action('woocommerce_order_status_failed', array($this, 'reset_initiate_checkout_tracking')); 65 66 73 74 // Track order thank you page 75 add_action('woocommerce_thankyou', array($this, 'track_order_thankyou'), 10); 76 67 77 // Initialize cart abandonment tracking 68 78 add_action('woocommerce_init', function() { 69 79 $this->init_cart_abandonment_tracking(); 70 80 }); 71 81 72 82 // Add session cleanup on successful order 73 83 add_action('woocommerce_checkout_order_processed', function() { … … 76 86 WC()->session->set('last_activity', null); 77 87 }); 78 88 79 89 // Wishlist Integration (if using WooCommerce Wishlist) 80 90 if (class_exists('YITH_WCWL')) { … … 84 94 } 85 95 } 96 97 /** 98 * Identify user on WooCommerce login 99 */ 100 public function identify_wc_user($credentials) { 101 if (!empty($credentials['user_login'])) { 102 $user = get_user_by('login', $credentials['user_login']); 103 if ($user) { 104 $this->send_user_identify_request($user); 105 } 106 } 107 return $credentials; 108 } 109 110 /** 111 * Send identify call to Usermaven API 112 * 113 * @param WP_User $user User object 114 */ 115 private function send_user_identify_request($user) { 116 if (!$user) { 117 return; 118 } 119 120 // Get WooCommerce customer 121 $customer = new WC_Customer($user->ID); 122 123 // Get custom user data 124 $roles = $user->roles; 125 $primary_role = !empty($roles) ? $roles[0] : ''; 126 127 // Get the anonymous_id from cookie if available 128 $eventn_cookie_name = '__eventn_id_' . $this->api_key; 129 $usermaven_cookie_name = 'usermaven_id_' . $this->api_key; 130 $anonymous_id = ''; 131 132 if (isset($_COOKIE[$eventn_cookie_name])) { 133 $anonymous_id = $_COOKIE[$eventn_cookie_name]; 134 } elseif (isset($_COOKIE[$usermaven_cookie_name])) { 135 $anonymous_id = $_COOKIE[$usermaven_cookie_name]; 136 } 137 138 $user_id = $user->ID; 139 $user_email = $user->user_email; 140 141 // if user id is null use email as user id 142 if (empty($user_id)) { 143 $user_id = $user_email; 144 } 145 146 // Prepare user data 147 $user_data = array( 148 'anonymous_id' => $anonymous_id, 149 'id' => (string) $user_id, 150 'email' => (string) $user_email, 151 'created_at' => date('Y-m-d\TH:i:s', strtotime($user->user_registered)), 152 'first_name' => $user->first_name, 153 'last_name' => $user->last_name, 154 'custom' => array( 155 'role' => $primary_role, 156 'username' => $user->user_login, 157 'display_name' => $user->display_name, 158 'billing_country' => $customer->get_billing_country(), 159 'shipping_country' => $customer->get_shipping_country(), 160 'is_paying_customer' => (bool) $customer->get_is_paying_customer() 161 ) 162 ); 163 164 // Prepare company data if available 165 $company_data = array(); 166 $company_name = $customer->get_billing_company(); 167 if (!empty($company_name)) { 168 $company_data = array( 169 'id' => 'wc_' . md5($company_name . $customer->get_billing_email()), 170 'name' => $company_name, 171 'created_at' => date('Y-m-d\TH:i:s', strtotime($user->user_registered)), 172 'custom' => array( 173 'billing_country' => $customer->get_billing_country(), 174 'billing_city' => $customer->get_billing_city(), 175 'billing_postcode' => $customer->get_billing_postcode() 176 ) 177 ); 178 } 179 180 // Send identify request using the API 181 $this->api->identify($user_data, $company_data); 182 } 183 86 184 87 185 /** … … 407 505 408 506 /** 409 * Track checkout initiation 410 */ 411 public function track_initiate_checkout() { 507 * Single entry point for tracking checkout initialization 508 * This ensures we don't have multiple competing triggers 509 */ 510 public function maybe_track_checkout_init() { 511 // Early exit conditions 412 512 if (WC()->cart->is_empty()) { 413 513 return; 414 514 } 415 515 516 // Get a unique identifier for current cart state 517 $cart_hash = WC()->cart->get_cart_hash(); 518 519 // Get stored tracking data 520 $tracked_cart_hash = WC()->session->get('usermaven_tracked_cart_hash'); 521 $last_tracked_time = WC()->session->get('usermaven_last_checkout_track_time'); 522 $current_time = time(); 523 524 // Check if this specific cart state has been tracked recently 525 if ($tracked_cart_hash === $cart_hash && 526 $last_tracked_time && 527 ($current_time - $last_tracked_time) < 300) { // 5 minutes threshold 528 return; 529 } 530 531 if (is_cart()) { 532 return; 533 } 534 535 // Check if we're actually on a checkout page/process 536 $is_checkout_context = ( 537 // Only track on actual checkout page, not cart page 538 (function_exists('is_checkout') && is_checkout()) || 539 // For custom checkout pages 540 (has_shortcode(get_post()->post_content ?? '', 'woocommerce_checkout')) || 541 // For AJAX checkout requests 542 (isset($_REQUEST['wc-ajax']) && $_REQUEST['wc-ajax'] === 'checkout') 543 ); 544 545 if (!$is_checkout_context) { 546 return; 547 } 548 549 $this->track_initiate_checkout($cart_hash); 550 WC()->session->set('usermaven_initiate_checkout_tracked', true); 551 } 552 553 /** 554 * Track checkout initiation with duplicate prevention 555 */ 556 private function track_initiate_checkout($cart_hash) { 416 557 // Prevent duplicate tracking 417 558 if (WC()->session->get('usermaven_initiate_checkout_tracked')) { 418 559 return; 419 560 } 420 561 421 562 $cart = WC()->cart; 422 563 $items = array(); 423 564 424 565 // Get WC Countries object for location handling 425 566 $wc_countries = new WC_Countries(); … … 430 571 continue; 431 572 } 432 573 433 574 // Get the parent product if this is a variation 434 575 $parent_product = $product; … … 436 577 $parent_product = wc_get_product($product->get_parent_id()); 437 578 } 438 579 439 580 // Get product categories from parent product 440 581 $categories = array(); … … 443 584 $categories = wp_list_pluck($terms, 'name'); 444 585 } 445 586 446 587 // Process variation attributes - keeping attribute_ prefix 447 588 $variation_attributes = array(); … … 451 592 } 452 593 } 453 594 454 595 // Get and validate prices 455 596 $unit_price = $product->get_price(); 456 597 $unit_price = $unit_price === '' ? 0.0 : (float) $unit_price; 457 598 458 599 $items[] = array( 459 600 'product_id' => (int) $parent_product->get_id(), … … 465 606 'line_tax' => (float) $cart_item['line_tax'], 466 607 'categories' => array_map('strval', $categories), 467 'variation_id' => !empty($cart_item['variation_id']) ? (int) $cart_item['variation_id'] : null,608 'variation_id' => isset($cart_item['variation_id']) ? (int) $cart_item['variation_id'] : null, 468 609 'variation_attributes' => $variation_attributes, 469 610 'is_on_sale' => (bool) $product->is_on_sale(), … … 471 612 ); 472 613 } 473 614 474 615 $billing_country_code = WC()->customer->get_billing_country(); 475 616 $shipping_country_code = WC()->customer->get_shipping_country(); 476 617 477 618 $event_attributes = array( 478 619 // Cart Financial Details 620 'cart_hash' => $cart_hash, 479 621 'total' => (float) $cart->get_total('numeric'), 480 622 'subtotal' => (float) $cart->get_subtotal(), 623 'cart_tax' => (float) $cart->get_cart_tax(), 481 624 'tax' => (float) $cart->get_total_tax(), 482 625 'shipping_total' => (float) $cart->get_shipping_total(), 483 626 'discount_total' => (float) $cart->get_discount_total(), 484 627 'currency' => (string) get_woocommerce_currency(), 485 628 486 629 // Cart Contents 487 630 'items_count' => (int) $cart->get_cart_contents_count(), … … 489 632 'items' => $items, 490 633 'weight_total' => (float) $cart->get_cart_contents_weight(), 491 634 492 635 // Applied Discounts 493 636 'coupons' => array_map('strval', $cart->get_applied_coupons()), 494 637 'coupon_discount' => (float) $cart->get_discount_total(), 495 638 'tax_discount' => (float) $cart->get_discount_tax(), 496 639 497 640 // Shipping Information 498 641 'needs_shipping' => (bool) $cart->needs_shipping(), … … 508 651 'shipping_country_code' => (string) $shipping_country_code, 509 652 'shipping_country_name' => (string) ($shipping_country_code ? $wc_countries->countries[$shipping_country_code] : ''), 653 'payment_methods' => array_keys(WC()->payment_gateways->get_available_payment_gateways()), 510 654 511 655 // Additional Context 512 656 'device_type' => (string) (wp_is_mobile() ? 'mobile' : 'desktop'), 513 657 'referrer' => (string) (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''), 514 'timestamp' => current_time('mysql'),658 'timestamp' => (string) current_time('mysql'), 515 659 'checkout_page' => (string) (is_checkout() ? 'standard' : 'custom'), 516 660 'user_agent' => (string) (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''), 517 'cart_hash' => (string) WC()->cart->get_cart_hash()518 ); 519 661 ); 662 663 // Send the event 520 664 $this->send_event('initiated_checkout', $event_attributes); 521 522 // Set the session variable to prevent duplicate tracking 523 WC()->session->set('usermaven_initiate_checkout_tracked', true); 665 666 // Update tracking state 667 WC()->session->set('usermaven_tracked_cart_hash', $cart_hash); 668 WC()->session->set('usermaven_last_checkout_track_time', time()); 669 } 670 671 /** 672 * Reset tracking state when cart is updated 673 */ 674 public function reset_checkout_tracking() { 675 WC()->session->set('usermaven_tracked_cart_hash', null); 676 WC()->session->set('usermaven_last_checkout_track_time', null); 524 677 } 525 678 … … 869 1022 870 1023 /** 871 * Track order submission with full details 872 * 873 * @param int $order_id The WooCommerce order ID 874 * @param array $posted_data Posted checkout form data 875 * @param WC_Order $order The WooCommerce order object 876 */ 877 public function track_order_submission($order_id, $posted_data, $order) { 878 if (!$order_id || !$order) { 879 return; 880 } 881 1024 * Early tracking for order submission to catch all checkout types 1025 */ 1026 public function track_order_submission($order_id) { 1027 error_log('track_order_submission early triggered for order: ' . $order_id); 1028 1029 WC()->session->set('usermaven_initiate_checkout_tracked', null); 1030 1031 if (!$order_id) { 1032 return; 1033 } 1034 1035 $order = wc_get_order($order_id); 1036 if (!$order) { 1037 return; 1038 } 1039 1040 // Check if this order has already been tracked 1041 $tracked = get_post_meta($order_id, '_usermaven_order_tracked', true); 1042 if ($tracked) { 1043 return; 1044 } 1045 1046 // Reset checkout tracking 1047 $this->reset_checkout_tracking(); 1048 1049 // Rest of your tracking code 882 1050 $location_details = $this->get_location_details($order); 883 1051 $items = $this->get_formatted_order_items($order); 884 1052 885 // Get commonattributes1053 // event attributes 886 1054 $event_attributes = array_merge( 887 1055 $this->get_common_order_attributes($order, $location_details), … … 906 1074 907 1075 $this->send_event('order_submitted', $event_attributes); 1076 1077 // Mark this order as tracked 1078 update_post_meta($order_id, '_usermaven_order_tracked', true); 908 1079 } 909 1080 … … 1574 1745 WC()->session->set('landing_page', $_SERVER['REQUEST_URI']); 1575 1746 } 1576 1747 1577 1748 // Do NOT update last_activity on every page load — only when user interacts with the cart or starts checkout. 1578 1749 // This prevents continuous resets that block abandonment detection. -
usermaven/tags/1.1.3/includes/class-usermaven.php
r3221608 r3240206 81 81 $this->version = USERMAVEN_VERSION; 82 82 } else { 83 $this->version = '1.1. 1';83 $this->version = '1.1.3'; 84 84 } 85 85 $this->plugin_name = 'usermaven'; -
usermaven/tags/1.1.3/usermaven.php
r3221608 r3240206 19 19 * Description: The Easiest Website and Product Analytics Platform 20 20 21 * Version: 1.1. 121 * Version: 1.1.3 22 22 * Author: Usermaven 23 23 * Author URI: https://usermaven.com/ … … 38 38 * Rename this for your plugin and update it as you release new versions. 39 39 */ 40 define( 'USERMAVEN_VERSION', '1.1. 1' );40 define( 'USERMAVEN_VERSION', '1.1.3' ); 41 41 42 42 /** -
usermaven/trunk/README.txt
r3221608 r3240206 6 6 Tested up to: 6.7.1 7 7 Requires PHP: 5.6 8 Stable tag: 1.1. 18 Stable tag: 1.1.3 9 9 License: Massachusetts Institute of Technology (MIT) license 10 10 License URI: https://opensource.org/licenses/MIT -
usermaven/trunk/includes/class-usermaven-api.php
r3217559 r3240206 9 9 $this->api_key = get_option('usermaven_api_key'); 10 10 $this->api_url = "$tracking_host/api/v1/s2s/event"; 11 } 12 13 public function identify($user_data, $company_data = []) { 14 $url = $this->api_url . "?token=$this->api_key.$this->server_token"; 15 16 // Get current timestamp in milliseconds 17 $current_timestamp_ms = round(microtime(true) * 1000); 18 $doc_encoding = get_bloginfo('charset'); 19 20 $data = [ 21 'api_key' => $this->api_key, 22 'event_type' => 'user_identify', 23 '_timestamp' => (string)$current_timestamp_ms, 24 'user' => $user_data, 25 'company' => [ 26 'id' => $company_data['id'] ?? '', 27 'name' => $company_data['name'] ?? '', 28 ], 29 'src' => 'http', 30 'url' => $_SERVER['HTTP_REFERER'] ?? '', 31 'page_title' => wp_get_document_title(), 32 'doc_path' => $_SERVER['REQUEST_URI'] ?? '', 33 'doc_host' => $_SERVER['HTTP_HOST'] ?? '', 34 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 35 'user_language' => $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '', 36 'doc_encoding' => (string) $doc_encoding, 37 ]; 38 39 $response = wp_remote_post($url, [ 40 'body' => json_encode($data), 41 'headers' => ['Content-Type' => 'application/json'] 42 ]); 43 44 if (is_wp_error($response)) { 45 error_log('Usermaven API Error: ' . $response->get_error_message()); 46 return false; 47 } 48 49 $body = wp_remote_retrieve_body($response); 50 $result = json_decode($body, true); 51 return $result['status'] === 'ok'; 11 52 } 12 53 -
usermaven/trunk/includes/class-usermaven-woocommerce.php
r3221608 r3240206 31 31 */ 32 32 private function init_hooks() { 33 // Track on WooCommerce specific login 34 add_action('woocommerce_login_credentials', array($this, 'identify_wc_user'), 10, 2); 35 33 36 // Product Viewing 34 37 add_action('template_redirect', array($this, 'track_product_view')); 35 38 36 39 // Cart Actions 37 40 add_action('woocommerce_add_to_cart', array($this, 'track_add_to_cart'), 10, 6); 38 41 add_action('woocommerce_cart_item_removed', array($this, 'track_remove_from_cart'), 10, 2); 39 42 add_action('woocommerce_after_cart_item_quantity_update', array($this, 'track_cart_update'), 10, 4); 40 41 // Checkout Process 42 add_action('woocommerce_before_checkout_form', array($this, 'track_initiate_checkout'), 10); 43 add_action('woocommerce_checkout_order_processed', array($this, 'track_order_submission'), 10, 3); 44 43 44 // Checkout Process - Consolidated tracking 45 // add_action('woocommerce_before_checkout_form', array($this, 'track_initiate_checkout'), 10); // Removed this because it was not triggering for custom checkout pages 46 add_action('wp', array($this, 'maybe_track_checkout_init')); 47 // add_action('woocommerce_checkout_order_processed', array($this, 'track_order_submission'), 10, 3); // Removed this because it was not triggering for custom checkout pages 48 add_action('woocommerce_new_order', array($this, 'track_order_submission'), 10, 1); 49 45 50 // Order Status and Completion 46 51 // add_action('woocommerce_payment_complete', array($this, 'track_order_completed')); … … 54 59 add_action('woocommerce_order_status_refunded', array($this, 'track_order_refunded'), 10, 2); 55 60 add_action('woocommerce_order_status_draft', array($this, 'track_order_draft'), 10, 1); 56 61 57 62 // Track customer creation 58 63 add_action('woocommerce_created_customer', array($this, 'track_customer_created'), 10, 3); 59 60 // Reset the tracking flag when the cart is updated or order completes/fails 61 add_action('woocommerce_cart_updated', array($this, 'reset_initiate_checkout_tracking')); 62 add_action('woocommerce_thankyou', array($this, 'track_order_thankyou'), 10); 64 65 // Reset tracking state for cart updates 66 add_action('woocommerce_cart_updated', array($this, 'reset_checkout_tracking')); 67 add_action('woocommerce_cart_emptied', array($this, 'reset_checkout_tracking')); 68 add_action('woocommerce_after_cart_item_quantity_update', array($this, 'reset_checkout_tracking')); 69 70 // Reset tracking for order completion/failure 63 71 add_action('woocommerce_order_status_completed', array($this, 'reset_initiate_checkout_tracking')); 64 72 add_action('woocommerce_order_status_failed', array($this, 'reset_initiate_checkout_tracking')); 65 66 73 74 // Track order thank you page 75 add_action('woocommerce_thankyou', array($this, 'track_order_thankyou'), 10); 76 67 77 // Initialize cart abandonment tracking 68 78 add_action('woocommerce_init', function() { 69 79 $this->init_cart_abandonment_tracking(); 70 80 }); 71 81 72 82 // Add session cleanup on successful order 73 83 add_action('woocommerce_checkout_order_processed', function() { … … 76 86 WC()->session->set('last_activity', null); 77 87 }); 78 88 79 89 // Wishlist Integration (if using WooCommerce Wishlist) 80 90 if (class_exists('YITH_WCWL')) { … … 84 94 } 85 95 } 96 97 /** 98 * Identify user on WooCommerce login 99 */ 100 public function identify_wc_user($credentials) { 101 if (!empty($credentials['user_login'])) { 102 $user = get_user_by('login', $credentials['user_login']); 103 if ($user) { 104 $this->send_user_identify_request($user); 105 } 106 } 107 return $credentials; 108 } 109 110 /** 111 * Send identify call to Usermaven API 112 * 113 * @param WP_User $user User object 114 */ 115 private function send_user_identify_request($user) { 116 if (!$user) { 117 return; 118 } 119 120 // Get WooCommerce customer 121 $customer = new WC_Customer($user->ID); 122 123 // Get custom user data 124 $roles = $user->roles; 125 $primary_role = !empty($roles) ? $roles[0] : ''; 126 127 // Get the anonymous_id from cookie if available 128 $eventn_cookie_name = '__eventn_id_' . $this->api_key; 129 $usermaven_cookie_name = 'usermaven_id_' . $this->api_key; 130 $anonymous_id = ''; 131 132 if (isset($_COOKIE[$eventn_cookie_name])) { 133 $anonymous_id = $_COOKIE[$eventn_cookie_name]; 134 } elseif (isset($_COOKIE[$usermaven_cookie_name])) { 135 $anonymous_id = $_COOKIE[$usermaven_cookie_name]; 136 } 137 138 $user_id = $user->ID; 139 $user_email = $user->user_email; 140 141 // if user id is null use email as user id 142 if (empty($user_id)) { 143 $user_id = $user_email; 144 } 145 146 // Prepare user data 147 $user_data = array( 148 'anonymous_id' => $anonymous_id, 149 'id' => (string) $user_id, 150 'email' => (string) $user_email, 151 'created_at' => date('Y-m-d\TH:i:s', strtotime($user->user_registered)), 152 'first_name' => $user->first_name, 153 'last_name' => $user->last_name, 154 'custom' => array( 155 'role' => $primary_role, 156 'username' => $user->user_login, 157 'display_name' => $user->display_name, 158 'billing_country' => $customer->get_billing_country(), 159 'shipping_country' => $customer->get_shipping_country(), 160 'is_paying_customer' => (bool) $customer->get_is_paying_customer() 161 ) 162 ); 163 164 // Prepare company data if available 165 $company_data = array(); 166 $company_name = $customer->get_billing_company(); 167 if (!empty($company_name)) { 168 $company_data = array( 169 'id' => 'wc_' . md5($company_name . $customer->get_billing_email()), 170 'name' => $company_name, 171 'created_at' => date('Y-m-d\TH:i:s', strtotime($user->user_registered)), 172 'custom' => array( 173 'billing_country' => $customer->get_billing_country(), 174 'billing_city' => $customer->get_billing_city(), 175 'billing_postcode' => $customer->get_billing_postcode() 176 ) 177 ); 178 } 179 180 // Send identify request using the API 181 $this->api->identify($user_data, $company_data); 182 } 183 86 184 87 185 /** … … 407 505 408 506 /** 409 * Track checkout initiation 410 */ 411 public function track_initiate_checkout() { 507 * Single entry point for tracking checkout initialization 508 * This ensures we don't have multiple competing triggers 509 */ 510 public function maybe_track_checkout_init() { 511 // Early exit conditions 412 512 if (WC()->cart->is_empty()) { 413 513 return; 414 514 } 415 515 516 // Get a unique identifier for current cart state 517 $cart_hash = WC()->cart->get_cart_hash(); 518 519 // Get stored tracking data 520 $tracked_cart_hash = WC()->session->get('usermaven_tracked_cart_hash'); 521 $last_tracked_time = WC()->session->get('usermaven_last_checkout_track_time'); 522 $current_time = time(); 523 524 // Check if this specific cart state has been tracked recently 525 if ($tracked_cart_hash === $cart_hash && 526 $last_tracked_time && 527 ($current_time - $last_tracked_time) < 300) { // 5 minutes threshold 528 return; 529 } 530 531 if (is_cart()) { 532 return; 533 } 534 535 // Check if we're actually on a checkout page/process 536 $is_checkout_context = ( 537 // Only track on actual checkout page, not cart page 538 (function_exists('is_checkout') && is_checkout()) || 539 // For custom checkout pages 540 (has_shortcode(get_post()->post_content ?? '', 'woocommerce_checkout')) || 541 // For AJAX checkout requests 542 (isset($_REQUEST['wc-ajax']) && $_REQUEST['wc-ajax'] === 'checkout') 543 ); 544 545 if (!$is_checkout_context) { 546 return; 547 } 548 549 $this->track_initiate_checkout($cart_hash); 550 WC()->session->set('usermaven_initiate_checkout_tracked', true); 551 } 552 553 /** 554 * Track checkout initiation with duplicate prevention 555 */ 556 private function track_initiate_checkout($cart_hash) { 416 557 // Prevent duplicate tracking 417 558 if (WC()->session->get('usermaven_initiate_checkout_tracked')) { 418 559 return; 419 560 } 420 561 421 562 $cart = WC()->cart; 422 563 $items = array(); 423 564 424 565 // Get WC Countries object for location handling 425 566 $wc_countries = new WC_Countries(); … … 430 571 continue; 431 572 } 432 573 433 574 // Get the parent product if this is a variation 434 575 $parent_product = $product; … … 436 577 $parent_product = wc_get_product($product->get_parent_id()); 437 578 } 438 579 439 580 // Get product categories from parent product 440 581 $categories = array(); … … 443 584 $categories = wp_list_pluck($terms, 'name'); 444 585 } 445 586 446 587 // Process variation attributes - keeping attribute_ prefix 447 588 $variation_attributes = array(); … … 451 592 } 452 593 } 453 594 454 595 // Get and validate prices 455 596 $unit_price = $product->get_price(); 456 597 $unit_price = $unit_price === '' ? 0.0 : (float) $unit_price; 457 598 458 599 $items[] = array( 459 600 'product_id' => (int) $parent_product->get_id(), … … 465 606 'line_tax' => (float) $cart_item['line_tax'], 466 607 'categories' => array_map('strval', $categories), 467 'variation_id' => !empty($cart_item['variation_id']) ? (int) $cart_item['variation_id'] : null,608 'variation_id' => isset($cart_item['variation_id']) ? (int) $cart_item['variation_id'] : null, 468 609 'variation_attributes' => $variation_attributes, 469 610 'is_on_sale' => (bool) $product->is_on_sale(), … … 471 612 ); 472 613 } 473 614 474 615 $billing_country_code = WC()->customer->get_billing_country(); 475 616 $shipping_country_code = WC()->customer->get_shipping_country(); 476 617 477 618 $event_attributes = array( 478 619 // Cart Financial Details 620 'cart_hash' => $cart_hash, 479 621 'total' => (float) $cart->get_total('numeric'), 480 622 'subtotal' => (float) $cart->get_subtotal(), 623 'cart_tax' => (float) $cart->get_cart_tax(), 481 624 'tax' => (float) $cart->get_total_tax(), 482 625 'shipping_total' => (float) $cart->get_shipping_total(), 483 626 'discount_total' => (float) $cart->get_discount_total(), 484 627 'currency' => (string) get_woocommerce_currency(), 485 628 486 629 // Cart Contents 487 630 'items_count' => (int) $cart->get_cart_contents_count(), … … 489 632 'items' => $items, 490 633 'weight_total' => (float) $cart->get_cart_contents_weight(), 491 634 492 635 // Applied Discounts 493 636 'coupons' => array_map('strval', $cart->get_applied_coupons()), 494 637 'coupon_discount' => (float) $cart->get_discount_total(), 495 638 'tax_discount' => (float) $cart->get_discount_tax(), 496 639 497 640 // Shipping Information 498 641 'needs_shipping' => (bool) $cart->needs_shipping(), … … 508 651 'shipping_country_code' => (string) $shipping_country_code, 509 652 'shipping_country_name' => (string) ($shipping_country_code ? $wc_countries->countries[$shipping_country_code] : ''), 653 'payment_methods' => array_keys(WC()->payment_gateways->get_available_payment_gateways()), 510 654 511 655 // Additional Context 512 656 'device_type' => (string) (wp_is_mobile() ? 'mobile' : 'desktop'), 513 657 'referrer' => (string) (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''), 514 'timestamp' => current_time('mysql'),658 'timestamp' => (string) current_time('mysql'), 515 659 'checkout_page' => (string) (is_checkout() ? 'standard' : 'custom'), 516 660 'user_agent' => (string) (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''), 517 'cart_hash' => (string) WC()->cart->get_cart_hash()518 ); 519 661 ); 662 663 // Send the event 520 664 $this->send_event('initiated_checkout', $event_attributes); 521 522 // Set the session variable to prevent duplicate tracking 523 WC()->session->set('usermaven_initiate_checkout_tracked', true); 665 666 // Update tracking state 667 WC()->session->set('usermaven_tracked_cart_hash', $cart_hash); 668 WC()->session->set('usermaven_last_checkout_track_time', time()); 669 } 670 671 /** 672 * Reset tracking state when cart is updated 673 */ 674 public function reset_checkout_tracking() { 675 WC()->session->set('usermaven_tracked_cart_hash', null); 676 WC()->session->set('usermaven_last_checkout_track_time', null); 524 677 } 525 678 … … 869 1022 870 1023 /** 871 * Track order submission with full details 872 * 873 * @param int $order_id The WooCommerce order ID 874 * @param array $posted_data Posted checkout form data 875 * @param WC_Order $order The WooCommerce order object 876 */ 877 public function track_order_submission($order_id, $posted_data, $order) { 878 if (!$order_id || !$order) { 879 return; 880 } 881 1024 * Early tracking for order submission to catch all checkout types 1025 */ 1026 public function track_order_submission($order_id) { 1027 error_log('track_order_submission early triggered for order: ' . $order_id); 1028 1029 WC()->session->set('usermaven_initiate_checkout_tracked', null); 1030 1031 if (!$order_id) { 1032 return; 1033 } 1034 1035 $order = wc_get_order($order_id); 1036 if (!$order) { 1037 return; 1038 } 1039 1040 // Check if this order has already been tracked 1041 $tracked = get_post_meta($order_id, '_usermaven_order_tracked', true); 1042 if ($tracked) { 1043 return; 1044 } 1045 1046 // Reset checkout tracking 1047 $this->reset_checkout_tracking(); 1048 1049 // Rest of your tracking code 882 1050 $location_details = $this->get_location_details($order); 883 1051 $items = $this->get_formatted_order_items($order); 884 1052 885 // Get commonattributes1053 // event attributes 886 1054 $event_attributes = array_merge( 887 1055 $this->get_common_order_attributes($order, $location_details), … … 906 1074 907 1075 $this->send_event('order_submitted', $event_attributes); 1076 1077 // Mark this order as tracked 1078 update_post_meta($order_id, '_usermaven_order_tracked', true); 908 1079 } 909 1080 … … 1574 1745 WC()->session->set('landing_page', $_SERVER['REQUEST_URI']); 1575 1746 } 1576 1747 1577 1748 // Do NOT update last_activity on every page load — only when user interacts with the cart or starts checkout. 1578 1749 // This prevents continuous resets that block abandonment detection. -
usermaven/trunk/includes/class-usermaven.php
r3221608 r3240206 81 81 $this->version = USERMAVEN_VERSION; 82 82 } else { 83 $this->version = '1.1. 1';83 $this->version = '1.1.3'; 84 84 } 85 85 $this->plugin_name = 'usermaven'; -
usermaven/trunk/usermaven.php
r3221608 r3240206 19 19 * Description: The Easiest Website and Product Analytics Platform 20 20 21 * Version: 1.1. 121 * Version: 1.1.3 22 22 * Author: Usermaven 23 23 * Author URI: https://usermaven.com/ … … 38 38 * Rename this for your plugin and update it as you release new versions. 39 39 */ 40 define( 'USERMAVEN_VERSION', '1.1. 1' );40 define( 'USERMAVEN_VERSION', '1.1.3' ); 41 41 42 42 /**
Note: See TracChangeset
for help on using the changeset viewer.