Compare commits

..

17 Commits
2.2.3 ... 2.4.0

11 changed files with 178 additions and 93 deletions

View File

@ -30,7 +30,6 @@ $aLang = [
// for cookie manager settings // for cookie manager settings
'SHOP_MODULE_GROUP_d3_gtm_settings_cookiemanager' => 'Cookie Manager Einstellungen', 'SHOP_MODULE_GROUP_d3_gtm_settings_cookiemanager' => 'Cookie Manager Einstellungen',
'SHOP_MODULE_d3_gtm_settings_hasOwnCookieManager' => 'Eigenen Cookie Manager nutzen? 'SHOP_MODULE_d3_gtm_settings_hasOwnCookieManager' => 'Cookie Manager nutzen?',
<strong style="color: red">Hinweis (Fragezeichen) lesen!</strong>', 'SHOP_MODULE_d3_gtm_settings_cookieName' => 'CookieID',
'SHOP_MODULE_d3_gtm_settings_cookieName' => 'Cookie-Name',
]; ];

View File

@ -1,40 +1,12 @@
[{assign var="d3VtConfigObject" value=$oViewConf->getConfig()}] [{* Always prepare the data layer to avoid errors *}]
[{if $d3VtConfigObject->getConfigParam('d3_gtm_settings_hasOwnCookieManager')}] <script>
[{if $oViewConf->D3blAcceptedCookie($d3VtConfigObject->getConfigParam('d3_gtm_settings_cookieName'))}] var dataLayer = [{$oViewConf->getGtmDataLayer()}] || [];
</script>
[{if $oViewConf->getGtmContainerId()}][{strip}] [{if $oViewConf->D3blShowGtmScript()}]
<!-- Google Tag Manager -->
<script>
var dataLayer = [{$oViewConf->getGtmDataLayer()}] || [];
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', '[{$oViewConf->getGtmContainerId()}]');
</script>
<!-- End Google Tag Manager -->
[{if $oViewConf->getTopActionClassName() === "alist" }]
[{* include file="ga4_view_item_list.tpl" gtmCategory=$oView->getActiveCategory() gtmProducts=$oView->getArticleList() listtype=$oView->getListType() *}]
[{elseif $oViewConf->getTopActionClassName() === "details" }]
[{* include file="ga4_view_item.tpl" gtmProduct=$oView->getProduct() *}]
[{elseif $oViewConf->getTopActionClassName() === "search" }]
[{elseif $oViewConf->getTopActionClassName() === "basket" }]
[{/if}]
[{/strip}][{/if}]
[{else}]
<script>
var dataLayer = [{$oViewConf->getGtmDataLayer()}] || [];
</script>
[{/if}]
[{else}]
[{if $oViewConf->getGtmContainerId()}][{strip}] [{if $oViewConf->getGtmContainerId()}][{strip}]
<!-- Google Tag Manager --> <!-- Google Tag Manager -->
<script> <script [{$oViewConf->getGtmScriptAttributes()}]>
var dataLayer = [{$oViewConf->getGtmDataLayer()}] || [];
(function (w, d, s, l, i) { (function (w, d, s, l, i) {
w[l] = w[l] || []; w[l] = w[l] || [];
w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'}); w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
@ -45,15 +17,15 @@
})(window, document, 'script', 'dataLayer', '[{$oViewConf->getGtmContainerId()}]'); })(window, document, 'script', 'dataLayer', '[{$oViewConf->getGtmContainerId()}]');
</script> </script>
<!-- End Google Tag Manager --> <!-- End Google Tag Manager -->
[{if $oViewConf->getTopActionClassName() === "alist" }] [{if $oViewConf->getTopActionClassName() === "alist" }]
[{* include file="ga4_view_item_list.tpl" gtmCategory=$oView->getActiveCategory() gtmProducts=$oView->getArticleList() listtype=$oView->getListType() *}] [{* include file="ga4_view_item_list.tpl" gtmCategory=$oView->getActiveCategory() gtmProducts=$oView->getArticleList() listtype=$oView->getListType() *}]
[{elseif $oViewConf->getTopActionClassName() === "details" }] [{elseif $oViewConf->getTopActionClassName() === "details" }]
[{* include file="ga4_view_item.tpl" gtmProduct=$oView->getProduct() *}] [{* include file="ga4_view_item.tpl" gtmProduct=$oView->getProduct() *}]
[{elseif $oViewConf->getTopActionClassName() === "search" }] [{elseif $oViewConf->getTopActionClassName() === "search" }]
[{elseif $oViewConf->getTopActionClassName() === "basket" }] [{elseif $oViewConf->getTopActionClassName() === "basket" }]
[{/if}] [{/if}]
[{/strip}][{/if}] [{/strip}][{/if}]
[{/if}] [{/if}]
[{$smarty.block.parent}] [{$smarty.block.parent}]

View File

@ -1,8 +1,12 @@
[{if $oViewConf->getGtmContainerId()}][{strip}] [{if $oViewConf->D3blShowGtmScript() && !$oViewConf->getCookieManagerType()}]
[{if $oViewConf->getGtmContainerId()}][{strip}]
<!-- Google Tag Manager (noscript) --> <!-- Google Tag Manager (noscript) -->
<noscript> <noscript>
<iframe src="https://www.googletagmanager.com/ns.html?id=[{$oViewConf->getGtmContainerId()}]" <iframe src="https://www.googletagmanager.com/ns.html?id=[{$oViewConf->getGtmContainerId()}]"
height="0" width="0" style="display:none;visibility:hidden"></iframe> height="0" width="0" style="display:none;visibility:hidden"></iframe>
</noscript> </noscript>
<!-- End Google Tag Manager (noscript) -->[{/strip}][{/if}] <!-- End Google Tag Manager (noscript) -->
[{/strip}][{/if}]
[{/if}]
[{$smarty.block.parent}] [{$smarty.block.parent}]

View File

@ -0,0 +1,25 @@
[{$smarty.block.parent}]
[{assign var="gtmProduct" value=$oView->getProduct()}]
[{assign var="gtmCategory" value=$gtmProduct->getCategory()}]
[{assign var="gtmManufacturer" value=$gtmProduct->getManufacturer()}]
<script>
dataLayer.push({"event": null, "eventLabel": null, "ecommerce": null}); /* Clear the previous ecommerce object. */
dataLayer.push({
'event': 'view_item',
'eventLabel':'Product View',
'ecommerce': {
'currency': '[{$currency->name}]',
'items': [
{
'item_name': '[{$gtmProduct->oxarticles__oxtitle->value}]',
'item_id': '[{$gtmProduct->oxarticles__oxartnum->value}]',
'item_brand': '[{if $gtmManufacturer}][{$gtmManufacturer->oxmanufacturers__oxtitle->value}][{/if}]',
'item_category': '[{if $gtmCategory}][{$gtmCategory->getLink()|parse_url:5|ltrim:"/"|rtrim:"/"}][{else}]-[{/if}]',
'item_variant': '[{if $gtmProduct->oxarticles__oxvarselect->value}][{$gtmProduct->oxarticles__oxvarselect->value}][{/if}]',
'price': [{$gtmProduct->oxarticles__oxprice->value}]
}
]
}
});
</script>

View File

@ -5,6 +5,8 @@
[{capture assign=d3_ga4_add_to_cart}] [{capture assign=d3_ga4_add_to_cart}]
[{block name="d3_ga4_add_to_basket"}] [{block name="d3_ga4_add_to_basket"}]
$("#toBasket").click(function(event) { $("#toBasket").click(function(event) {
[{*** Debug cases ***}]
[{*event.preventDefault();*}] [{*event.preventDefault();*}]
let iArtQuantity = $("#amountToBasket").val(); let iArtQuantity = $("#amountToBasket").val();
@ -28,7 +30,6 @@
'item_category_3':itemCategories[2] || '', 'item_category_3':itemCategories[2] || '',
'item_category_4':itemCategories[3] || '', 'item_category_4':itemCategories[3] || '',
[{if false}] [{if false}]
[{* ??? what *}]
'item_list_name': 'Search Results', // If associated with a list selection. 'item_list_name': 'Search Results', // If associated with a list selection.
'item_list_id': 'SR123', // If associated with a list selection. 'item_list_id': 'SR123', // If associated with a list selection.
'index': 1, // If associated with a list selection. 'index': 1, // If associated with a list selection.

View File

@ -1,26 +0,0 @@
[{strip}]
[{* variable $gtmProduct is passed from parent tempalte *}]
[{assign var="gtmCurrency" value=$oView->getActCurrency()}]
[{assign var="gtmManufacturer" value=$gtmProduct->getManufacturer()}]
[{assign var="gtmCategory" value=$gtmProduct->getCategory()}]
<script type="text/javascript">
dataLayer.push({ecommerce: null});
dataLayer.push({
'event':'GA4_event',
'event_name': 'view_item',
'ecommerce': {
'items': [
{
'item_id': '[{$gtmProduct->getFieldData("oxartnum")}]',
'item_name': '[{$gtmProduct->getFieldData("oxtitle")}]',
'item_variant': '[{if $gtmProduct->oxarticles__oxvarselect->value}][{$gtmProduct->oxarticles__oxvarselect->value}][{/if}]',
'price': [{$gtmProduct->oxarticles__oxprice->value|default:0}],
'item_brand': '[{if $gtmManufacturer}][{$gtmManufacturer->oxmanufacturers__oxtitle->value}][{/if}]',
'item_category': '[{if $gtmCategory}][{$gtmCategory->getLink()|parse_url:5|ltrim:"/"|rtrim:"/"}][{else}]-[{/if}]',
'quantity': '1'
}
]
}
});
</script>
[{/strip}]

View File

@ -4,9 +4,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.2.3](https://git.d3data.de/D3Public/GoogleAnalytics4/compare/2.2.2...2.2.3) - 2023-03-10 ## [2.4.0](https://git.d3data.de/D3Public/GoogleAnalytics4/compare/2.3.3...2.4.0) - 2023-05-02
### Removed ### Added
- unnecessary files to prevent confusion - "OXID Cookie Management powered by usercentrics" compatibility
- usercentrics defined script attributes
- cookie-manager evaluation
### Changed
- genuine clean up of base-js-files
## [2.3.3](https://git.d3data.de/D3Public/GoogleAnalytics4/compare/2.3.2...2.3.3) - 2023-03-20
### Fixed
- metadata file path for view_item
## [2.3.2](https://git.d3data.de/D3Public/GoogleAnalytics4/compare/2.2.2...2.3.2) - 2023-03-17
### Added
- Aggrosoft-Cookie-Consent compatibility
### Fixed
- wrong function for pageview on thankyou page
### Deleted
- unused files
## [2.2.2](https://git.d3data.de/D3Public/GoogleAnalytics4/compare/2.2.1...2.2.2) - 2023-02-22 ## [2.2.2](https://git.d3data.de/D3Public/GoogleAnalytics4/compare/2.2.1...2.2.2) - 2023-02-22
### Fixed ### Fixed
@ -29,6 +45,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- using of ContainerFactory in ViewConfig - using of ContainerFactory in ViewConfig
## [1.3.1](https://git.d3data.de/D3Public/GoogleAnalytics4/compare/1.2.1...1.3.1) - 2023-03-17
### Added
- Aggrosoft-Cookie-Consent compatibility
### Fixed
- wrong function for pageview on thankyou page
## [1.2.1](https://git.d3data.de/D3Public/GoogleAnalytics4/compare/1.2...1.2.1) - 2023-02-22 ## [1.2.1](https://git.d3data.de/D3Public/GoogleAnalytics4/compare/1.2...1.2.1) - 2023-02-22
### Fixed ### Fixed
- price formatting view_cart - price formatting view_cart

View File

@ -1,11 +1,11 @@
## Technische Doku # Technische Doku
### GA4 Events / Customizing ## GA4 Events / Customizing
FĂĽr alle implementierten GA4 Events existieren Templates unter `source/modules/d3/googleanalytics4/Application/views/ga4/`, dabei entspricht der Dateiname dem Eventnamen in GA4. FĂĽr alle implementierten GA4 Events existieren Templates unter `source/modules/d3/googleanalytics4/Application/views/ga4/`, dabei entspricht der Dateiname dem Eventnamen in GA4.
Die Einbindung dieser Event-Templates erfolgt über TPL-Blöcke unter `source/modules/d3/googleanalytics4/Application/views/blocks/`. Die Einbindung dieser Event-Templates erfolgt über TPL-Blöcke unter `source/modules/d3/googleanalytics4/Application/views/blocks/`.
*Hinweis: nicht alle templates sind bereits gefĂĽllt. WĂĽnschen Sie die Implementierung eines unausgefĂĽllten templates? *Hinweis: nicht alle templates sind bereits gefĂĽllt. WĂĽnschen Sie die Implementierung eines unausgefĂĽllten templates?
Kommen Sie auf uns zu unter https://www.d3data.de/ Kommen Sie auf uns zu unter https://www.d3data.de/
### Blöcke ## Blöcke
Für den geregelten Ablauf sind folgende Blöcke nötig: Für den geregelten Ablauf sind folgende Blöcke nötig:
- Suchergebnisse - Suchergebnisse
- Blockname: search_results - Blockname: search_results
@ -32,7 +32,7 @@ Für den geregelten Ablauf sind folgende Blöcke nötig:
- Datei: page/checkout/thankyou.tpl - Datei: page/checkout/thankyou.tpl
- GA4 Event: purchase - GA4 Event: purchase
### VerfĂĽgbare Datalayer Variablen ## VerfĂĽgbare Datalayer Variablen
FĂĽr die einfachste Ăśbersicht der enthaltenen Daten empfehle ich den Vorschau-Modus vom Google Tag Manager. FĂĽr die einfachste Ăśbersicht der enthaltenen Daten empfehle ich den Vorschau-Modus vom Google Tag Manager.
Bei jedem Seitenaufruf wird die Datenschicht mit einigen wenigen Infos erstellt, die man zum reinen Erfassen der Seitenaufrufe benötigt: Bei jedem Seitenaufruf wird die Datenschicht mit einigen wenigen Infos erstellt, die man zum reinen Erfassen der Seitenaufrufe benötigt:
@ -44,8 +44,25 @@ Bei jedem Seitenaufruf wird die Datenschicht mit einigen wenigen Infos erstellt,
Alle fĂĽr Ecommerce Tracking relevanten Daten werden mit speziellen Ecommerce Events in die Datenschicht eingefĂĽgt. Alle fĂĽr Ecommerce Tracking relevanten Daten werden mit speziellen Ecommerce Events in die Datenschicht eingefĂĽgt.
### Cookie-Handling ## Cookie-Handling
Sie nutzen einen eigenen, als Modul im Shop installierten, Cookie-manager? Sie nutzen einen eigenen, als Modul im Shop installierten, Cookie-manager?
Dann tragen Sie in den Folgeeinstellungen unter "Cookie Manager Einstellungen", Dann tragen Sie in den Folgeeinstellungen unter "Cookie Manager Einstellungen",
die Cookie-ID des zugehörigen Cookies ein. Und aktivieren Sie diese Weiche, die Cookie-ID des zugehörigen Cookies ein.
indem Sie den Haken bei "Eigenen Cookie Manager nutzen?" setzen. Aktivieren Sie anschlieĂźend diese Weiche. Setzen Sie den Haken bei "Eigenen Cookie Manager nutzen?".
### UnterstĂĽtzung fĂĽr
- [aggrosoft - oxid-cookie-compliance](https://github.com/aggrosoft/oxid-cookie-compliance)
- https://github.com/aggrosoft/oxid-cookie-compliance
- die entsprechend gewählte Kategorie in den Moduleinstellungen des 'Google Analytics 4' unter
```Einstell. > Cookie Manager Einstellungen > Cookie-ID``` eintragen
- Default-Werte sind entweder ```ANALYTICS``` oder ```MARKETING```. Bitte auf die GroĂźschreibung achten.
- [Netensio - Cookie Consent Manager](https://www.netensio.de/oxid-eshop-module/cookie-consent-manager-fuer-oxid-eshop.html)
- Modul entsprechend konfigurieren
- CookieID des angelegten Cookies in den Moduleinstellungen des 'Google Analytics 4' unter
```Einstell. > Cookie Manager Einstellungen > Cookie-ID``` eintragen
- [OXID Cookie Management powered by usercentrics](https://docs.oxid-esales.com/modules/usercentrics/de/latest/einfuehrung.html)
- In der Usercentrics-Verwaltung einen Service fĂĽr Google Analytics anlegen
- Den Service-Namen in den Moduleinstellungen des 'Google Analytics 4' unter
```Einstell. > Cookie Manager Einstellungen > Cookie-ID``` eintragen

View File

@ -22,6 +22,7 @@ class ViewConfig extends ViewConfig_parent
// Google Tag Manager Container ID // Google Tag Manager Container ID
private $sContainerId = null; private $sContainerId = null;
private $sCookieManagerType = null;
public function getGtmContainerId() public function getGtmContainerId()
{ {
@ -35,22 +36,86 @@ class ViewConfig extends ViewConfig_parent
return $this->sContainerId; return $this->sContainerId;
} }
public function getCookieManagerType()
{
if ($this->sCookieManagerType === null)
{
$this->sCookieManagerType = false;
$allowedManagerTypes = [
'net_cookie_manager',
'agcookiecompliance',
'oxps_usercentrics'
];
foreach ($allowedManagerTypes as $type) {
if ($this->isModuleActive($type)) {
$this->sCookieManagerType = $type;
break;
}
}
}
return $this->sCookieManagerType;
}
/** /**
* @param $sCookieID
* @return bool * @return bool
*/ */
public function D3blAcceptedCookie($sCookieID) public function D3blShowGtmScript()
{ {
$oSession = Registry::getSession(); $oConfig = $this->getConfig();
$aCookies = $oSession->getVariable("aCookieSel");
if (!is_null($aCookies) && is_array($aCookies) && array_key_exists($sCookieID, $aCookies) && $aCookies[$sCookieID] == "1") { // No Cookie Manager in use
if (!$oConfig->getConfigParam('d3_gtm_settings_hasOwnCookieManager')) {
return true; return true;
} }
$sCookieID = $oConfig->getConfigParam('d3_gtm_settings_cookieName');
// Netensio Cookie Manager
if ($this->getCookieManagerType() == "net_cookie_manager") {
$oSession = Registry::getSession();
$aCookies = $oSession->getVariable("aCookieSel");
return (!is_null($aCookies) && is_array($aCookies) && array_key_exists($sCookieID, $aCookies) && $aCookies[$sCookieID] == "1");
}
// Aggrosoft Cookie Consent
if ($this->getCookieManagerType() == "agcookiecompliance") {
if (method_exists($this, "isCookieCategoryEnabled")) {
return $this->isCookieCategoryEnabled($sCookieID);
}
}
// UserCentrics
if ($this->getCookieManagerType() == "oxps_usercentrics") {
// Always needs the script-tags delivered to the DOM.
return true;
}
// Cookie Manager not (yet) supported
return false; return false;
} }
/**
* Get additional attributes for script tags.
* This is especially important for UserCentrics.
* @return string
*/
public function getGtmScriptAttributes()
{
if ($this->getCookieManagerType() == "oxps_usercentrics") {
$oConfig = $this->getConfig();
$sCookieId = $oConfig->getConfigParam('d3_gtm_settings_cookieName');
if ($sCookieId) {
return 'type="text/plain" data-usercentrics="' . $sCookieId . '"';
}
}
return "";
}
private $blGA4enabled = null; private $blGA4enabled = null;
public function isGA4enabled() public function isGA4enabled()
@ -75,7 +140,7 @@ class ViewConfig extends ViewConfig_parent
/** @var FrontendController $oShop */ /** @var FrontendController $oShop */
$oUser = $oConfig->getUser(); $oUser = $oConfig->getUser();
$cl = $this->getTopActionClassName(); $cl = $this->getTopActiveClassName();
$aPageTypes = [ $aPageTypes = [
"content" => "cms", "content" => "cms",
"details" => "product", "details" => "product",
@ -86,6 +151,7 @@ class ViewConfig extends ViewConfig_parent
"payment" => "checkout", "payment" => "checkout",
"order" => "checkout", "order" => "checkout",
"thankyou" => "checkout", "thankyou" => "checkout",
"start" => "start",
]; ];
$dataLayer = [ $dataLayer = [

View File

@ -77,5 +77,6 @@ Die vollständigen Copyright- und Lizenzinformationen entnehmen Sie bitte der [L
Zu diesem Modul haben beigetragen: Zu diesem Modul haben beigetragen:
- [Marat Bedoev](https://github.com/vanilla-thunder) - [Marat Bedoev](https://github.com/vanilla-thunder)
- [Christoph Stäblein [gn2]](https://github.com/reyneke-vosz)
Vielen Dank. Vielen Dank.

View File

@ -17,7 +17,7 @@ $aModule = [
Die Entwicklung basiert auf einem Fork von Marat Bedoev - <a href='https://github.com/vanilla-thunder/oxid-module-gtm'>Github-Link</a> Die Entwicklung basiert auf einem Fork von Marat Bedoev - <a href='https://github.com/vanilla-thunder/oxid-module-gtm'>Github-Link</a>
", ",
'thumbnail' => 'thumbnail.png', 'thumbnail' => 'thumbnail.png',
'version' => '2.2.3', 'version' => '2.4.0',
'author' => 'Data Development (Inh.: Thomas Dartsch)', 'author' => 'Data Development (Inh.: Thomas Dartsch)',
'email' => 'support@shopmodule.com', 'email' => 'support@shopmodule.com',
'url' => 'https://www.oxidmodule.com/', 'url' => 'https://www.oxidmodule.com/',
@ -28,8 +28,6 @@ $aModule = [
// GA4 events // GA4 events
'ga4_add_to_cart.tpl' => 'd3/googleanalytics4/Application/views/ga4/add_to_cart.tpl', 'ga4_add_to_cart.tpl' => 'd3/googleanalytics4/Application/views/ga4/add_to_cart.tpl',
'ga4_search.tpl' => 'd3/googleanalytics4/Application/views/ga4/search.tpl', 'ga4_search.tpl' => 'd3/googleanalytics4/Application/views/ga4/search.tpl',
// article-details // view_item
'ga4_view_item.tpl' => 'd3/googleanalytics4/Application/views/ga4/view_item.tpl',
'ga4_view_item_list.tpl' => 'd3/googleanalytics4/Application/views/ga4/view_item_list.tpl', 'ga4_view_item_list.tpl' => 'd3/googleanalytics4/Application/views/ga4/view_item_list.tpl',
], ],
'blocks' => [ 'blocks' => [
@ -51,18 +49,17 @@ $aModule = [
'template' => 'page/checkout/basket.tpl', 'template' => 'page/checkout/basket.tpl',
'block' => 'checkout_basket_main', 'block' => 'checkout_basket_main',
'file' => '/Application/views/blocks/checkout_s1.tpl' 'file' => '/Application/views/blocks/checkout_s1.tpl'
], ],
// purchase
[ [
'template' => 'page/checkout/thankyou.tpl', 'template' => 'page/checkout/thankyou.tpl',
'block' => 'checkout_thankyou_main', 'block' => 'checkout_thankyou_main',
'file' => '/Application/views/blocks/checkout_s5.tpl' 'file' => '/Application/views/blocks/checkout_s5.tpl'
], ],
// add_to_cart // details
[ [
'template' => 'page/details/inc/productmain.tpl', 'template' => 'page/details/inc/productmain.tpl',
'block' => 'details_productmain_tobasket', 'block' => 'details_productmain_title',
'file' => '/Application/views/ga4/add_to_cart.tpl', 'file' => '/Application/views/blocks/view_item.tpl',
'position' => 150 'position' => 150
], ],
// Lists // Lists
@ -79,6 +76,13 @@ $aModule = [
'block' => 'search_results', 'block' => 'search_results',
'file' => '/Application/views/ga4/search.tpl', 'file' => '/Application/views/ga4/search.tpl',
'position' => 150 'position' => 150
],
// add_to_cart
[
'template' => 'page/details/inc/productmain.tpl',
'block' => 'details_productmain_tobasket',
'file' => '/Application/views/ga4/add_to_cart.tpl',
'position' => 150
] ]
], ],
'settings' => [ 'settings' => [