Skip to content
Code-Schnipsel Gruppen Projekte
Bestätigt Commit 6d55fd36 erstellt von Henning Leutz's avatar Henning Leutz :martial_arts_uniform:
Dateien durchsuchen

feat: integration of dataLayer and qTrack()

Übergeordneter 576ee484
Keine zugehörigen Branchen gefunden
Keine zugehörigen Tags gefunden
2 Merge Requests!43Next,!42Dev
<?php
QUI::$Ajax->registerFunction(
'package_quiqqer_order_ajax_frontend_dataLayer_getCategoryData',
function ($project, $siteId) {
try {
$Project = QUI::getProjectManager()->decode($project);
$Site = $Project->get($siteId);
$categoryId = $Site->getAttribute('quiqqer.products.settings.categoryId');
$Category = QUI\ERP\Products\Handler\Categories::getCategory($categoryId);
return $Category->getTitle();
} catch (QUI\Exception $Exception) {
return '';
}
},
['project', 'siteId']
);
<?php
use QUI\ERP\Order\Utils\DataLayer;
use QUI\ERP\Products\Handler\Products;
QUI::$Ajax->registerFunction(
'package_quiqqer_order_ajax_frontend_dataLayer_getProductData',
function ($productId) {
try {
$productId = (int)$productId;
$Product = Products::getProduct($productId);
return DataLayer::parseProduct($Product);
} catch (QUI\Exception $Exception) {
return [];
}
},
['productId']
);
<?php
use QUI\ERP\Order\Handler as OrderHandler;
use QUI\ERP\Order\Utils\DataLayer;
use QUI\ERP\Products\Handler\Products;
QUI::$Ajax->registerFunction(
'package_quiqqer_order_ajax_frontend_dataLayer_getTrackData',
function ($basketId, $products) {
if (!QUI::getUserBySession()->getId()) {
$Basket = new QUI\ERP\Order\Basket\BasketGuest();
$Basket->import(json_decode($products, true));
} else {
try {
$Basket = OrderHandler::getInstance()->getBasketById($basketId);
} catch (QUI\Exception $Exception) {
return [];
}
}
$Locale = QUI::getLocale();
$List = $Basket->getProducts();
if (!$List) {
return [];
}
$list = $List->toArray();
$products = $list['products'];
// generate result
$items = [];
foreach ($products as $product) {
$Product = Products::getProduct($product['id']);
$item = DataLayer::parseProduct($Product, $Locale);
$items[] = $item;
}
return [
'currency' => $List->getCurrency()->getCode(),
'value' => $list['sum'],
'items' => $items
];
},
[
'basketId',
'products'
]
);
<?php
use QUI\ERP\Order\Utils\DataLayer;
QUI::$Ajax->registerFunction(
'package_quiqqer_order_ajax_frontend_dataLayer_getTrackDataForOrderProcess',
function ($orderHash) {
try {
$Orders = QUI\ERP\Order\Handler::getInstance();
$Order = $Orders->getOrderByHash($orderHash);
if (!$Order) {
return [];
}
$Articles = $Order->getArticles();
if (!$Articles->count()) {
return [];
}
} catch (QUI\Exception $Exception) {
return [];
}
return DataLayer::parseOrder($Order);
},
['orderHash']
);
window.whenQuiLoaded().then(function() {
'use strict';
require([
'qui/QUI',
'Ajax'
], function(QUI, QUIAjax) {
//region helper functions
/**
* Sends a request to track the contents of a basket.
*
* @param {Basket} Basket - The basket object containing the products to track.
* @return {Promise} A promise that resolves when the tracking request is completed.
*/
function getBasketData(Basket)
{
if (!parseInt(QUIQQER_USER.id)) {
return new Promise(function(resolve) {
let products = [];
let basketProducts = Basket.getProducts();
for (let i = 0, len = basketProducts.length; i < len; i++) {
products.push(basketProducts[i].getAttributes());
}
QUIAjax.get('package_quiqqer_order_ajax_frontend_dataLayer_getTrackData', resolve, {
'package': 'quiqqer/order',
basketId: Basket.getId(),
products: JSON.encode(products)
});
});
}
return new Promise(function(resolve) {
QUIAjax.get('package_quiqqer_order_ajax_frontend_dataLayer_getTrackData', resolve, {
'package': 'quiqqer/order',
basketId: Basket.getId()
});
});
}
/**
* Tracks a product view in Matomo.
*
* @param {boolean|integer} productId - The ID of the product being viewed.
*
* @return {void}
*/
function trackProductView(productId)
{
QUIAjax.get('package_quiqqer_order_ajax_frontend_dataLayer_getProductData', function(product) {
window.qTrack('event', 'view_item', {
'currency': product.currency.code,
'value': product.price,
'items': [
{
item_id: product.productNo,
item_name: product.title,
//affiliation: product.manufacturer,
//item_brand: 'Google',
item_category: product.category,
item_variant: product.variant,
price: product.price,
quantity: 1
}
],
'page_location': window.location.toString(),
'page_title': document.title,
'visitor_type': QUIQQER_USER.id ? 'user' : 'visitor',
'site_type': QUIQQER_SITE.type.replace('quiqqer/', ''), // <- mor wollte das
'site:id': QUIQQER_SITE.id
});
}, {
'package': 'quiqqer/order',
productId: productId
});
}
/**
* Tracks a category view
*
* @param siteId
*/
function trackCategoryView(siteId)
{
QUIAjax.get('package_quiqqer_order_ajax_frontend_dataLayer_getCategoryData', function(category) {
window.qTrack('event', 'page_view', {
'page_location': window.location.toString(),
'page_title': document.title,
'visitor_type': QUIQQER_USER.id ? 'user' : 'visitor',
'site_type': QUIQQER_SITE.type.replace('quiqqer/', ''), // <- mor wollte das
'site_id': QUIQQER_SITE.id,
'category': category
});
}, {
'package': 'quiqqer/order',
siteId: siteId
});
}
function getOrderData(OrderProcess)
{
const stepData = OrderProcess.getCurrentStepData();
let url = '/' + stepData.step;
if (QUIQQER_SITE.url !== '' && QUIQQER_SITE.url !== '/') {
url = QUIQQER_SITE.url + url;
}
return new Promise((resolve) => {
OrderProcess.getOrder().then(function(orderHash) {
QUIAjax.get(
'package_quiqqer_order_ajax_frontend_dataLayer_getTrackDataForOrderProcess',
function(orderData) {
orderData.url = url;
orderData.step = stepData.step;
resolve(orderData);
},
{
'package': 'quiqqer/order',
orderHash: orderHash
}
);
});
});
}
/**
* Return current product id
*
* @return {boolean|integer}
*/
function getProductId()
{
if (typeof window.QUIQQER_PRODUCT_ID === 'undefined') {
return false;
}
return window.QUIQQER_PRODUCT_ID;
}
//endregion
//region events
// basket tracking only if order is installed
if (typeof window.QUIQQER_ORDER_ORDER_PROCESS_MERGE !== 'undefined') {
require(['package/quiqqer/order/bin/frontend/Basket'], function(Basket) {
Basket.addEvent('onAdd', function() {
getBasketData(Basket).then(function(data) {
window.qTrack('event', 'add_to_cart', data);
});
});
Basket.addEvent('onRemove', function() {
getBasketData(Basket).then(function(data) {
window.qTrack('event', 'view_cart', data);
});
});
Basket.addEvent('onClear', function(Basket) {
getBasketData(Basket).then(function(data) {
window.qTrack('event', 'view_cart', data);
});
});
});
}
// category / product tracking
if (window.QUIQQER_SITE.type === 'quiqqer/products:types/category' && !getProductId()) {
trackCategoryView(window.QUIQQER_SITE.id);
}
if (window.QUIQQER_SITE.type === 'quiqqer/products:types/category' && getProductId()) {
trackProductView(getProductId());
}
QUI.addEvent('onQuiqqerProductsOpenProduct', function(Parent, productId) {
trackProductView(productId);
});
QUI.addEvent('onQuiqqerProductsCloseProduct', function() {
trackCategoryView(window.QUIQQER_SITE.id);
});
QUI.addEvent('onQuiqqerOrderProcessOpenStep', function(OrderProcess) {
getOrderData(OrderProcess).then((order) => {
window.qTrack('event', 'view_cart', order);
});
});
QUI.addEvent('onQuiqqerOrderProcessLoad', function(OrderProcess) {
getOrderData(OrderProcess).then((order) => {
window.qTrack('event', 'begin_checkout', order);
});
});
QUI.addEvent('onQuiqqerOrderProductAdd', function(OrderProcess) {
getOrderData(OrderProcess).then((order) => {
window.qTrack('event', 'add_to_cart', order);
});
});
// finish
QUI.addEvent('onQuiqqerOrderProcessFinish', function(orderHash) {
getOrderData(orderHash).then((order) => {
window.qTrack('event', 'purchase', order);
});
});
if (QUI.getAttribute('QUIQQER_ORDER_CHECKOUT_FINISH')) {
QUIAjax.get('package_quiqqer_order_ajax_frontend_dataLayer_getTrackDataForOrderProcess', function(order) {
window.qTrack('event', 'purchase', order);
}, {
'package': 'quiqqer/order',
orderHash: QUI.getAttribute('QUIQQER_ORDER_CHECKOUT_FINISH')
});
}
});
});
......@@ -29,6 +29,7 @@
"quiqqer\/tax": "^1|dev-master|dev-dev",
"quiqqer\/payment-transactions": "^1|dev-master|dev-dev",
"quiqqer\/fontawesome": ">=4.5|dev-master|dev-dev",
"quiqqer\/data-layer": "^1|dev-master|dev-dev",
"ramsey\/uuid": "^3|^4",
"quiqqer-asset\/navigo": "5.*",
"quiqqer-asset\/history-events": "1.*"
......
......@@ -43,4 +43,6 @@
<event on="onQuiqqer::products::product::detail::equipment::buttons"
fire="\QUI\ERP\Order\EventHandling::onDetailEquipmentButtons"
/>
<event on="onQuiqqer::template::header::end" fire="\QUI\ERP\Order\EventHandling::onTemplateEnd"/>
</events>
......@@ -441,6 +441,15 @@ public static function onTemplateGetHeader(QUI\Template $Template)
);
}
public static function onTemplateEnd(
Collector $Collection,
QUI\Template $Template
) {
$Collection->append(
'<script src="' . URL_OPT_DIR . 'quiqqer/order/bin/frontend/dataLayerTracking.js"></script>'
);
}
/**
* quiqqer/order: onQuiqqerOrderProcessStatusChange
*
......
<?php
/**
* This file contains QUI\ERP\Order\Utils\DataLayer
*/
namespace QUI\ERP\Order\Utils;
use QUI;
use QUI\ERP\Products\Handler\Fields;
use QUI\ERP\Products\Handler\Products;
use QUI\ERP\Products\Product\Product;
use QUI\ERP\Products\Product\Types\VariantChild;
/**
* Helper for DataLayer Data
*
* item_id: "SKU_12345",
* item_name: "Stan and Friends Tee",
* affiliation: "Google Merchandise Store",
* coupon: "SUMMER_FUN",
* discount: 2.22,
* index: 0,
* item_brand: "Google",
* item_category: "Apparel",
* item_category2: "Adult",
* item_category3: "Shirts",
* item_category4: "Crew",
* item_category5: "Short sleeve",
* item_list_id: "related_products",
* item_list_name: "Related Products",
* item_variant: "green",
* location_id: "ChIJIQBpAG2ahYAR_6128GcTUEo",
* price: 9.99,
* quantity: 1
*/
class DataLayer
{
public static function parseProduct(Product $Product, $Locale = null): array
{
$manufacturer = '';
$variant = '';
$mField = $Product->getField(Fields::FIELD_MANUFACTURER)->getValue();
if (!empty($mField) && isset($mField[0])) {
try {
$manufacturer = QUI::getUsers()->get($mField[0])->getName();
} catch (QUI\Exception $exception) {
}
}
if ($Product instanceof VariantChild) {
$variant = $Product->generateVariantHash();
}
$product = [
'item_id' => $Product->getField(Fields::FIELD_PRODUCT_NO)->getValue(),
'item_name' => $Product->getTitle(),
'category' => $Product->getCategory()->getTitle(),
'price' => $Product->getPrice()->getPrice(),
'currency' => $Product->getPrice()->getCurrency()->getCode(),
'manufacturer' => $manufacturer,
'variant' => $variant
];
// categories
$categories = $Product->getCategories();
$i = 2; // google start the second category at 2
foreach ($categories as $Category) {
/* @var $Category QUI\ERP\Products\Category\Category */
$product['item_category' . $i] = $Category->getTitle($Locale);
$i++;
}
return $product;
}
public static function parseArticle(QUI\ERP\Accounting\Article $Article, $Locale = null): array
{
$Product = Products::getProduct($Article->getId(), $Locale);
$item = self::parseProduct($Product);
$item['price'] = $Article->getPrice()->getValue();
$item['currency'] = $Article->getPrice()->getCurrency()->getCode();
$item['quantity'] = $Article->getQuantity();
if ($Article->getDiscount()) {
$item['discount'] = $Article->getDiscount()->getValue();
}
return $item;
}
public static function parseOrder(QUI\ERP\Order\OrderInterface $Order, $Locale = null): array
{
$calculations = $Order->getArticles()->getCalculations();
$tax = 0;
foreach ($calculations['vatArray'] as $vat) {
$tax = $tax + $vat['sum'];
}
$order = [
'currency' => $Order->getCurrency()->getCode(),
'value' => $calculations['sum'],
'tax' => $tax
];
if ($Order->getShipping()) {
$order['shipping'] = $Order->getShipping()->getPrice();
}
if (QUI::getPackageManager()->isInstalled('quiqqer/coupons')) {
$order['coupon'] = $Order->getDataEntry('quiqqer-coupons');
}
if ($Order->isSuccessful()) {
$order['transaction_id'] = $Order->getHash();
}
// items / articles
$index = 0;
foreach ($Order->getArticles() as $Article) {
$article = self::parseArticle($Article, $Locale);
$article['index'] = $index;
$order['items'][] = $article;
$index++;
}
return $order;
}
}
\ No newline at end of file
0% Lade oder .
You are about to add 0 people to the discussion. Proceed with caution.
Bearbeitung dieser Nachricht zuerst beenden!
Bitte registrieren oder zum Kommentieren