Skip to content
Open
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
73 changes: 73 additions & 0 deletions Config/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,79 @@ public function isWebhookTriggerOnOrderState(): bool
return $this->getWebhookTriggerMode() === 'on_order_state';
}

/**
* Check if page-specific checking is enabled for purchase event
*
* @return bool
*/
public function isPurchaseEventPageCheckEnabled(): bool
{
return (bool)$this->getModuleConfigValueAdvanced('purchase_event_page_check_enabled', true);
}

/**
* Get allowed checkout actions for purchase event
*
* @return array
*/
public function getPurchaseEventAllowedCheckoutActions(): array
{
// Only return actions if page check is enabled
if (!$this->isPurchaseEventPageCheckEnabled()) {
return [];
}

$configValue = $this->getModuleConfigValueAdvanced('purchase_event_allowed_checkout_actions', null);

// If null or empty and page check is enabled, return all available actions as default
if ($configValue === null || $configValue === '' || $configValue === false) {
return $this->getAllAvailableCheckoutActions();
}

// Multiselect values in Magento can be stored in different formats:
// 1. As an array (when retrieved via ScopeConfigInterface in some cases)
// 2. As a comma-separated string (most common)
// 3. As a JSON string (less common)

if (is_array($configValue)) {
$actions = array_filter(array_map('trim', $configValue));
// If array is empty, return all available actions
return empty($actions) ? $this->getAllAvailableCheckoutActions() : $actions;
}

if (is_string($configValue)) {
// Try JSON decode first (in case it's stored as JSON)
$decoded = json_decode($configValue, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
$actions = array_filter(array_map('trim', $decoded));
return empty($actions) ? $this->getAllAvailableCheckoutActions() : $actions;
}

// Otherwise treat as comma-separated string
$actions = array_filter(array_map('trim', explode(',', $configValue)));
return empty($actions) ? $this->getAllAvailableCheckoutActions() : $actions;
}

return $this->getAllAvailableCheckoutActions();
}

/**
* Get all available checkout actions
*
* @return array
*/
private function getAllAvailableCheckoutActions(): array
{
return [
'checkout_index_index',
'checkout_onepage_success',
'checkout_cart_index',
'checkout_onepage_index',
'checkout_multishipping_index',
'checkout_multishipping_success',
];
}

/**
* @return bool
*/
Expand Down
98 changes: 96 additions & 2 deletions CustomerData/GtmCheckout.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,122 @@
namespace Tagging\GTM\CustomerData;

use Magento\Customer\CustomerData\SectionSourceInterface;
use Magento\Framework\App\RequestInterface;
use Tagging\GTM\Api\CheckoutSessionDataProviderInterface;
use Tagging\GTM\Config\Config;

class GtmCheckout implements SectionSourceInterface
{
private CheckoutSessionDataProviderInterface $checkoutSessionDataProvider;
private RequestInterface $request;
private Config $config;

/**
* @param CheckoutSessionDataProviderInterface $checkoutSessionDataProvider
* @param RequestInterface $request
* @param Config $config
*/
public function __construct(
CheckoutSessionDataProviderInterface $checkoutSessionDataProvider
CheckoutSessionDataProviderInterface $checkoutSessionDataProvider,
RequestInterface $request,
Config $config
) {
$this->checkoutSessionDataProvider = $checkoutSessionDataProvider;
$this->request = $request;
$this->config = $config;
}

/**
* @return array
*/
public function getSectionData(): array
{
// Add debug logging: the action, module, enabled status
if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] getSectionData called');
}
$gtmEvents = $this->checkoutSessionDataProvider->get();

if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] Current GTM events: ' . json_encode($gtmEvents));
}

$pageCheckEnabled = $this->config->isPurchaseEventPageCheckEnabled();

if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] PurchaseEventPageCheckEnabled = ' . ($pageCheckEnabled ? 'true' : 'false'));
}

if (!$pageCheckEnabled) {
if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] PageCheck DISABLED, returning all GTM events');
}
return ['gtm_events' => $gtmEvents];
}
$isCheckoutPage = $this->isCheckoutPage();

if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] isCheckoutPage = ' . ($isCheckoutPage ? 'true' : 'false'));
}

if ($isCheckoutPage) {
if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] On checkout page: clearing all checkout session GTM events');
}
$this->checkoutSessionDataProvider->clear();
return ['gtm_events' => $gtmEvents];
}

$purchaseEvent = $gtmEvents['purchase_event'] ?? null;
$otherEvents = $gtmEvents;
unset($otherEvents['purchase_event']);

if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] Not checkout page, will keep only non-purchase_event events: ' . json_encode($otherEvents));
}

$this->checkoutSessionDataProvider->clear();
return ['gtm_events' => $gtmEvents];

if ($purchaseEvent !== null) {
if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] purchase_event found, re-adding it to checkout session data');
}
$this->checkoutSessionDataProvider->add('purchase_event', $purchaseEvent);
}

return ['gtm_events' => $otherEvents];

}

private function isCheckoutPage(): bool
{
$fullActionName = $this->request->getFullActionName();
$moduleName = $this->request->getModuleName();

if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] Checking if is checkout page, module=' . $moduleName . ' fullAction=' . $fullActionName);
}

if ($moduleName !== 'checkout') {
if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] Not checkout module, skipping');
}
return false;
}

$allowedActions = $this->config->getPurchaseEventAllowedCheckoutActions();

if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] Allowed actions: ' . implode(', ', $allowedActions));
$this->debugger->debug('[GtmCheckout] Current fullActionName: ' . $fullActionName);
}

$isAllowed = in_array($fullActionName, $allowedActions, true);

if (property_exists($this, 'debugger') && $this->debugger) {
$this->debugger->debug('[GtmCheckout] isCheckoutPage returning: ' . ($isAllowed ? 'true' : 'false'));
}

return $isAllowed;
}
}
2 changes: 1 addition & 1 deletion DataLayer/Event/Purchase.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function get(): array
{
$order = $this->order;
return [
'event' => 'trytagging_purchase',
'event' => 'trytagging_purchase3',
'ecommerce' => [
'transaction_id' => $order->getIncrementId(),
'affiliation' => $this->config->getStoreName(),
Expand Down
2 changes: 1 addition & 1 deletion DataLayer/Event/PurchaseWebhookEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public function purchase(OrderInterface $order)
}

$data = [
'event' => 'trytagging_purchase',
'event' => 'trytagging_purchase4',
'marketing' => $marketingData,
'store_domain' => $this->config->getStoreDomain(),
'plugin_version' => $this->config->getVersion(),
Expand Down
61 changes: 61 additions & 0 deletions Model/Config/Source/CheckoutActions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php declare(strict_types=1);

namespace Tagging\GTM\Model\Config\Source;

use Magento\Framework\Data\OptionSourceInterface;

class CheckoutActions implements OptionSourceInterface
{
/**
* Available checkout actions that can trigger purchase events
*/
private const CHECKOUT_ACTIONS = [
'checkout_index_index' => 'Checkout Index (Main checkout page)',
'checkout_onepage_success' => 'Checkout Success Page',
'checkout_cart_index' => 'Shopping Cart Page',
'checkout_onepage_index' => 'One Page Checkout',
'checkout_multishipping_index' => 'Multishipping Checkout',
'checkout_multishipping_success' => 'Multishipping Success',
];

/**
* {@inheritdoc}
*/
public function toOptionArray(): array
{
$options = [];

foreach (self::CHECKOUT_ACTIONS as $value => $label) {
$options[] = [
'value' => $value,
'label' => __($label)
];
}

return $options;
}

/**
* Get all available checkout action values
*
* @return array
*/
public function getAvailableActions(): array
{
return array_keys(self::CHECKOUT_ACTIONS);
}

/**
* Get default checkout actions (for fallback)
*
* @return array
*/
public function getDefaultActions(): array
{
return [
'checkout_index_index',
'checkout_onepage_success',
];
}
}

5 changes: 3 additions & 2 deletions Observer/TriggerPurchaseDataLayerEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

namespace Tagging\GTM\Observer;

use Magento\Framework\App\RequestInterface;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Sales\Api\Data\OrderInterface;
use Tagging\GTM\Api\CheckoutSessionDataProviderInterface;
use Tagging\GTM\Config\Config;
use Tagging\GTM\DataLayer\Event\Purchase as PurchaseEvent;
use Tagging\GTM\Logger\Debugger;
use Exception;
Expand All @@ -19,7 +21,7 @@ class TriggerPurchaseDataLayerEvent implements ObserverInterface
public function __construct(
CheckoutSessionDataProviderInterface $checkoutSessionDataProvider,
PurchaseEvent $purchaseEvent,
Debugger $debugger
Debugger $debugger,
) {
$this->checkoutSessionDataProvider = $checkoutSessionDataProvider;
$this->purchaseEvent = $purchaseEvent;
Expand All @@ -31,7 +33,6 @@ public function execute(Observer $observer)
/** @var OrderInterface $order */
$order = $observer->getData('order');

$this->debugger->debug("TriggerPurchaseDataLayerEvent::execute(): has changed ");
$this->checkoutSessionDataProvider->add(
'purchase_event',
$this->purchaseEvent->setOrder($order)->get()
Expand Down
21 changes: 21 additions & 0 deletions etc/adminhtml/system.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,27 @@
<field id="webhook_trigger_mode">on_order_state</field>
</depends>
</field>
<field id="purchase_event_page_check_enabled" type="select" translate="label" sortOrder="4" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Check specific page to trigger purchase event</label>
<comment><![CDATA[If enabled, the purchase event will only be sent when the order is placed on specific checkout pages. You can select which pages below.<br/>
<b>Default:</b> Enabled (all checkout pages are selected by default)<br/>
<b>If disabled:</b> Purchase event will fire from any page where an order is placed (admin, API, etc.)]]></comment>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<depends>
<field id="*/settings/enabled">1</field>
</depends>
</field>
<field id="purchase_event_allowed_checkout_actions" type="multiselect" translate="label" sortOrder="5" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Allowed Checkout Actions for Purchase Event</label>
<comment><![CDATA[Select which checkout pages/actions should trigger the purchase event. When page check is enabled, the purchase event will only fire when an order is placed on one of the selected checkout pages.<br/>
<b>Default:</b> All checkout pages are enabled when page check is turned on<br/>
<b>Note:</b> If page check is disabled, these selections are ignored and the event fires from any page.]]></comment>
<source_model>Tagging\GTM\Model\Config\Source\CheckoutActions</source_model>
<depends>
<field id="*/settings/enabled">1</field>
<field id="purchase_event_page_check_enabled">1</field>
</depends>
</field>
</group>
</section>
</system>
Expand Down
2 changes: 1 addition & 1 deletion view/frontend/layout/checkout_onepage_success.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<argument name="data_layer_events" xsi:type="array">
<item name="purchase_event" xsi:type="array">
<item name="event" xsi:type="string">trytagging_purchase</item>
<item name="event" xsi:type="string">trytagging_purchase2</item>
<item name="ecommerce" xsi:type="array">
<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>
Expand Down
5 changes: 5 additions & 0 deletions view/frontend/layout/default.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
</referenceBlock>

<referenceContainer name="after.body.start">
<block
name="Tagging_GTM.debug-action"
template="Tagging_GTM::luma/debug-action.phtml"
ifconfig="GTM/settings/enabled"
/>
<block
name="Tagging_GTM.iframe"
template="Tagging_GTM::iframe.phtml"
Expand Down
5 changes: 5 additions & 0 deletions view/frontend/layout/hyva_default.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="after.body.start">
<block
name="Tagging_GTM.debug-action"
template="Tagging_GTM::hyva/debug-action.phtml"
ifconfig="GTM/settings/enabled"
/>
<block
name="Tagging_GTM.pusher-script"
template="Tagging_GTM::hyva/script-pusher.phtml"
Expand Down
Loading
Loading