Skip to content

Instantly share code, notes, and snippets.

@createit-ru
Created December 20, 2023 08:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save createit-ru/2575f7a672060f839747b65383223421 to your computer and use it in GitHub Desktop.
Save createit-ru/2575f7a672060f839747b65383223421 to your computer and use it in GitHub Desktop.
ecommerce.js for MODX (электронная коммерция для MODX)
;
// Можно включить отладку, в этом случае данные дополнительно выводятся в консоль браузера
const ecommerceDebug = true;
const ecommerce = {
options: {
currency: "RUB", // валюта
debug: false
},
initialize: function (currency = "RUB", debug = false) {
ecommerce.options.currency = currency;
ecommerce.options.debug = debug;
// Обработка событий, которые возникают при загрузке страницы
let ecommerceElements = document.querySelectorAll('[data-ecommerce]');
ecommerceElements.forEach(function (ecommerceElement) {
let type = ecommerceElement.dataset.ecommerce;
switch (type) {
case 'impressions':
ecommerce.action.impressions(ecommerceElement);
break;
case 'click':
ecommerce.action.click(ecommerceElement);
break;
case 'detail':
ecommerce.action.detail(ecommerceElement);
break;
case 'purchase':
ecommerce.action.purchase(ecommerceElement);
break;
default:
console.log('[ecommerce] Неизвестный тип действия: ' + type);
break;
}
});
// miniShop2 события
miniShop2.Callbacks.add('Cart.add.response.success', 'ecommerce_add', function (response) {
ecommerce.action.add(response.data);
});
miniShop2.Callbacks.add('Cart.remove.response.success', 'ecommerce_remove', function (response) {
ecommerce.action.remove(response.data);
});
miniShop2.Callbacks.add('Cart.change.response.success', 'ecommerce_change', function (response) {
ecommerce.action.change(response.data);
});
// mSearch2 событие mse2_load
if (window.jQuery) {
jQuery(document).on('mse2_load', function (e) {
let el = document.getElementById(mSearch2.options.results.replace("#", ""));
if(el) {
// Просмотр списка товаров
ecommerce.action.impressions(el);
// Добавим обработчики на клик по товару
let clickElements = document.querySelectorAll('[data-ecommerce="click"]');
clickElements.forEach(function (clickElement) {
ecommerce.action.click(clickElement);
});
}
});
}
},
action: {
add: function (responseData) {
let row = responseData.row;
let productElements = document.querySelectorAll('[itemtype="http://schema.org/Product"]');
productElements.forEach(function (productElement) {
let identifierElement = productElement.querySelector('[itemprop="identifier"]')
if (identifierElement && identifierElement.content === row.id) {
let listElement = productElement.closest('[data-ecommerce="impressions"]');
let list = listElement ? listElement.dataset.ecommerceList : "";
let product = ecommerce.microMarkup.getProduct(productElement);
product.quantity = 1;
let countElement = productElement.querySelector('input[name="count"]');
if (countElement) {
product.quantity = countElement.value;
}
product.price = row.price;
product.list = list;
let data = {
"products": [
product
]
};
ecommerce.action._do("add", data);
}
})
},
remove: function (responseData) {
let row = responseData.row;
let data = {
"products": [
{
"id": row.id,
"name": "", // TODO: miniShop2 не отдает информации о названии товара при действиях в корзине
"price": row.price,
"quantity": row.count
}
]
};
ecommerce.action._do("remove", data);
},
change: function (responseData) {
let row = responseData.row;
if(responseData.cart.hasOwnProperty(row.key)) {
// в корзине есть такой ключ, значит изменилось кол-во товара
// TODO: Функция не реализована.
// в настоящий момент невозможно определить кол-во добавленного или удаленного товара,
// мы только знаем новое количество, чего недостаточно для отправки данных в электронную коммерцию
} else {
// в корзине нет такого ключа, значит товар из корзины удален (пользователь установил кол-во равное 0)
ecommerce.action.remove(responseData);
}
},
click: function (el) {
el.addEventListener('click', function (event) {
let element = event.target; // Начинаем с элемента, на который было совершено нажатие
while (element && (!element.hasAttribute('itemtype') || element.getAttribute('itemtype') !== 'http://schema.org/Product')) {
element = element.parentElement; // Переходим к родителю
}
// Если нашли элемент с нужным атрибутом, выводим информацию (в данном случае, в консоль)
if (element) {
// определяем список, для этого ищем родительский элемент с [data-ecommerce="impressions"]
let listElement = element.closest('[data-ecommerce="impressions"]');
let list = listElement ? listElement.dataset.ecommerceList : "";
let product = ecommerce.microMarkup.getProduct(element);
product.list = list;
let data = {
"products": [
product
]
};
ecommerce.action._do("click", data);
}
})
},
impressions: function (el) {
let products = [];
let productElements = el.querySelectorAll('[itemtype="http://schema.org/Product"]');
let list = el.dataset.ecommerceList;
let position = 1;
productElements.forEach(function (productElement) {
let product = ecommerce.microMarkup.getProduct(productElement);
product.position = position;
product.list = list;
products.push(product);
position++;
});
ecommerce.action._do("impressions", products);
},
detail: function (el) {
let product = ecommerce.microMarkup.getProduct(el);
let data = {
"products": [
product
]
};
ecommerce.action._do("detail", data);
},
purchase: function (el) {
let products = [];
let orderedItems = el.querySelectorAll('[itemprop="orderedItem"][itemtype="http://schema.org/OrderItem"]');
orderedItems.forEach(function (orderedItemEl) {
let quantity = orderedItemEl.querySelector('[itemprop="orderQuantity"]').content;
let product = ecommerce.microMarkup.getProduct(orderedItemEl);
product.quantity = quantity;
products.push(product);
});
let data = {
"actionField": {
"id": el.querySelector('[itemprop="orderNumber"]').content
},
"products": products
};
ecommerce.action._do("purchase", data);
},
_do: function (actionType, data) {
window.dataLayer = window.dataLayer || [];
let obj = {
"ecommerce": {
"currencyCode": ecommerce.options.currency
}
};
obj["ecommerce"][actionType] = data;
window.dataLayer.push(obj);
if(ecommerce.options.debug) {
console.log(JSON.stringify(obj, null, 2));
}
}
},
microMarkup: {
getProduct: function (el) {
let product = {};
const props = {
id: 'identifier',
name: 'name',
model: 'model',
price: 'price',
category: 'category'
};
for (const prop in props) {
let propElement = el.querySelector('[itemprop="' + props[prop] + '"]');
if (propElement) {
product[prop] = (propElement.tagName.toLowerCase() === 'meta')
? propElement.content
: (propElement.textContent || propElement.innerText);
}
}
// Если для product задано model, то используем это значение вместо name
if ("model" in product && product.model) {
product.name = product.model;
delete product.model;
}
return product;
},
}
}
ecommerce.initialize("RUB", ecommerceDebug);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment