Контекстный кодинг: как улучшить работу с Google Tag Manager с помощью программирования

Пошаговая инструкция на примере GTM вместо Yagla.

В закладки
Аудио

В комментариях к статье «Google Tag Manager вместо Yagla» меня спросили, как реализовать текстовую подмену, если переменная podmena не равна заданному слову, а содержит его. Допустим, если в переменной есть слово «москва», а на сайте должно отобразиться «дешёвые слоны в Москве». Фактически — как использовать текстовую подмену на сайтах ещё эффективнее. Задача нетривиальная настолько, что достойна отдельной статьи.

Привет, я Александр Зарайский, руководитель обучающего центра контекстного рекламного агентства MOAB. Сегодня я покажу вам, как упростить работу в Google Tag Manager с помощью кодинга. Если вы ещё не читали мою статью «Google Tag Manager вместо Yagla», рекомендую сначала ознакомиться с ней, так как разобранный здесь пример сделан на её основе.

В чём вообще проблема?

Допустим, вы сделали текстовую подмену по инструкции из прошлой статьи. Теперь у вас в ссылке есть переменная podmena. Если вписать в неё значение, которое вы добавили в таблицу поиска — например, «москва», — то новый заголовок подставится автоматически. Вот так:

Но что, если вы захотите, чтобы переменная передавала не вписанные значения, а, допустим, значение {keyword} из вашей UTM-метки? Например, «купить инкубатор москва» или «купить инкубатор в москве», или даже просто слово «москве». Вот что получится:

Что-то пошло не так. Конечно, мы можем вписать в таблицу поиска каждое требуемое значение, но это очень долго. Да и редактировать таблицу поиска в дальнейшем будет трудно, особенно если накопится много ключевых слов. Таблица поиска может разрастись до нескольких сотен или даже тысяч строк, работать с которыми придётся вручную. Перспектива неприятная.

Впрочем, есть более простой и удобный вариант — именно его мы разберём.

Пошаговый алгоритм

Вот такой результат мы должны получить:

Давайте разбираться, как это сделать.

У нас есть готовая таблица поиска podmena, которая принимает три значения и даёт на выходе конкретный текст для заголовка:

Значения подтягиваются из URL переменной «Запросы для подмены».

В общем, всё, что мы делали для создания подмены, работает корректно.

Но есть проблема. Сейчас подмена работает по алгоритму: если значение podmena равно значению из таблицы поиска, то подменяем заголовок на сайте.

А нам нужно сделать другой алгоритм: если значение podmena содержит значение из таблицы поиска, то подменяем заголовок на сайте.

Чтобы этого добиться, нужно сделать «прокладку» между podmena и таблицей поиска. Речь о «прокладке» в виде отдельной функции, которая будет проверять значение podmena, искать нужные фразы и передавать результат таблице поиска. Тем самым выполняя условие «содержит».

Звучит сложно? Всё не так страшно, давайте сделаем и разберём результат.

Для начала создадим новую переменную типа «Собственный код JavaScript» и назовем её «Проверка переменной podmena».

Оставить эту переменную пустой нельзя, потому сразу заполним её кодом. Те, кто хорошо знаком с JavaScript, спокойно добавляют код, сохраняют переменную и читают дальше. Для тех, кто не знает этого языка программирования, я добавил подробные объяснения.

Сам код:

function() { var podmena; //объявление новой переменной podmena = {{Запрос для подмены}}; //записываем значение podmena из URL в переменную return podmena; //возвращаем значение переменной }

Вот что мы сделали:

  • Объявили функцию JavaScript.
  • Объявили переменную.
  • Записали значение «Запрос для подмены» в переменную.
  • Сделали так, чтобы функция возвращала значение podmena в качестве результата.

Теперь подробный разбор:

1. Объявление функции JavaScript — комбинация «function()». Рабочие процессы функции обрамлены в фигурные скобки:

«function() { }»

Обычно фигурные скобки пишут с новой строки для удобства понимания.

2. Мы создали переменную комбинацией «var [название переменной]». Необязательно называть переменную podmena. Можно, например, назвать переменную «var p», но это будет менее понятно, правда? Чтобы не запутаться в коде, выбирайте понятные названия для переменных.

Любое объявление переменной заканчивается точкой с запятой:

«var podmena;»

Так компьютер поймёт, что это отдельная переменная.

3. Мы указали, что переменная podmena равна значению из URL переменной «Запрос для подмены»:

podmena = {{Запрос для подмены}};

При этом «Запрос для подмены» заключается аж в две фигурные скобки с каждой стороны. Это требование GTM для того, чтобы обращаться к другим переменным в аккаунте. Таким образом вы можете обращаться к любым переменным и использовать их в своём коде.

4. Теперь переменная podmena имеет точно такое же значение, что и «Запрос для подмены», и последнее, что делает функция, это возвращает значение:

return = podmena;

Функция будет возвращать значение, где бы она ни была вызвана. Теперь мы эту функцию прикрепим к таблице поиска, и перемычка готова! Смотрите:

Если в таблицу поиска установить в качестве входной переменной новую функцию, будет происходить вот что:

  • Podmena в URL передаёт значение в «Запрос для подмены».
  • «Запрос для подмены» передаёт значение в функцию.
  • Функция передаёт значение в таблицу поиска.

Так функция становится нужной нам перемычкой. Но пока она ещё ничего не делает с тем значением, которое получает. Потому давайте улучшим функцию следующим кодом:

function() { var podmena = {{Запрос для подмены}}; //принимаем значение podmena из URL var stringForCheck = "москв"; //искомое значение, которое будем искать в podmena var stringIfSuccess = "москва"; //какое значение вернем, если найдем нужное значение var checkOut = podmena.indexOf(stringForCheck); //ищем индекс нужного значения в переменной if (checkOut > 0) //если он нашелся, возвращаем ожидаемое значение { return stringIfSuccess; } return podmena; }

Мы сделали четыре переменных и добавили условия if, а также использовали метод indexOf.

Теперь давайте разбираться.

Как видите, мы упростили объявление переменной и запись значения, соединив всё вместе:

var podmena = {{Запрос для подмены}};

Работает так же, как и в прошлом коде, только запись короче.

Также мы создали две переменных:

var stringForCheck = "москв";

var stringIfSuccess = "москва";

Их роль я объясню чуть позже.

Ещё у нас есть переменная:

var checkOut = podmena.indexOf(stringForCheck);

В эту переменную checkOut мы записываем не просто значение podmena, а индекс значения stringForCheck, которое есть в значении podmena.

То есть stringForCheck у нас равно «москв». Если это значение «москв» будет в podmena, нам вернётся индекс, который покажет, где это слово в строке начинается.

Предположим, что podmena = «инкубатор москва». Тогда при проверке podmena.indexOf(“москв”); индекс будет равен 10. То есть слово “москв” начинается с 10 буквы в строке.

Если искомого слова не найдётся, индекс будет равен -1.

Так мы сделали ищейку, которая находит нужные слова! Это именно то, что нужно для текущей задачи.

Осталось только обработать результат ищейки и выдать ответ. Обработать ответ можно примерно таким образом:

Если слово нашлось в тексте (индекс не равен -1), то функция должна об этом сообщить в таблицу поиска.

В другом случае (индекс равен -1) функция ничего не делает и передаёт результат в таблицу поиска.

Именно такую обработку и совершают последние строки кода:

if (checkOut > 0) { return stringIfSuccess; } return podmena;

Здесь if совершает проверку переменной checkOut. Если переменная больше нуля (checkOut > 0), совершаются действия в фигурных скобках (return stringIfSuccess). Если checkOut меньше нуля (например, -1), действие в фигурных скобках совершаться не будет.

В конце функции есть значение

return podmena;

return — команда к завершению функции. То есть когда объявляется return, функция возвращает указанное рядом с return значение (return «что-то»; //например) или может ничего не указывать и вызвать

return;

Тогда функция себя завершит и ничего не вернет после обработки.

А теперь ещё раз обратим внимание на комбинацию:

if (checkOut > 0) { return stringIfSuccess; } return podmena;

Если условие if срабатывает, то произойдет

return stringIfSuccess;

Функция завершит работу и вернет значение. А return podmena; уже не сработает, так как функция завершила свою работу ранее.

Если условие if не сработало, то у нас сработает стандартное return podmena.

Вот и всё! С помощью этого кода реализуется алгоритм поиска указанного слова (stringForCheck) и возвращается нужное значение (stringIfSuccess), если фраза найдена. Так что уже неважно, какое ключевое слово находится в podmena, лишь бы там была интересующая нас фраза.

Но можно сделать ещё одно приятное улучшение. Сейчас идёт проверка только одной фразы. А ведь фраз в таблице поиска несколько, и было бы неплохо проверять на наличие каждую. Для этого мы можем улучшить существующую функцию:

function() { var podmena = {{Запрос для подмены}}; //принимаем значение podmena из URL //искомые значения, которые будем искать в podmena var stringForCheck = ["москв", "петербург", "питер", "красноярск", "житомир"]; //какое значение вернем, если найдем искомое var stringIfSuccess = ["москва", "петербург", "петербург", "красноярск", "житомир"]; var result = podmena; for (var i = 0; i < stringForCheck.length; i++) { var checkOut = podmena.indexOf(stringForCheck[i]); //ищем индекс искомого значения в переменной if (checkOut >= 0) //если он находится, возвращаем ожидаемое значение { return stringIfSuccess[i]; } } return podmena; }

Итак. Что мы добавили:

1. В значении переменной появились перечисленные в кавычках слова, заключённые в квадратные скобки.

2. Добавился цикл for.

А теперь расшифруем.

1. У нас есть переменная

var stringForCheck = ["москв", "петербург", "петербург", "красноярск", "житомир"];

Благодаря квадратным скобкам она хранит не одно значение, а несколько. Такая переменная носит гордое название «массив».

Теперь доступ к данным переменной можно получить только с указанием индекса желаемого значения. Важно — индекс всегда начинается с нуля.

Например, если мы хотим найти «питер» и вписать это значение в другой переменной, нужно указать:

var anotherVariable = stringForCheck[2];

А если нужно вписать значение «москв», то:

var anotherVariable = stringForCheck[0];

2. Цикл for предполагает, что функция несколько раз повторит один и тот же алгоритм действий, указанный в фигурных скобках, пока выполняется условие, указанное в обычных скобках.

Мы задаём условие цикла:

for (var i = 0; i < stringForCheck.length; i++)

Для этого создаём переменную i и приравниваем её к нулю:

var i = 0;

Затем задаём условие:

i < stringForCheck.length;

Этот метод stringForCheck.length возвращает значение длины массива stringForCheck. Если посмотреть в код выше, мы увидим, что там записано пять слов через запятую. Соответственно, этот метод вернёт значение 5.

Мы проверяем, что i меньше длины stringForCheck. Пока это справедливо, алгоритм в фигурных скобках будет выполняться.

И последнее:

i++)

Эта строчка указывает, что после выполнения всего алгоритма в фигурных скобках цикла for к переменной i прибавляется единица.

Итак, что происходит:

1. Создаётся переменная i и приравнивается к нулю.

2. Сверяется i с длиной массива stringForCheck.

3. Выполняется алгоритм, если i меньше длины массива.

4. Прибавляется единица к i.

5. Проверка повторяется с п.2.

Если условие п.2 не выполняется, то цикл for завершается.

Итак, давайте рассмотрим работу алгоритма цикла.

for (var i = 0; i < stringForCheck.length; i++) { var checkOut = podmena.indexOf(stringForCheck[i]); if (checkOut >= 0) { return stringIfSuccess[i]; } }

Тут всё просто и знакомо. Мы задаём переменную checkOut. Приравниваем её значение к индексу значения массива. И тут есть важный момент: мы ищем индекс переменной stringForCheck[i]. То есть мы используем переменную i, чтобы каждую итерацию цикла for получать каждое значение массива по очереди (сначала 0, потом 1, потом 2 и так далее). Так цикл for проходит по всем значениям массива, а значит, по всем городам, которые записаны в переменной stringForCheck.

Дальше происходит проверка: если индекс текущего значения больше нуля (найдено текущее проверяемое слово), то функция завершается (return) и возвращается значение из другой переменной stringIfSuccess. А в stringIfSuccess у нас записан ряд значений, которые имеют такую же очередь, как и в stringForCheck. Поэтому в таблицу поиска вернётся нужное значение.

Разберём на примере, чтобы было понятно. Предположим, значение podmena = «инкубатор в петербурге»;

Далее задаются нужные переменные, и начинается цикл for.

Первый цикл, i равно нулю.

Происходит проверка:

var checkOut = podmena.indexOf(stringForCheck[0]); if (checkOut >= 0) { return stringIfSuccess[0]; }

stringForCheck[0] у нас равен «москв», а в переменной podmena такого значения нет, потому проверка if будет неудачной, и цикл for пойдёт на следующий круг.

Второй цикл, i теперь равен единице.

Происходит следующая проверка:

var checkOut = podmena.indexOf(stringForCheck[1]); if (checkOut >= 1) { return stringIfSuccess[1]; }

stringForCheck[1] у нас равен «петербург». Такое значение в переменной podmena есть. Следовательно, проверка if будет успешной, и функция завершит работу и вернёт значение stringIfSuccess[1], который равен «петербург».

Так можно проверять множество значений на наличие в pomena и возвращать нужные нам переменные.

Если вы впервые сталкиваетесь с программированием и осилили всю эту информацию, то поздравляю с базовым введением в программирование.

Подробнее обо всем, что я тут рассказал, можно почитать в учебнике JavaScript.

В заключение

Эта функция — лишь один из вариантов удобной работы с GTM. Её можно улучшить и сделать более гибкой.

Надеюсь, я подтолкнул вас к новым идеям применения JavaScript для работы с GTM. Если остались вопросы или появились мысли, как можно улучшить функцию, — пишите в комментариях

#инструкции

Материал опубликован пользователем. Нажмите кнопку «Написать», чтобы поделиться мнением или рассказать о своём проекте.

Написать
{ "author_name": "Александр Зарайский", "author_type": "self", "tags": ["\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438"], "comments": 21, "likes": 42, "favorites": 100, "is_advertisement": false, "subsite_label": "marketing", "id": 57788, "is_wide": true, "is_ugc": true, "date": "Thu, 07 Feb 2019 11:50:00 +0300" }
{ "id": 57788, "author_id": 139172, "diff_limit": 1000, "urls": {"diff":"\/comments\/57788\/get","add":"\/comments\/57788\/add","edit":"\/comments\/edit","remove":"\/admin\/comments\/remove","pin":"\/admin\/comments\/pin","get4edit":"\/comments\/get4edit","complain":"\/comments\/complain","load_more":"\/comments\/loading\/57788"}, "attach_limit": 2, "max_comment_text_length": 5000, "subsite_id": 199113 }

21 комментарий 21 комм.

Популярные

По порядку

Написать комментарий...
2

Спасибо за статью!
Мы как раз много GTM-им в контексте, а настолько подробного мануала не было :)

Ответить
5

Приятно слышать )
Если будут пожеланию по другим темам GTM, пишите )

Ответить
0

Александр, есть такое пожелание! Было бы здорово, если бы Вы пролили свет на АБ тестирование результатов подмен в текущей реализации. Спасибо за статью, за эту и за будущую! )

Ответить
0

Имеется ввиду, сравнение эффективности подставляемых заголовков друг с другом? По сути, это отдельная статья по инструменту Google Optimize и не уверен, хорошо ли тут сработают подставляемые заголовки... Или, возможно, я не уловил Вашу мысль )

Ответить
2

Это слишком круто, чтобы быть правдой. Спасибо. В закладки !!!

Ответить
1

Приятно читать, Ольга ) Надеюсь поможет

Ответить
1

Спасибо за такое качественное дополнение темы GTM

Ответить
2

Рад, что понравилось )

Ответить
0

круто, что так подробно делитесь

Ответить
1

Предлагайте еще темы, также подробно поделюсь, если смогу )

Ответить
0

на любые темы по контексту, конверсии? )) или ГТМ? )

Ответить
0

Ну что бы продолжить тему, лучше ГТМ )
А если есть сложные вопросы по контексту и конверсиям, то предлагайте

Ответить
0

Очень хорошо! Надо будет обкатать

Ответить
0

Как инициировать вызов тега после полной загрузки DOM если сайт на react.js?

Ответить
0

GTM всегда вызывает тег после полной загрузки DOM, если не ошибаюсь. Но можно привязать условие срабатывания тега, на после того, как DOM было загружено. Не совсем понял, в чем может быть загвоздка при react.js. Можете пояснить?

Ответить
0

тот html тег, который меняется, прилетает в дом после отработки тега GTM. То есть в скрипт тега корректно передается подмененный текст, но в доме не происходит изменений. Не пойму как отловить событие полной загрузки документа. И да, у сайта микросервисная архитектура.

Ответить
0

Если подменить текст нужно не после загрузки DOM, а в произвольный момент, то нужно использовать не триггер "Просмотр страницы", а триггер "Пользовательское событие".

В javascript-коде вашего сайта в момент, когда страница готова к замене текста, нужно выполнить dataLayer.push({'event': 'react_is_ready'});

Тут react_is_ready - это произвольное имя события в вашем триггере в GTM. Чтобы добавить строку в нужное место, потребуются навыки программирования. Всё остальное сможете сделать по статье.

Но! Визуальная задержка перед подменой текста может оказаться критичным моментом, который в итоге потребует переноса всей логики из GTM в react. Нужно пробовать и смотреть, как это выглядит на практике

Ответить
0

Отличный ответ, Эгос ) Кое что и для подчерпнул

Ответить
0

Отличный мануал, подробно, понятно и, как всегда, с роскошными гифками, так что еще и наглядно =) кстати, какую программу используете для записи гифок?

Ответить
0

Рад, что помогает статья )
Для записи использовалась Camtasia Studio 2018

Ответить
–2

Нефига себе как можно....

Ответить
0
{ "page_type": "article" }

Прямой эфир

[ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fizc" } } }, { "id": 4, "label": "240х200_mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "flbq" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjog" } } }, { "id": 10, "disable": true, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "disable": true, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "bscsh", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-223676-0", "render_to": "inpage_VI-223676-0-1104503429", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=bugf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Плашка на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudx", "p2": "ftjf" } } }, { "id": 16, "label": "Кнопка в шапке мобайл", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byzqf", "p2": "ftwx" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvc" } } }, { "id": 19, "label": "Тизер на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "p1": "cbltd", "p2": "gazs" } } } ]
Компания отказалась от email
в пользу общения при помощи мемов
Подписаться на push-уведомления
{ "page_type": "default" }