Поступила ко мне такая задача, есть сайт на Magento и заказчик желает мониторить ошибки заполнения форм на сайте в Google Analytics (GA). Как всегда на сайте есть и Prototype и jQuery ну и куча JS лапши в придачу, в общем все как обычно. Сначала я нагородил громоздкое решение, но потом в голову пришла хорошая идея, которой и хочу поделиться с хабрасообществом.
Под JS лапшой я подразумеваю слабо структурированный JS код сторонних разработчиков на этом сайте. Я буду и далее использовать этот термин для краткости. Я не буду описывать лишние подробности и приводить весь код, изложу кратко мой подход, предполагая, что читатель понимает как работают события в GA, имеет базовые представления о Magento и сам сможет вставить код куда следует.
После анализа сайта я понял что мне крупно повезло, т.к. стиль отображения информации на сайте сохранялся единый. Моя идея простая: для валидации полей форм на фронтенде Magento используется библиотека js/prototype/validation.js (путь от корня сайта). Если валидатор обнаруживает ошибку — он добавляет CSS класс ‘validation-failed’ к DOM элементу поля формы. Также этот класс добавлялся всеми обработчиками из JS лапши. Бинго — этот факт можно отслеживать для отправки в GA соответствующего события. Слава богу что практически вся JS лапша использовала для этого либо метод Element.addClassName из Prototype либо addClass из jQuery и было совсем немного кода, использующего нативные методы JS, которые я заменил на Element.addClassName.
Теперь остается только перекрыть эти два метода библиотек Prototype и jQuery для вызова своей функции checkValidationFailed для отправки события в GA. Т.к. код Element.addClassName в Prototype очень простой, то можно просто заменить этот метод, с jQuery так просто не получится — пришлось использовать т.с. «промежуточный» объект.
Вот мой код (он конечно не идеален, но работает):
document.observe('dom:loaded', function () {
Element.addMethods({
addClassName: function(element, className) {
if (!(element = $(element))) {
return;
}
if (!Element.hasClassName(element, className)) {
element.className += (element.className ? ' ' : '') + className;
}
checkValidationFailed(className, element);
return element;
}
});
var oAddClass = jQuery.fn.addClass;
jQuery.fn.addClass = function() {
checkValidationFailed(arguments[0], this[0]);
return oAddClass.apply(this, arguments);
};
function checkValidationFailed(className, element) {
if (className != 'validation-failed') {
return;
}
var label = 'undefined';
if (typeof element.name != 'undefined') {
label = element.name;
}
if (typeof element.labels != 'undefined' &&
typeof element.labels[0] != 'undefined' &&
typeof element.labels[0].innerText != 'undefined'
) {
label = label + ' : ' + element.labels[0].innerText;
}
dataLayer.push({ 'event': 'form_error_jsvalidator', 'error_message' : label });
}
});
Т.к. на сайте используется Google Tag Manager — для отправки сообщений в GA используется стандартный dataLayer.
На основании URL страницы, с которой пришло событие и переменной label в отчете GA легко понять на какой странице и в каком поле формы произошла ошибка — этого было достаточно моему заказчику, но в принципе можно передавать в GA таким образом еще кучу дополнительной информации.
Думаю что такой подход подойдет не только для Magento, но и для сайтов на других платформах.