diff --git a/CHANGELOG.md b/CHANGELOG.md index 683179e8..33e36683 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 2026-08-05 5.0.15 +* Fix cart tracking event payload and cart ID lifecycle + ## 2026-06-18 5.0.14 * WordPress 7.0 compatibility: updated Tested up to * Fixed jQuery dependency registration for plugin scripts diff --git a/VERSION b/VERSION index 4b57201a..1ed9c641 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.14 +5.0.15 diff --git a/src/assets/js/retailcrm-tracker.js b/src/assets/js/retailcrm-tracker.js index 68d019e5..ceb8dd69 100644 --- a/src/assets/js/retailcrm-tracker.js +++ b/src/assets/js/retailcrm-tracker.js @@ -68,21 +68,23 @@ function startTrack(...trackerEvents) function sendCartChange() { - let cart = {}; - cart.items = []; - - getCartItems().then(function(cartItems) { - cartItems.forEach(item => { - cart.items.push({ - external_id: item.id, - xml_id: item.sku, - price: item.price, - quantity: item.quantity - }); - }); - }); + getCartItems().then(function(response) { + if (!response?.cart_id || !Array.isArray(response.items) || response.items.length === 0) { + return; + } + + const cart = { + cart_id: response.cart_id, + items: response.items.map(function(item) { + return { + external_id: item.id, + xml_id: item.sku, + price: item.price, + quantity: item.quantity + }; + }) + }; - if (cart.items !== []) { getCustomerInfo().then(function (customer) { if (!customer?.externalId) { return; @@ -93,7 +95,7 @@ function startTrack(...trackerEvents) ocapi.event('cart', cart); }, 1000); }); - } + }); } async function getCustomerInfo() { diff --git a/src/include/class-wc-retailcrm-base.php b/src/include/class-wc-retailcrm-base.php index 076bd85b..354c0cae 100644 --- a/src/include/class-wc-retailcrm-base.php +++ b/src/include/class-wc-retailcrm-base.php @@ -23,6 +23,7 @@ class WC_Retailcrm_Base extends WC_Retailcrm_Abstracts_Settings { const ASSETS_DIR = '/woo-retailcrm/assets'; + const TRACKER_CART_ID_SESSION_KEY = 'retailcrm_tracker_cart_id'; /** @var WC_Retailcrm_Proxy|WC_Retailcrm_Client_V5|bool */ protected $apiClient; @@ -195,6 +196,16 @@ public function __construct($retailcrm = false) } function get_cart_items_for_tracker() + { + wp_send_json_success($this->get_cart_data_for_tracker()); + } + + /** + * Get the current cart data for the JS tracker. + * + * @return array + */ + public function get_cart_data_for_tracker() { $cartItems = []; @@ -209,7 +220,26 @@ function get_cart_items_for_tracker() ]; } - wp_send_json_success($cartItems); + $cartId = null; + $session = WC()->session; + + if (empty($cartItems)) { + if ($session) { + $session->__unset(self::TRACKER_CART_ID_SESSION_KEY); + } + } elseif ($session) { + $cartId = $session->get(self::TRACKER_CART_ID_SESSION_KEY); + + if (empty($cartId)) { + $cartId = wp_generate_uuid4(); + $session->set(self::TRACKER_CART_ID_SESSION_KEY, $cartId); + } + } + + return [ + 'cart_id' => $cartId, + 'items' => $cartItems, + ]; } function get_customer_info_for_tracker() @@ -531,6 +561,10 @@ public function retailcrm_process_order($order_id) WC_Retailcrm_Logger::setHook(current_action(), $order_id); $this->orders->orderCreate($order_id); + + if (WC()->session) { + WC()->session->__unset(self::TRACKER_CART_ID_SESSION_KEY); + } } /** diff --git a/src/readme.txt b/src/readme.txt index 693836c4..b10b5005 100644 --- a/src/readme.txt +++ b/src/readme.txt @@ -4,7 +4,7 @@ Tags: crm, marketing, e-com Requires PHP: 7.1 Requires at least: 5.3 Tested up to: 7.0 -Stable tag: 5.0.14 +Stable tag: 5.0.15 License: MIT License URI: https://github.com/retailcrm/woocommerce-module/blob/master/LICENSE @@ -47,6 +47,9 @@ Make sure you have a specific API key must for each store. == Changelog == += 5.0.15 = +* Fix cart tracking event payload and cart ID lifecycle + = 5.0.14 = * WordPress 7.0 compatibility diff --git a/src/uninstall.php b/src/uninstall.php index 569e9bfc..5694d44a 100644 --- a/src/uninstall.php +++ b/src/uninstall.php @@ -16,7 +16,7 @@ * * @link https://wordpress.org/plugins/woo-retailcrm/ * - * @version 5.0.14 + * @version 5.0.15 * * @package RetailCRM */ diff --git a/src/woo-retailcrm.php b/src/woo-retailcrm.php index e8f322d9..0d137aed 100644 --- a/src/woo-retailcrm.php +++ b/src/woo-retailcrm.php @@ -7,7 +7,7 @@ * Author URI: http://retailcrm.pro/ * License: MIT * License URI: https://github.com/retailcrm/woocommerce-module/blob/master/LICENSE - * Version: 5.0.14 + * Version: 5.0.15 * Tested up to: 7.0 * Requires Plugins: woocommerce * WC requires at least: 5.4 @@ -30,7 +30,7 @@ class WC_Integration_Retailcrm { const WOOCOMMERCE_SLUG = 'woocommerce'; const WOOCOMMERCE_PLUGIN_PATH = 'woocommerce/woocommerce.php'; - const MODULE_VERSION = '5.0.14'; + const MODULE_VERSION = '5.0.15'; private static $instance; diff --git a/tests/test-wc-retailcrm-base.php b/tests/test-wc-retailcrm-base.php index 8fb27c22..eb9a7720 100644 --- a/tests/test-wc-retailcrm-base.php +++ b/tests/test-wc-retailcrm-base.php @@ -274,6 +274,71 @@ public function test_subscribed_checkbox() ob_end_clean(); } + public function test_cart_id_lifecycle() + { + $product = WC_Helper_Product::create_simple_product(); + $product->set_sku('SKU-123'); + $product->set_regular_price(159); + $product->set_price(159); + $product->save(); + + WC()->cart->empty_cart(); + WC()->session->__unset(WC_Retailcrm_Base::TRACKER_CART_ID_SESSION_KEY); + WC()->cart->add_to_cart($product->get_id(), 2); + + $initialCart = $this->baseRetailcrm->get_cart_data_for_tracker(); + + $this->assertNotEmpty($initialCart['cart_id']); + $this->assertTrue(wp_is_uuid($initialCart['cart_id'])); + $this->assertCount(1, $initialCart['items']); + $this->assertEquals((string) $product->get_id(), $initialCart['items'][0]['id']); + $this->assertEquals('SKU-123', $initialCart['items'][0]['sku']); + $this->assertEquals(wc_get_price_including_tax($product), $initialCart['items'][0]['price']); + $this->assertEquals(2, $initialCart['items'][0]['quantity']); + + $updatedCart = $this->baseRetailcrm->get_cart_data_for_tracker(); + + $this->assertEquals($initialCart['cart_id'], $updatedCart['cart_id']); + + WC()->cart->empty_cart(); + $emptyCart = $this->baseRetailcrm->get_cart_data_for_tracker(); + + $this->assertNull($emptyCart['cart_id']); + $this->assertSame([], $emptyCart['items']); + $this->assertNull(WC()->session->get(WC_Retailcrm_Base::TRACKER_CART_ID_SESSION_KEY)); + + WC()->cart->add_to_cart($product->get_id()); + $newCart = $this->baseRetailcrm->get_cart_data_for_tracker(); + + $this->assertNotEquals($initialCart['cart_id'], $newCart['cart_id']); + + WC()->cart->empty_cart(); + WC()->session->__unset(WC_Retailcrm_Base::TRACKER_CART_ID_SESSION_KEY); + } + + public function test_cart_id_cleared_after_checkout() + { + $orders = $this + ->getMockBuilder('\WC_Retailcrm_Orders') + ->disableOriginalConstructor() + ->setMethods(['orderCreate']) + ->getMock(); + $orders + ->expects($this->once()) + ->method('orderCreate') + ->with(123); + + $ordersProperty = new ReflectionProperty(WC_Retailcrm_Base::class, 'orders'); + $ordersProperty->setAccessible(true); + $ordersProperty->setValue($this->baseRetailcrm, $orders); + + WC()->session->set(WC_Retailcrm_Base::TRACKER_CART_ID_SESSION_KEY, wp_generate_uuid4()); + + $this->baseRetailcrm->retailcrm_process_order(123); + + $this->assertNull(WC()->session->get(WC_Retailcrm_Base::TRACKER_CART_ID_SESSION_KEY)); + } + public function test_initialize_whatsapp() { ob_start();