Простая передача в Google Analytics событий ошибок заполнения форм в Magento (и не только)

acca5751e232eb57445ba6a27a4d178dПоступила ко мне такая задача, есть сайт на 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, но и для сайтов на других платформах.