GTM中的自定义模板:一个示例

5月底,Google在Google跟踪代码管理器(GTM)中引入了一项新功能:自定义模板或自定义模板。 让我们看看为什么需要它,如何使用它,与HTML标签和JavaScript变量有什么区别。

例如,请考虑为VKontakte动态重定向像素创建自定义模板,然后通过该模板进一步自定义GTM标签。



关于自定义模板的简单词汇
创建自定义模板
•信息选项卡
•字段选项卡
•代码标签
•权限选项卡
在创建的自定义模板上自定义和测试标签
•浏览量
•添加到购物车
•采矿测试
结论

关于自定义模板的简单词汇


自定义模板是用户可以用来创建新标签或变量的模板。 GTM具有现成的模板(在“特色”或“推荐”部分),例如Google Analytics(分析)标记,Google Optimize等。 现在我们可以用我们的模板对其进行补充。 创建后,它们将出现在“自定义”选项卡中:



与HTML标记和JS变量的主要区别在于,当用户使用现成的模板创建标记或变量时,他不会与JS代码进行交互。

用户模板的代码由开发人员或网络分析师在其创建阶段编写。 然后,当根据用户模板创建标签或变量时,所有交互都通过接口执行(在创建用户模板时也进行了配置):



因此,与编写HTML标签或JS变量相比,根据用户模板自定义标签或变量变得容易一个数量级,因为这不需要使用JavaScript的知识和技能。

自定义模板的另一大优点是,由于标签的JS代码中的错误,“放置”网站的可能性降低了一个数量级。

在我们的示例中,要配置动态重定向标签“ VKontakte”,您不再需要与开发人员联系-一切都可以独立设置,即使商品的数据传输(在网站上配置了Google的高级电子商务),也只有GTM经验。

创建自定义模板


由于我们正在创建标签模板,因此需要转到“模板”部分,然后单击“标签模板”部分中的“新建”按钮。



之后,模板编辑器将打开:



编辑器的左侧是设置窗口,右侧是预览窗口和控制台。 设置窗口中有四个选项卡,它们是创建和使用模板所必需的。

信息标签


标签上的信息在此选项卡上填写:名称,描述,图标。 这是在模板列表中创建新标签时将看到的信息:



标记图标有以下要求:PNG,JPEG或GIF格式,至少64x64像素的分辨率和不超过50 KB的大小。

字段标签


本部分创建模板的界面。 该界面包含各种字段和形式,在创建新标签或变量的阶段,用户可以与之交互。

将来,模板代码中将使用用户使用界面创建标签时输入的信息。

要添加新元素,请单击“添加字段”按钮。 出现用于选择元素类型的窗口:



GTM允许您选择以下类型的界面元素:

  • 文字框
  • 下拉菜单
  • 复选框 ;
  • 开关
  • 简单表格 ,您可以在此处编辑每个单元格。
  • 扩展表 ,您只能编辑一行,这种类型的表很方便用于从键值对创建字典;
  • 元素组 ,允许您将几种类型分组为一组;
  • 快捷方式用于向界面添加文本;它不需要用户输入任何数据。

添加元素后,需要给它起一个友好的名称,该名称随后将在代码中使用。 这是一种变量名-应该易于理解并且可以揭示所创建接口元素的本质。 例如,名称“ ID”并不表示任何特定含义,但名称“ pixelIDs”已经表明用户输入的像素ID存储在此元素中:



接下来,转到每个元素的设置并激活必要的属性。
在不同情况下,需要接口元素的不同属性,因此默认情况下它们都是隐藏的,我们需要激活现在需要的那些属性:



对于不同类型的元素,可用属性有所不同,我将指出最常用的元素,几乎是所有元素:

1.显示名称 。 这是用户在创建标签时将在界面中看到的名称:



2.示例值 。 这向用户提示要在字段中输入哪些值:



3.帮助文本 。 这是用户将鼠标悬停在元素的帮助图标上时将看到的文本:



4.数据验证规则 。 在此属性中,您可以设置某些规则来检查用户在字段中输入的数据,并在必要时设置尝试使用未通过测试的数据保存标签时显示的错误文本。

例如,您可以指定必须填写该字段。 第二个示例:您需要从用户那里获取电子邮件地址,然后可以验证用户输入的数据必须与正则表达式。* @。* \ .. *匹配。



要指定在输入的数据不符合验证规则时出现的错误文本,您需要激活高级规则设置:





另外,在高级设置中,您可以指定激活此规则的条件(“启用条件”字段)。

5.纳入条款 。 这些是用户拥有此界面元素的条件。

例如,为了不使模板中的界面元素超载,可以在选中复选框时使必要元素的外观。 也就是说,假设用户想要以像素为单位配置产品数据的传输(使用网站上配置的高级Google电子商务网站可以实现),那么他选中“使用dataLayer传输产品数据”复选框,并在选中该复选框后,元素将出现在标签界面中需要配置这样的传输。 如果未选中该框,则界面中没有元素。



我注意到在这里有必要指出元素的名称,在添加之后必须立即为其赋值。

添加设置并创建界面时,可以在预览窗口中立即查看和测试所有更改:



代码标签


此选项卡是代码编辑器。

GTM自定义模板代码是用精简的JavaScript ES6编写的,并在隔离的环境中运行,在该环境中,所有与全局数据(即直接与页面)的通信都是通过API完成的。 也没有分别使用常规方法的全局对象,例如窗口或文档。 例如,构造函数(新对象等),setTimeout,parseInt,delete等。 -所有这些都无法在“自定义模板”中使用。

但是所有这些都有一个API。 因此,编写自定义模板的代码应首先定义我们将在代码中使用的API:

// API //     const copyFromWindow = require('copyFromWindow'); //     const setInWindow = require('setInWindow'); //      const injectScript = require('injectScript'); //    const callInWindow = require('callInWindow'); //  ,     ,    const makeTableMap = require('makeTableMap'); //   URL  const getUrl = require('getUrl'); //    const getQueryParameters = require('getQueryParameters'); //     const makeInteger = require('makeInteger'); //    const makeString = require('makeString'); //  setTimeout const callLater = require('callLater'); //  console.log const logToConsole = require('logToConsole'); 

请参阅Google Developer Help,以获取 API 完整列表以及详细文档。

我将向您展示如何使用API​​的示例:
动作说明经典js自定义模板API
控制台输出console.log('嗨');logToConsole('Hi');
设定计时器setTimeout(函数,100);callLater(函数);
转换为字符串字符串(1234);makeString(1234);
转换为整数parseInt('1234',10);makeInteger('1234');
页面主机window.location.hostnamegetUrl('host');

从示例表中可以看到,定义API后,必须使用它而不是标准JS构造。

定义API之后,最好使用用户输入的设置来定义对象。 例如,这也可以在可执行代码期间从用户的设置中请求必要的数据之后完成。 但是,如果我们从一开始就定义设置对象,那么使用代码将变得更加容易和易于理解,因为所有用户设置都存储在单独的对象中。

要从接口元素获取数据,必须使用数据构造。

{{元素名称}}:

 //    const settings = { //  event: data.event, //ID  () pixelIDs: data.pixelIDs, //ID - (  1 -) priceListId: data.priceListId, //   -? fewPriceLists: data.fewPriceLists, //ID - (    ) priceListIds: data.priceListIds === undefined ? data.priceListIds : makeTableMap(data.priceListIds,'hostname','priceListId'), //  ecommerce   ? ecommerceUse: data.ecommerceUse, // ecommerce   eventEcommerce: data.eventEcommerce, //     siteSearchQueryParam: data.siteSearchQueryParam }; 

注意:如果将undefined传递给makeTableMap方法,将导致脚本错误,因此我使用带有三元运算符的构造(if-else构造的缩写记录)来过滤掉此类脚本。

关于makeTableMap方法。
如果接口使用扩展表,则其中的数据将以以下形式存储:

 [ 'key': 'k1', 'value': 'v1'}, 'key': 'k2', 'value': 'v2'} ] 

使用makeTableMap方法处理后,数据将成为具有键值对的常规对象:

 { 'k1': 'v1', 'k2': 'v2' } 


自定义模板代码的另一个要求:如果成功执行了标记,则必须调用data.gtmOnSuccess()方法,如果发生错误,请调用data.gtmOnFailure()方法。

例如,在我的代码中,成功发送请求后,将调用data.gtmOnSuccess()方法,如果在外部脚本页面VK openapi.js上下载失败,则将调用data.gtmOnFailure()方法。

在定义了API并使用设置定义了对象之后,您可以开始编写用于计算像素的算法。

这里要记住的主要事情是:

•如果需要获取全局变量,请使用copyFromWindow API方法。

 copyFromWindow('VK'); //VK -   ,     

•如果需要设置全局变量,则使用setInWindow API方法。

 setInWindow('openapiInject', 1); //openapiInject -   ,    //1 - ,    . 

•如果您需要运行全局函数,请使用callInWindow API方法。

 callInWindow('VK.Retargeting.Init', p); //VK.Retargeting.Init -   ,    //p - ,      

•如果需要在页面上添加外部脚本,请使用injectScript API方法。

 injectScript('https://vk.com/js/api/openapi.js?159', pixel.setVkAsyncInit(), data.gtmOnFailure, 'vkPixel'); //https://vk.com/js/api/openapi.js?159 -  ,      //pixel.setVkAsyncInit() - ,        //data.gtmOnFailure - ,        //vkPixel -  ,  ,   URL  .    ,   JavaScript       

•如果需要获取URL(或URL的一部分),请使用getUrl API方法。

 getUrl('host'); //host -  URL,  .  ,  host: protocol, port, path, extension, fragment, query. 

如我上面所写,自定义模板支持JS ES6。 建议使用此语法,因为它可以缩短代码并使代码更易读,并且JS的工作更可预测且类似于其他编程语言。

有关JS ES6语法的更多信息
需要使用的主要功能是箭头函数和const的声明,并让变量而不是var。

通过const声明的变量是一个常量,其值不能更改。

通过let声明的变量与通过var声明的变量不同,如下所示:

  • let不添加到全局窗口对象;
  • 让可见性仅限于声明块;
  • 通过let声明的变量无法重新声明。

箭头功能是常用功能的缩写:

 //1.   const func1 = function() { return 'test'; } //    const func1 = () => 'test'; //2.   const func2 = function(arg) { if (arg > 0) return 'plus'; else return 'minus'; } //    const func2 = arg => { if (arg > 0) return 'plus'; else return 'minus'; } //3.   const func3 = function(arg1, arg2){ if (arg1 > arg2) return arg1; else return arg2; } //    const func3 = (arg1, arg2) => { if (arg1 > arg2) return arg1; else return arg2; } 


现在,我们了解了如何使用自定义模板API,可以使用JavaScript ES6语法编写标签操作代码。

我的代码包含以下方法:启动像素,安装VK openapi.js,从dataLayer(配置了Google的高级电子商务网站)中检索产品数据,处理这些数据,使其转化为发送给VKontakte重定向像素所需的格式,以及事件分配方法。

像素触发方法支持三种情况:

  1. 像素在缺少openapi.js的页面上运行。
  2. 该像素在存在openapi.js的页面上运行,但尚未加载。
  3. 在加载了openapi.js的页面上启动像素。

我的VKontakte动态重定向像素的自定义GTM模板的完整代码
 //api const copyFromWindow = require('copyFromWindow'); const setInWindow = require('setInWindow'); const injectScript = require('injectScript'); const callInWindow = require('callInWindow'); const makeTableMap = require('makeTableMap'); const getUrl = require('getUrl'); const getQueryParameters = require('getQueryParameters'); const makeInteger = require('makeInteger'); const makeString = require('makeString'); const callLater = require('callLater'); //    const settings = { event: data.event, pixelIDs: data.pixelIDs, priceListId: data.priceListId, fewPriceLists: data.fewPriceLists, priceListIds: data.priceListIds === undefined ? data.priceListIds : makeTableMap(data.priceListIds,'hostname','priceListId'), ecommerceUse: data.ecommerceUse, eventEcommerce: data.eventEcommerce, siteSearchQueryParam: data.siteSearchQueryParam }; //       const pixel = { //    getPageHostname: () => getUrl('host'), //    VK getVK: () => copyFromWindow('VK'), //    VK setVkAsyncInit: () => { setInWindow('vkAsyncInit', pixel.sendEvent); }, //       getSiteSearchPhrase: () => { if (settings.event === 'view_search') return getQueryParameters(settings.siteSearchQueryParam); else return undefined; }, //      getEventParams: (products, currencyCode, revenue) => { let eventParamsClean= {}; let eventParams = { products: eventProducts.getProductParams(products), category_ids: eventProducts.getCategoryString(products), currency_code: currencyCode, total_price: eventProducts.getTotalPrice(products, revenue), search_string: pixel.getSiteSearchPhrase() }; if (eventParams.products !== undefined) eventParamsClean.products = eventParams.products; if (eventParams.category_ids !== undefined) eventParamsClean.category_ids = eventParams.category_ids; if (eventParams.currency_code !== undefined) eventParamsClean.currency_code = eventParams.currency_code; if (eventParams.total_price !== undefined) eventParamsClean.total_price = eventParams.total_price; if (eventParams.search_string !== undefined) eventParamsClean.search_string = eventParams.search_string; return eventParamsClean; }, //  - getPriceListId: hostname => { if (settings.fewPriceLists) return settings.priceListIds[hostname]; else return settings.priceListId; }, //  openapi.js openapiInit: () => { injectScript('https://vk.com/js/api/openapi.js?159', pixel.setVkAsyncInit(), data.gtmOnFailure, 'vkPixel'); setInWindow('openapiInject', 1); }, //   sendEvent: () => { if (settings.event === 'hit') { settings.pixelIDs.split(',').forEach(p => { callInWindow('VK.Retargeting.Init',p); callInWindow('VK.Retargeting.Hit'); }); } else { const pricelist = pixel.getPriceListId(pixel.getPageHostname()); const name = settings.event; let products = []; if(settings.ecommerceUse) products = name === 'view_home' || name === 'view_category' || name === 'view_search' || name === 'view_other' ? settings.eventEcommerce : settings.eventEcommerce.products; else products = undefined; const currencyCode = settings.ecommerceUse ? settings.eventEcommerce.currencyCode : undefined; const revenue = (settings.ecommerceUse && name === 'purchase') ? settings.eventEcommerce.actionField.revenue : undefined; const eventParams = settings.ecommerceUse ? pixel.getEventParams(products, currencyCode, revenue) : undefined; settings.pixelIDs.split(',').forEach(p => { callInWindow('VK.Retargeting.Init',p); callInWindow('VK.Retargeting.ProductEvent', pricelist, name, eventParams); }); }, //   start: () => { if (pixel.getVK() === undefined && copyFromWindow('openapiInject') !== 1) { pixel.openapiInit(); data.gtmOnSuccess(); } else if (pixel.getVK() === undefined && copyFromWindow('openapiInject') === 1) { if (pixel.count < 50) { callLater(pixel.start); pixel.count++; } else return; } else { pixel.sendEvent(); data.gtmOnSuccess(); }, //   count: 0 }; //       const eventProducts = { //    products   getProductParams: products => { let arr = []; products.forEach(i => { let productParamsClean = {}; let productParams = { id: makeString(i.id), group_id: makeString(i.brand), price: makeInteger(i.price * 100) / 100 }; if (productParams.id !== 'undefined') productParamsClean.id = productParams.id; if (productParams.group_id !== 'undefined') productParamsClean.group_id = productParams.group_id; if (productParams.price !== 0) productParamsClean.price = productParams.price; arr.push(productParamsClean); }); return arr; }, //       'a,b,c'       getCategoryString: products => { let categoryId = ''; let check = []; products.forEach(i => { if(check.indexOf(i.category) === -1) { check.push(i.category); categoryId += ',' + i.category; }); return categoryId.slice(1); }, //     getTotalPrice: (products, revenue) => { let sumPrice = 0; if (revenue !== undefined ) return makeInteger(revenue * 100) / 100; else { products.forEach(i => { if (i.hasOwnProperty('quantity')) sumPrice += (makeInteger(i.price * 100) / 100) * makeInteger(i.quantity); else sumPrice += makeInteger(i.price * 100) / 100; }); return sumPrice; }; //  pixel.start(); 


权限标签


编写完标记代码后,最后阶段仍然存在-发出与页面的全局数据进行交互的权限。 只需在“权限”选项卡上即可完成。

由于代码是在隔离的环境中执行的,并且通过API与全局数据进行交互,因此对于每种API方法(必要时),我们需要手动指定某些操作的权限。

这样做是为了尽可能审慎地使用全局页面数据,从而最大程度地减少了将网站“放入”模板代码错误的机会。

对于我的代码中使用的API方法,必须发出三种类型的权限:



1.访问全局变量 -读取,写入,执行对我们代码中使用的全局变量的访问。 必须手动添加变量,并且每个变量都指示我们允许执行的操作。



例如,只能读取VK变量,可以读取和重新定义vkAsyncInit,并且只能执行VK.Retargeting.Hit方法。

2.读取URL 。 在这里,您必须指定允许接收URL的哪些部分。 我允许接收URL的任何部分:



但是,如果您愿意,可以指定任何特定的:



3.注入脚本 。 在此必须注册可从中下载外部脚本的地址。 在我的代码中,仅加载了一个带有VK openapi.js的脚本,我指定了其地址:



就是这样,自定义模板设置已完成,您可以保存模板并进行测试。

在创建的自定义模板上自定义和测试标签


例如,我们将使用创建的自定义模板创建两个“ VKontakte”动态重定向标签:pageview和addToCart。

浏览量


我们将进入必要的GTM容器,创建一个新标签,然后在“自定义”部分中选择标签类型VK Pixel:



填写标签名称,选择要跟踪的事件,选择“命中”(这是标准的网页浏览量),在“像素ID”字段中,将数据发送到的两个像素的ID,然后设置“所有页面”触发器:



保存创建的标签。

加入购物车


为将产品添加到购物车的事件创建标签比点击标签要复杂一些。

首先,您需要转移添加到购物篮中的货物。 正如我在上文所述,通过在网站上配置Google的高级电子商务,这是有可能的。 在这种情况下,产品数据取自dataLayer。

为此,我们需要在GTM中创建dataLayer变量,该变量将存储addToCart事件的电子商务对象。 变量设置如下所示:



其次,您需要创建一个触发器,该触发器将在电子商务addToCart事件发生时激活标签(当addToCart事件发生时,在推入dataLayer时,触发器将激活标签):



在使用电子商务对象和触发器创建变量后,您可以开始创建代码:



为了:

  1. 作为跟踪事件,选择“添加到购物车”。
  2. 我们填写两个像素的逗号分隔ID,必须将数据传输到其中。
  3. 设置复选框“使用多个价格表”:在我们的示例中,对于莫斯科和圣彼得堡,必须使用不同的价格表。
  4. 用价格表填写表格。
  5. 设置复选框“使用电子商务转移产品和参数”。
  6. 在此事件的电子商务对象中,指定先前创建的变量。
  7. 我们为受监控事件设置触发器,在本例中为AddToCart。
  8. 保存。

采矿测试


要检查VKontakte上动态重定向的像素值,您需要在GTM中激活预览模式,请访问我们的网站并在浏览器控制台中打开“网络”部分,然后在“过滤器”字段中输入“ rtrg”:


之后,我们刷新页面,并且应该有两个请求-以两个像素发送的Hit事件:



状态200表示服务器已成功发送和接收请求。

同样在“预览GTM”窗口中,我们看到我们创建的标记对于“页面查看”事件正常工作。

要检查“添加到购物车”事件,请将产品添加到购物车,在控制台中,我们还有两个请求:



在“预览GTM”窗口中,我们看到第二个标签成功运行。 来自dataLayer的产品数据被正确提取并处理,正确的价格表也被替换。

对于第二个主机,价格表也可以正确替换:



其他事件的标签以相同的方式配置和检查。

结论


自定义模板正在改变使用GTM的熟悉范例。 每个人都习惯了HTML标签和JS变量,但是现在有一个很好的选择。

一次创建一个高质量的自定义模板就足够了,然后熟悉GTM的任何人都可以使用它。

鉴于可以共享创建的模板的功能,我认为它们应该在用户中越来越受欢迎。

您可以下载我们在本文中研究过 VKontakte 自定义动态重定向像素模板

要导入模板,您需要创建一个新的自定义模板,然后从菜单中选择导入:



我为ppc.world准备的材料

Source: https://habr.com/ru/post/zh-CN458788/


All Articles