diff --git a/app/code/core/Mage/GoogleAnalytics/Block/Ga.php b/app/code/core/Mage/GoogleAnalytics/Block/Ga.php index b706fd83b53..01d210f0d17 100644 --- a/app/code/core/Mage/GoogleAnalytics/Block/Ga.php +++ b/app/code/core/Mage/GoogleAnalytics/Block/Ga.php @@ -131,36 +131,32 @@ protected function _getEnhancedEcommerceDataForAnalytics4() $request = $this->getRequest(); $moduleName = $request->getModuleName(); $controllerName = $request->getControllerName(); + $helper = Mage::helper('googleanalytics'); /** * This event signifies that an item was removed from a cart. * * @link https://developers.google.com/tag-platform/gtagjs/reference/events#remove_from_cart */ - $removedProducts = Mage::getSingleton('core/session')->getRemovedProductsCart(); + $removedProducts = Mage::getSingleton('core/session')->getRemovedProductsForAnalytics(); if ($removedProducts) { foreach ($removedProducts as $removedProduct) { - $_removedProduct = Mage::getModel('catalog/product')->load($removedProduct); $eventData = []; $eventData['currency'] = Mage::app()->getStore()->getCurrentCurrencyCode(); - $eventData['value'] = number_format($_removedProduct->getFinalPrice(), 2, '.', ''); + $eventData['value'] = $helper->formatPrice($removedProduct['price'] * $removedProduct['qty']); $eventData['items'] = []; $_item = [ - 'item_id' => $_removedProduct->getSku(), - 'item_name' => $_removedProduct->getName(), - 'price' => number_format($_removedProduct->getFinalPrice(), 2, '.', ''), + 'item_id' => $removedProduct['sku'], + 'item_name' => $removedProduct['name'], + 'price' => $helper->formatPrice($removedProduct['price']), + 'quantity' => (int) $removedProduct['qty'], + 'item_brand' => $removedProduct['manufacturer'], + 'item_category' => $removedProduct['category'], ]; - if ($_removedProduct->getAttributeText('manufacturer')) { - $_item['item_brand'] = $_removedProduct->getAttributeText('manufacturer'); - } - $itemCategory = Mage::helper('googleanalytics')->getLastCategoryName($_removedProduct); - if ($itemCategory) { - $_item['item_category'] = $itemCategory; - } - array_push($eventData['items'], $_item); + $eventData['items'][] = $_item; $result[] = "gtag('event', 'remove_from_cart', " . json_encode($eventData, JSON_THROW_ON_ERROR) . ");"; } - Mage::getSingleton('core/session')->unsRemovedProductsCart(); + Mage::getSingleton('core/session')->unsRemovedProductsForAnalytics(); } /** @@ -168,30 +164,24 @@ protected function _getEnhancedEcommerceDataForAnalytics4() * * @link https://developers.google.com/tag-platform/gtagjs/reference/events#add_to_cart */ - $addedProducts = Mage::getSingleton('core/session')->getAddedProductsCart(); + $addedProducts = Mage::getSingleton('core/session')->getAddedProductsForAnalytics(); if ($addedProducts) { - foreach ($addedProducts as $addedProduct) { - $_addedProduct = Mage::getModel('catalog/product')->load($addedProduct); + foreach ($addedProducts as $_addedProduct) { $eventData = []; $eventData['currency'] = Mage::app()->getStore()->getCurrentCurrencyCode(); - $eventData['value'] = number_format($_addedProduct->getFinalPrice(), 2, '.', ''); + $eventData['value'] = $helper->formatPrice($_addedProduct['price'] * $_addedProduct['qty']); $eventData['items'] = []; $_item = [ - 'item_id' => $_addedProduct->getSku(), - 'item_name' => $_addedProduct->getName(), - 'price' => number_format($_addedProduct->getFinalPrice(), 2, '.', ''), + 'item_id' => $_addedProduct['sku'], + 'item_name' => $_addedProduct['name'], + 'price' => $helper->formatPrice($_addedProduct['price']), + 'quantity' => (int) $_addedProduct['qty'], + 'item_brand' => $_addedProduct['manufacturer'], + 'item_category' => $_addedProduct['category'], ]; - if ($_addedProduct->getAttributeText('manufacturer')) { - $_item['item_brand'] = $_addedProduct->getAttributeText('manufacturer'); - } - - $itemCategory = Mage::helper('googleanalytics')->getLastCategoryName($_addedProduct); - if ($itemCategory) { - $_item['item_category'] = $itemCategory; - } - array_push($eventData['items'], $_item); + $eventData['items'][] = $_item; $result[] = "gtag('event', 'add_to_cart', " . json_encode($eventData, JSON_THROW_ON_ERROR) . ");"; - Mage::getSingleton('core/session')->unsAddedProductsCart(); + Mage::getSingleton('core/session')->unsAddedProductsForAnalytics(); } } @@ -205,14 +195,14 @@ protected function _getEnhancedEcommerceDataForAnalytics4() $category = Mage::registry('current_category') ? Mage::registry('current_category')->getName() : false; $eventData = []; $eventData['currency'] = Mage::app()->getStore()->getCurrentCurrencyCode(); - $eventData['value'] = number_format($productViewed->getFinalPrice(), 2, '.', ''); + $eventData['value'] = $helper->formatPrice($productViewed->getFinalPrice()); $eventData['items'] = []; $_item = [ 'item_id' => $productViewed->getSku(), 'item_name' => $productViewed->getName(), 'list_name' => 'Product Detail Page', 'item_category' => $category, - 'price' => number_format($productViewed->getFinalPrice(), 2, '.', ''), + 'price' => $helper->formatPrice($productViewed->getFinalPrice()), ]; if ($productViewed->getAttributeText('manufacturer')) { $_item['item_brand'] = $productViewed->getAttributeText('manufacturer'); @@ -251,7 +241,7 @@ protected function _getEnhancedEcommerceDataForAnalytics4() 'item_id' => $productViewed->getSku(), 'index' => $index, 'item_name' => $productViewed->getName(), - 'price' => number_format($productViewed->getFinalPrice(), 2, '.', ''), + 'price' => $helper->formatPrice($productViewed->getFinalPrice()), ]; if ($productViewed->getAttributeText('manufacturer')) { $_item['item_brand'] = $productViewed->getAttributeText('manufacturer'); @@ -263,7 +253,7 @@ protected function _getEnhancedEcommerceDataForAnalytics4() $index++; $eventData['value'] += $productViewed->getFinalPrice(); } - $eventData['value'] = number_format($eventData['value'], 2, '.', ''); + $eventData['value'] = $helper->formatPrice($eventData['value']); $result[] = "gtag('event', 'view_item_list', " . json_encode($eventData, JSON_THROW_ON_ERROR) . ");"; } @@ -273,32 +263,34 @@ protected function _getEnhancedEcommerceDataForAnalytics4() * @link https://developers.google.com/tag-platform/gtagjs/reference/events#view_cart */ elseif ($moduleName == 'checkout' && $controllerName == 'cart') { - $productCollection = Mage::getSingleton('checkout/session')->getQuote()->getAllVisibleItems(); + $productCollection = Mage::getSingleton('checkout/session')->getQuote()->getAllItems(); $eventData = []; $eventData['currency'] = Mage::app()->getStore()->getCurrentCurrencyCode(); $eventData['value'] = 0.00; $eventData['items'] = []; foreach ($productCollection as $productInCart) { - $_product = Mage::getModel('catalog/product')->load($productInCart->getProductId()); + if ($productInCart->getParentItem()) { + continue; + } + $_product = $productInCart->getProduct(); $_item = [ 'item_id' => $_product->getSku(), 'item_name' => $_product->getName(), - 'price' => number_format($_product->getFinalPrice(), 2, '.', ''), + 'price' => $helper->formatPrice($_product->getFinalPrice()), 'quantity' => (int) $productInCart->getQty(), ]; if ($_product->getAttributeText('manufacturer')) { $_item['item_brand'] = $_product->getAttributeText('manufacturer'); } - - $itemCategory = Mage::helper('googleanalytics')->getLastCategoryName($_product); + $itemCategory = $helper->getLastCategoryName($_product); if ($itemCategory) { $_item['item_category'] = $itemCategory; } array_push($eventData['items'], $_item); - $eventData['value'] += $_product->getFinalPrice(); + $eventData['value'] += $_product->getFinalPrice() * $productInCart->getQty(); } - $eventData['value'] = number_format($eventData['value'], 2, '.', ''); + $eventData['value'] = $helper->formatPrice($eventData['value']); $result[] = "gtag('event', 'view_cart', " . json_encode($eventData, JSON_THROW_ON_ERROR) . ");"; } @@ -308,32 +300,34 @@ protected function _getEnhancedEcommerceDataForAnalytics4() * @link https://developers.google.com/tag-platform/gtagjs/reference/events#begin_checkout */ elseif ($moduleName == static::CHECKOUT_MODULE_NAME && $controllerName == static::CHECKOUT_CONTROLLER_NAME) { - $productCollection = Mage::getSingleton('checkout/session')->getQuote()->getAllVisibleItems(); + $productCollection = Mage::getSingleton('checkout/session')->getQuote()->getAllItems(); if ($productCollection) { $eventData = []; $eventData['currency'] = Mage::app()->getStore()->getCurrentCurrencyCode(); $eventData['value'] = 0.00; $eventData['items'] = []; foreach ($productCollection as $productInCart) { - $_product = Mage::getModel('catalog/product')->load($productInCart->getProductId()); + if ($productInCart->getParentItem()) { + continue; + } + $_product = $productInCart->getProduct(); $_item = [ 'item_id' => $_product->getSku(), 'item_name' => $_product->getName(), - 'price' => number_format($_product->getFinalPrice(), 2, '.', ''), + 'price' => $helper->formatPrice($_product->getFinalPrice()), 'quantity' => (int) $productInCart->getQty(), ]; if ($_product->getAttributeText('manufacturer')) { $_item['item_brand'] = $_product->getAttributeText('manufacturer'); } - - $itemCategory = Mage::helper('googleanalytics')->getLastCategoryName($_product); + $itemCategory = $helper->getLastCategoryName($_product); if ($itemCategory) { $_item['item_category'] = $itemCategory; } array_push($eventData['items'], $_item); $eventData['value'] += $_product->getFinalPrice(); } - $eventData['value'] = number_format($eventData['value'], 2, '.', ''); + $eventData['value'] = $helper->formatPrice($eventData['value']); $result[] = "gtag('event', 'begin_checkout', " . json_encode($eventData, JSON_THROW_ON_ERROR) . ");"; } } @@ -352,28 +346,30 @@ protected function _getEnhancedEcommerceDataForAnalytics4() $orderData = [ 'currency' => $order->getBaseCurrencyCode(), 'transaction_id' => $order->getIncrementId(), - 'value' => number_format($order->getBaseGrandTotal(), 2, '.', ''), - 'coupon' => strtoupper($order->getCouponCode()), - 'shipping' => number_format($order->getBaseShippingAmount(), 2, '.', ''), - 'tax' => number_format($order->getBaseTaxAmount(), 2, '.', ''), + 'value' => $helper->formatPrice($order->getBaseGrandTotal()), + 'coupon' => strtoupper((string)$order->getCouponCode()), + 'shipping' => $helper->formatPrice($order->getBaseShippingAmount()), + 'tax' => $helper->formatPrice($order->getBaseTaxAmount()), 'items' => [] ]; /** @var Mage_Sales_Model_Order_Item $item */ - foreach ($order->getAllVisibleItems() as $item) { + foreach ($order->getAllItems() as $item) { + if ($item->getParentItem()) { + continue; + } + $_product = $item->getProduct(); $_item = [ 'item_id' => $item->getSku(), 'item_name' => $item->getName(), 'quantity' => (int) $item->getQtyOrdered(), - 'price' => number_format($item->getBasePrice(), 2, '.', ''), - 'discount' => number_format($item->getBaseDiscountAmount(), 2, '.', '') + 'price' => $helper->formatPrice($item->getBasePrice()), + 'discount' => $helper->formatPrice($item->getBaseDiscountAmount()) ]; - $_product = Mage::getModel('catalog/product')->load($item->getProductId()); if ($_product->getAttributeText('manufacturer')) { $_item['item_brand'] = $_product->getAttributeText('manufacturer'); } - - $itemCategory = Mage::helper('googleanalytics')->getLastCategoryName($_product); + $itemCategory = $helper->getLastCategoryName($_product); if ($itemCategory) { $_item['item_category'] = $itemCategory; } diff --git a/app/code/core/Mage/GoogleAnalytics/Helper/Data.php b/app/code/core/Mage/GoogleAnalytics/Helper/Data.php index 49b4b098987..5079f00e022 100644 --- a/app/code/core/Mage/GoogleAnalytics/Helper/Data.php +++ b/app/code/core/Mage/GoogleAnalytics/Helper/Data.php @@ -184,4 +184,13 @@ public function getLastCategoryName($product): string } return ''; } + + /** + * @param int|float|string $price + * @return string + */ + public function formatPrice($price): string + { + return number_format($price, 2, '.', ''); + } } diff --git a/app/code/core/Mage/GoogleAnalytics/Model/Observer.php b/app/code/core/Mage/GoogleAnalytics/Model/Observer.php index 728a0ae2fe6..411b6941ee6 100644 --- a/app/code/core/Mage/GoogleAnalytics/Model/Observer.php +++ b/app/code/core/Mage/GoogleAnalytics/Model/Observer.php @@ -39,38 +39,65 @@ public function setGoogleAnalyticsOnOrderSuccessPageView(Varien_Event_Observer $ } /** - * Add 'removed item' from cart into session for GA4 block to render event on cart view - * + * Process items added or removed from cart for GA4 block to render event on cart view * @param Varien_Event_Observer $observer + * @return void */ - public function removeItemFromCartGoogleAnalytics(Varien_Event_Observer $observer) + public function processItemsAddedOrRemovedFromCart(Varien_Event_Observer $observer): void { - $productRemoved = $observer->getEvent()->getQuoteItem()->getProduct(); - if ($productRemoved) { - $_removedProducts = Mage::getSingleton('core/session')->getRemovedProductsCart() ?: []; - $_removedProducts[] = $productRemoved->getId(); - $_removedProducts = array_unique($_removedProducts); - Mage::getSingleton('core/session')->setRemovedProductsCart($_removedProducts); + /** @var Mage_Sales_Model_Quote_Item $item */ + $item = $observer->getEvent()->getItem(); + if ($item->getParentItem()) { + return; } - } - /** - * Add 'added item' to cart into session for GA4 block to render event on cart view - * - * @param Varien_Event_Observer $observer - */ - public function addItemToCartGoogleAnalytics(Varien_Event_Observer $observer) - { - $productAdded = $observer->getEvent()->getQuoteItem()->getProduct(); - if ($productAdded) { - // Fix double add to cart for configurable products, skip child product - if ($productAdded->getParentProductId()) { - return; + // avoid to process the same quote_item more than once + // this could happen in case of double save of the same quote_item + $processedProductsRegistry = Mage::registry('processed_quote_items_for_analytics') ?? new ArrayObject(); + if ($processedProductsRegistry->offsetExists($item->getId())) { + return; + } + $processedProductsRegistry[$item->getId()] = true; + Mage::register('processed_quote_items_for_analytics', $processedProductsRegistry, true); + + $addedQty = 0; + $removedQty = 0; + if ($item->isObjectNew()) { + $addedQty = $item->getQty(); + } elseif ($item->isDeleted()) { + $removedQty = $item->getQty(); + } elseif ($item->hasDataChanges()) { + $newQty = $item->getQty(); + $oldQty = $item->getOrigData('qty'); + if ($newQty > $oldQty) { + $addedQty = $newQty - $oldQty; + } elseif ($newQty < $oldQty) { + $removedQty = $oldQty - $newQty; + } + } + + if ($addedQty || $removedQty) { + $product = $item->getProduct(); + $dataForAnalytics = [ + 'id' => $product->getId(), + 'sku' => $product->getSku(), + 'name' => $product->getName(), + 'qty' => $addedQty ?: $removedQty, + 'price' => $product->getFinalPrice(), + 'manufacturer' => $product->getAttributeText('manufacturer') ?: '', + 'category' => Mage::helper('googleanalytics')->getLastCategoryName($product) + ]; + + $session = Mage::getSingleton('core/session'); + if ($addedQty) { + $addedProducts = $session->getAddedProductsForAnalytics() ?: []; + $addedProducts[] = $dataForAnalytics; + $session->setAddedProductsForAnalytics($addedProducts); + } else { + $removedProducts = $session->getRemovedProductsForAnalytics() ?: []; + $removedProducts[] = $dataForAnalytics; + $session->setRemovedProductsForAnalytics($removedProducts); } - $_addedProducts = Mage::getSingleton('core/session')->getAddedProductsCart() ?: []; - $_addedProducts[] = $productAdded->getParentItem() ? $productAdded->getParentItem()->getId() : $productAdded->getId(); - $_addedProducts = array_unique($_addedProducts); - Mage::getSingleton('core/session')->setAddedProductsCart($_addedProducts); } } } diff --git a/app/code/core/Mage/GoogleAnalytics/etc/config.xml b/app/code/core/Mage/GoogleAnalytics/etc/config.xml index 8f7750a93b9..d4e605dde6e 100644 --- a/app/code/core/Mage/GoogleAnalytics/etc/config.xml +++ b/app/code/core/Mage/GoogleAnalytics/etc/config.xml @@ -72,22 +72,22 @@ - + - + googleanalytics/observer - removeItemFromCartGoogleAnalytics - + processItemsAddedOrRemovedFromCart + - - + + - + googleanalytics/observer - addItemToCartGoogleAnalytics - + processItemsAddedOrRemovedFromCart + - +