From 850ecf96398bb712a73bbd16add6317fa7e2612e Mon Sep 17 00:00:00 2001 From: Jeroen Frenken Date: Mon, 8 Dec 2025 08:43:08 +0100 Subject: [PATCH 1/4] Added user_data to purchase event --- CLAUDE.md | 78 ++++++++++++++++++++++++++++++++++++ DataLayer/Event/Purchase.php | 43 +++++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..56986528 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,78 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +This is the **Tagging_GTM** Magento 2 module - an AdPage/Tagging integration for Google Tag Manager. The module pushes e-commerce events and data to the dataLayer for GTM consumption. + +- **Package**: `tagginggroup/gtm` +- **Module name**: `Tagging_GTM` +- **PHP namespace**: `Tagging\GTM` +- **Requirements**: Magento 2.3.7+ or 2.4.1+, PHP 7.4 or 8.1+ + +## Common Commands + +```bash +# Install module +composer require tagginggroup/gtm +bin/magento module:enable Tagging_GTM +bin/magento setup:upgrade +bin/magento cache:clean + +# Run unit tests (requires Magento test framework) +./vendor/bin/phpunit -c phpunit.xml + +# Logs location +var/log/Tagging_GTM.log +``` + +## Architecture + +### Core Concepts + +The module uses a **Tag-based DataLayer architecture** where data is assembled from Tag, Event, and Processor objects: + +1. **Tags** (`Api/Data/TagInterface`): Single-value data providers that implement `get()` - return scalar values or arrays +2. **Events** (`Api/Data/EventInterface`): Complete event objects (purchase, add_to_cart, etc.) that implement `get(): array` +3. **Processors** (`Api/Data/ProcessorInterface`): Post-processors that modify the assembled data via `process(array $data): array` +4. **MergeTagInterface**: Tags that merge their data into the parent array rather than as a nested key + +### Data Flow + +``` +Layout XML → DataLayer Block → TagParser → dataLayer push +``` + +1. Layout XML files configure `data_layer` and `data_layer_events` arrays on the `Tagging_GTM.data-layer` block +2. `ViewModel/DataLayer.php` retrieves and processes this data +3. `DataLayer/TagParser.php` recursively resolves Tag/Event objects to their values +4. Processors are applied last for data modification + +### Key Directories + +- **DataLayer/Tag/**: Individual tag implementations (PageTitle, CartItems, CurrentProduct, etc.) +- **DataLayer/Event/**: E-commerce events (Purchase, AddToCart, BeginCheckout, Login, etc.) +- **DataLayer/Processor/**: Page-specific processors (SuccessPage, Checkout, Cart, Category, Product) +- **DataLayer/Mapper/**: Data mappers for products, categories, customers +- **Observer/**: Event observers triggering dataLayer events (AddToCart, Login, Logout, SignUp, etc.) +- **Plugin/**: Magento plugins for checkout events (shipping info, payment info, search results) + +### Configuration + +- XML config: `etc/data_layer.xml` - extend default dataLayer values and event data via XML +- Admin config: **Stores > Configuration > AdPage > AdPage GTM** +- DI configuration: `etc/di.xml` and `etc/frontend/di.xml` + +### Hyva Theme Support + +The module includes Hyva theme compatibility via: +- `view/frontend/layout/hyva_default.xml` +- `view/frontend/layout/hyva_checkout_index_index.xml` +- `MageWire/` components for Hyva checkout + +### Testing + +- Unit tests: `Test/Unit/` +- Integration tests: `Test/Integration/` +- Functional tests: `Test/Functional/` diff --git a/DataLayer/Event/Purchase.php b/DataLayer/Event/Purchase.php index 078aee32..d7e60cca 100644 --- a/DataLayer/Event/Purchase.php +++ b/DataLayer/Event/Purchase.php @@ -1,4 +1,6 @@ - $this->priceFormatter->format((float)$order->getShippingInclTax()), 'coupon' => $order->getCouponCode(), 'items' => $this->orderItems->setOrder($order)->get() - ] + ], + 'user_data' => $this->getUserData($order) + ]; + } + + /** + * @param OrderInterface $order + * @return array + */ + private function getUserData(OrderInterface $order): array + { + $billingAddress = $order->getBillingAddress(); + $shippingAddress = $order->getShippingAddress(); + + return [ + 'customer_id' => $order->getCustomerId() ?? '', + 'billing_first_name' => $billingAddress ? $billingAddress->getFirstname() ?? '' : '', + 'billing_last_name' => $billingAddress ? $billingAddress->getLastname() ?? '' : '', + 'billing_address' => $billingAddress && $billingAddress->getStreet() ? $billingAddress->getStreet()[0] ?? '' : '', + 'billing_postcode' => $billingAddress ? $billingAddress->getPostcode() ?? '' : '', + 'billing_country' => $billingAddress ? $billingAddress->getCountryId() ?? '' : '', + 'billing_state' => $billingAddress ? $billingAddress->getRegion() ?? '' : '', + 'billing_city' => $billingAddress ? $billingAddress->getCity() ?? '' : '', + 'billing_email' => $billingAddress ? $billingAddress->getEmail() ?? '' : '', + 'billing_phone' => $billingAddress ? $billingAddress->getTelephone() ?? '' : '', + 'shipping_first_name' => $shippingAddress ? $shippingAddress->getFirstname() ?? '' : '', + 'shipping_last_name' => $shippingAddress ? $shippingAddress->getLastname() ?? '' : '', + 'shipping_company' => $shippingAddress ? $shippingAddress->getCompany() ?? '' : '', + 'shipping_address' => $shippingAddress && $shippingAddress->getStreet() ? $shippingAddress->getStreet()[0] ?? '' : '', + 'shipping_postcode' => $shippingAddress ? $shippingAddress->getPostcode() ?? '' : '', + 'shipping_country' => $shippingAddress ? $shippingAddress->getCountryId() ?? '' : '', + 'shipping_state' => $shippingAddress ? $shippingAddress->getRegion() ?? '' : '', + 'shipping_city' => $shippingAddress ? $shippingAddress->getCity() ?? '' : '', + 'shipping_phone' => $shippingAddress ? $shippingAddress->getTelephone() ?? '' : '', + 'email' => $order->getCustomerEmail() ?? '', + 'first_name' => $order->getCustomerFirstname() ?? '', + 'last_name' => $order->getCustomerLastname() ?? '', + 'new_customer' => $order->getCustomerIsGuest() ? 'true' : 'false' ]; } From e8261c9a2bd794fd3b0664257457d9911728fb76 Mon Sep 17 00:00:00 2001 From: Jeroen Frenken Date: Mon, 8 Dec 2025 12:35:25 +0100 Subject: [PATCH 2/4] Bumped version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c8fc5186..fa57c5cf 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "tagginggroup/gtm", - "version": "1.5.4", + "version": "1.5.5", "license": "OSL-3.0", "type": "magento2-module", "description": "AdPage tagging integration for Magento 2", From 1680068c94426455afcd02be6af1d5aa63c6351f Mon Sep 17 00:00:00 2001 From: Jeroen Frenken Date: Mon, 8 Dec 2025 13:06:16 +0100 Subject: [PATCH 3/4] Added hyva support / added user_data tag order --- DataLayer/Tag/Order/UserData.php | 68 +++++++++++++++++++ .../layout/checkout_onepage_success.xml | 1 + .../templates/hyva/script-additions.phtml | 6 +- 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 DataLayer/Tag/Order/UserData.php diff --git a/DataLayer/Tag/Order/UserData.php b/DataLayer/Tag/Order/UserData.php new file mode 100644 index 00000000..9f624336 --- /dev/null +++ b/DataLayer/Tag/Order/UserData.php @@ -0,0 +1,68 @@ +checkoutSession = $checkoutSession; + $this->orderRepository = $orderRepository; + } + + /** + * @return array + */ + public function get(): array + { + $order = $this->getOrder(); + $billingAddress = $order->getBillingAddress(); + $shippingAddress = $order->getShippingAddress(); + + return [ + 'customer_id' => $order->getCustomerId() ?? '', + 'billing_first_name' => $billingAddress ? $billingAddress->getFirstname() ?? '' : '', + 'billing_last_name' => $billingAddress ? $billingAddress->getLastname() ?? '' : '', + 'billing_address' => $billingAddress && $billingAddress->getStreet() ? $billingAddress->getStreet()[0] ?? '' : '', + 'billing_postcode' => $billingAddress ? $billingAddress->getPostcode() ?? '' : '', + 'billing_country' => $billingAddress ? $billingAddress->getCountryId() ?? '' : '', + 'billing_state' => $billingAddress ? $billingAddress->getRegion() ?? '' : '', + 'billing_city' => $billingAddress ? $billingAddress->getCity() ?? '' : '', + 'billing_email' => $billingAddress ? $billingAddress->getEmail() ?? '' : '', + 'billing_phone' => $billingAddress ? $billingAddress->getTelephone() ?? '' : '', + 'shipping_first_name' => $shippingAddress ? $shippingAddress->getFirstname() ?? '' : '', + 'shipping_last_name' => $shippingAddress ? $shippingAddress->getLastname() ?? '' : '', + 'shipping_company' => $shippingAddress ? $shippingAddress->getCompany() ?? '' : '', + 'shipping_address' => $shippingAddress && $shippingAddress->getStreet() ? $shippingAddress->getStreet()[0] ?? '' : '', + 'shipping_postcode' => $shippingAddress ? $shippingAddress->getPostcode() ?? '' : '', + 'shipping_country' => $shippingAddress ? $shippingAddress->getCountryId() ?? '' : '', + 'shipping_state' => $shippingAddress ? $shippingAddress->getRegion() ?? '' : '', + 'shipping_city' => $shippingAddress ? $shippingAddress->getCity() ?? '' : '', + 'shipping_phone' => $shippingAddress ? $shippingAddress->getTelephone() ?? '' : '', + 'email' => $order->getCustomerEmail() ?? '', + 'first_name' => $order->getCustomerFirstname() ?? '', + 'last_name' => $order->getCustomerLastname() ?? '', + 'new_customer' => $order->getCustomerIsGuest() ? 'true' : 'false' + ]; + } + + /** + * @return OrderInterface + */ + private function getOrder(): OrderInterface + { + return $this->orderRepository->get($this->checkoutSession->getLastRealOrder()->getId()); + } +} diff --git a/view/frontend/layout/checkout_onepage_success.xml b/view/frontend/layout/checkout_onepage_success.xml index 9536bbcb..d12697fb 100644 --- a/view/frontend/layout/checkout_onepage_success.xml +++ b/view/frontend/layout/checkout_onepage_success.xml @@ -24,6 +24,7 @@ Tagging\GTM\DataLayer\Tag\Order\Order Tagging\GTM\DataLayer\Tag\Order\OrderItems + Tagging\GTM\DataLayer\Tag\Order\UserData diff --git a/view/frontend/templates/hyva/script-additions.phtml b/view/frontend/templates/hyva/script-additions.phtml index 27634ac9..6f5f13e3 100644 --- a/view/frontend/templates/hyva/script-additions.phtml +++ b/view/frontend/templates/hyva/script-additions.phtml @@ -34,11 +34,11 @@ $commons = $block->getCommonsViewModel(); } var getSectionNames = function() { - return ['cart', 'customer']; + return ['cart', 'customer', 'gtm-checkout']; } getSectionNames().forEach(function(sectionName) { - if (!event.detail.data[sectionName].gtm) { + if (!event.detail.data[sectionName] || !event.detail.data[sectionName].gtm) { return; } @@ -52,7 +52,7 @@ $commons = $block->getCommonsViewModel(); let attributes = {}; getSectionNames().forEach(function(sectionName) { - if (!event.detail.data[sectionName].gtm_events) { + if (!event.detail.data[sectionName] || !event.detail.data[sectionName].gtm_events) { return; } From 55bdef91e593499b42c4fddf4f8105bf6650ff73 Mon Sep 17 00:00:00 2001 From: Jeroen Frenken Date: Mon, 8 Dec 2025 15:17:30 +0100 Subject: [PATCH 4/4] Bug fix hyva double purchase event --- view/frontend/templates/hyva/script-additions.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/frontend/templates/hyva/script-additions.phtml b/view/frontend/templates/hyva/script-additions.phtml index 6f5f13e3..6b864d6c 100644 --- a/view/frontend/templates/hyva/script-additions.phtml +++ b/view/frontend/templates/hyva/script-additions.phtml @@ -34,7 +34,7 @@ $commons = $block->getCommonsViewModel(); } var getSectionNames = function() { - return ['cart', 'customer', 'gtm-checkout']; + return ['cart', 'customer']; } getSectionNames().forEach(function(sectionName) {