Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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/`
43 changes: 41 additions & 2 deletions DataLayer/Event/Purchase.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?php declare(strict_types=1);
<?php

declare(strict_types=1);

namespace Tagging\GTM\DataLayer\Event;

Expand Down Expand Up @@ -42,7 +44,44 @@ public function get(): array
'shipping' => $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'
];
}

Expand Down
68 changes: 68 additions & 0 deletions DataLayer/Tag/Order/UserData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace Tagging\GTM\DataLayer\Tag\Order;

use Magento\Checkout\Model\Session as CheckoutSession;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Tagging\GTM\Api\Data\TagInterface;

class UserData implements TagInterface
{
private CheckoutSession $checkoutSession;
private OrderRepositoryInterface $orderRepository;

public function __construct(
CheckoutSession $checkoutSession,
OrderRepositoryInterface $orderRepository
) {
$this->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());
}
}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
1 change: 1 addition & 0 deletions view/frontend/layout/checkout_onepage_success.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<item name="order" xsi:type="object">Tagging\GTM\DataLayer\Tag\Order\Order</item>
<item name="items" xsi:type="object">Tagging\GTM\DataLayer\Tag\Order\OrderItems</item>
</item>
<item name="user_data" xsi:type="object">Tagging\GTM\DataLayer\Tag\Order\UserData</item>
</item>
</argument>

Expand Down
4 changes: 2 additions & 2 deletions view/frontend/templates/hyva/script-additions.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ $commons = $block->getCommonsViewModel();
}

getSectionNames().forEach(function(sectionName) {
if (!event.detail.data[sectionName].gtm) {
if (!event.detail.data[sectionName] || !event.detail.data[sectionName].gtm) {
return;
}

Expand All @@ -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;
}

Expand Down
Loading