From 173d1a5d0451d727bc02746e58ccb3c0eee0bb0f Mon Sep 17 00:00:00 2001 From: Geoffrey Roberts Date: Mon, 9 Dec 2019 11:31:17 +1100 Subject: [PATCH] Add ability to add props to script and noscript tags --- README.md | 56 ++++++++++++++------ dist/TagManager.js | 40 ++++++++++----- package-lock.json | 2 +- src/TagManager.js | 87 ++++++++++++++++++++------------ src/__tests__/TagManager.spec.js | 45 +++++++++++------ 5 files changed, 155 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index bc809590..e378562f 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![npm downloads](https://img.shields.io/npm/dm/react-gtm-module.svg?style=flat-square)](https://www.npmjs.com/package/react-gtm-module) # react-gtm-module + ### React Google Tag Manager Module This is a Javascript module to [React](https://facebook.github.io/react/) based apps that implement Google Tag Manager. It is designed to use [GTM](https://developers.google.com/tag-manager/quickstart) snippet. @@ -71,7 +72,6 @@ ReactDOM.render(, app) ``` - ### Multiple dataLayer example: If you need send multiple custom dataLayer you can initialize GTM Module on different components sending different dataLayers @@ -134,6 +134,33 @@ export default Home ``` +### Adding properties to GTM script and noscript tags + +You can also add attributes to your script and noscript tags, +if you need to do so for accessibility or security. + +```js +import React from 'react' +import ReactDOM from 'react-dom' +import Router from 'react-router' +import routes from './routes' + +... +import TagManager from 'react-gtm-module' + +const tagManagerArgs = { + gtmId: 'GTM-000000', + scriptProps: { nonce: 'abcdef' }, + noscriptProps: { 'aria-hidden': 'true' } +} + +TagManager.initialize(tagManagerArgs) +... + +const app = document.getElementById('app') +ReactDOM.render(, app) + +``` ## Events @@ -188,27 +215,26 @@ TagManager.initialize(tagManagerArgs) ``` ##### How can I find auth and preview? + Go to Google Tag Manager -> ADMIN -> Environments -> Actions -> Get Snippet. Look for gtm_auth and gtm_preview -##### Don't know to use GTM environments? - - https://support.google.com/tagmanager/answer/6311518 - - https://www.simoahava.com/analytics/better-qa-with-google-tag-manager-environments/ - - +##### Don't know to use GTM environments? -|Value|Type|Required|Notes| -|------|-----|-----|-----| -|gtmId| `String`| Yes | GTM id, must be something like `GTM-000000`.| -|dataLayer| `Object`| No | Object that contains all of the information that you want to pass to Google Tag Manager.| -|dataLayerName| `String`| No | Custom name for dataLayer object.| -|events| `Object`| No | Additional events such as 'gtm.start': new Date().getTime(),event:'gtm.js'.| -|auth| `String` | No | used to set environments. | -|preview| `String` | No | used to set environments, something like `env-00`. | +- https://support.google.com/tagmanager/answer/6311518 +- https://www.simoahava.com/analytics/better-qa-with-google-tag-manager-environments/ +| Value | Type | Required | Notes | +| ------------- | -------- | -------- | ---------------------------------------------------------------------------------------- | +| gtmId | `String` | Yes | GTM id, must be something like `GTM-000000`. | +| dataLayer | `Object` | No | Object that contains all of the information that you want to pass to Google Tag Manager. | +| dataLayerName | `String` | No | Custom name for dataLayer object. | +| events | `Object` | No | Additional events such as 'gtm.start': new Date().getTime(),event:'gtm.js'. | +| auth | `String` | No | used to set environments. | +| preview | `String` | No | used to set environments, something like `env-00`. | ### Note: - Disabling javascript in the browser can prevent the correct operation of this library if React is only being rendered on the client side. -- Before implementing GTM in your application ensure that you have at least one published container, otherwise Google Tag Manager snippet will return 404. \ No newline at end of file +- Before implementing GTM in your application ensure that you have at least one published container, otherwise Google Tag Manager snippet will return 404. diff --git a/dist/TagManager.js b/dist/TagManager.js index 115c753c..d795b7fa 100644 --- a/dist/TagManager.js +++ b/dist/TagManager.js @@ -1,6 +1,6 @@ -'use strict'; +"use strict"; -var _Snippets = require('./Snippets'); +var _Snippets = require("./Snippets"); var _Snippets2 = _interopRequireDefault(_Snippets); @@ -8,21 +8,31 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de var TagManager = { dataScript: function dataScript(dataLayer) { - var script = document.createElement('script'); + var script = document.createElement("script"); script.innerHTML = dataLayer; return script; }, gtm: function gtm(args) { var snippets = _Snippets2.default.tags(args); - var noScript = function noScript() { - var noscript = document.createElement('noscript'); + var noScript = function noScript(props) { + var noscript = document.createElement("noscript"); + if (props) { + Object.keys(props).forEach(function (pk) { + noscript.setAttribute(pk, props[pk]); + }); + } noscript.innerHTML = snippets.iframe; return noscript; }; - var script = function script() { - var script = document.createElement('script'); + var script = function script(props) { + var script = document.createElement("script"); + if (props) { + Object.keys(props).forEach(function (pk) { + script.setAttribute(pk, props[pk]); + }); + } script.innerHTML = snippets.script; return script; }; @@ -41,11 +51,15 @@ var TagManager = { events = _ref$events === undefined ? {} : _ref$events, dataLayer = _ref.dataLayer, _ref$dataLayerName = _ref.dataLayerName, - dataLayerName = _ref$dataLayerName === undefined ? 'dataLayer' : _ref$dataLayerName, + dataLayerName = _ref$dataLayerName === undefined ? "dataLayer" : _ref$dataLayerName, _ref$auth = _ref.auth, - auth = _ref$auth === undefined ? '' : _ref$auth, + auth = _ref$auth === undefined ? "" : _ref$auth, _ref$preview = _ref.preview, - preview = _ref$preview === undefined ? '' : _ref$preview; + preview = _ref$preview === undefined ? "" : _ref$preview, + _ref$scriptProps = _ref.scriptProps, + scriptProps = _ref$scriptProps === undefined ? {} : _ref$scriptProps, + _ref$noscriptProps = _ref.noscriptProps, + noscriptProps = _ref$noscriptProps === undefined ? {} : _ref$noscriptProps; var gtm = this.gtm({ id: gtmId, @@ -56,13 +70,13 @@ var TagManager = { preview: preview }); if (dataLayer) document.head.appendChild(gtm.dataScript); - document.head.insertBefore(gtm.script(), document.head.childNodes[0]); - document.body.insertBefore(gtm.noScript(), document.body.childNodes[0]); + document.head.insertBefore(gtm.script(scriptProps), document.head.childNodes[0]); + document.body.insertBefore(gtm.noScript(noscriptProps), document.body.childNodes[0]); }, dataLayer: function dataLayer(_ref2) { var _dataLayer = _ref2.dataLayer, _ref2$dataLayerName = _ref2.dataLayerName, - dataLayerName = _ref2$dataLayerName === undefined ? 'dataLayer' : _ref2$dataLayerName; + dataLayerName = _ref2$dataLayerName === undefined ? "dataLayer" : _ref2$dataLayerName; if (window[dataLayerName]) return window[dataLayerName].push(_dataLayer); var snippets = _Snippets2.default.dataLayer(_dataLayer, dataLayerName); diff --git a/package-lock.json b/package-lock.json index e93f6a4f..026b91ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "react-gtm-module", - "version": "2.0.7", + "version": "2.0.8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/TagManager.js b/src/TagManager.js index f2abf1a1..ac154c79 100644 --- a/src/TagManager.js +++ b/src/TagManager.js @@ -1,35 +1,54 @@ -import Snippets from './Snippets' +import Snippets from "./Snippets"; const TagManager = { - dataScript: function (dataLayer) { - const script = document.createElement('script') - script.innerHTML = dataLayer - return script + dataScript: function(dataLayer) { + const script = document.createElement("script"); + script.innerHTML = dataLayer; + return script; }, - gtm: function (args) { - const snippets = Snippets.tags(args) + gtm: function(args) { + const snippets = Snippets.tags(args); - const noScript = () => { - const noscript = document.createElement('noscript') - noscript.innerHTML = snippets.iframe - return noscript - } + const noScript = props => { + const noscript = document.createElement("noscript"); + if (props) { + Object.keys(props).forEach(pk => { + noscript.setAttribute(pk, props[pk]); + }); + } + noscript.innerHTML = snippets.iframe; + return noscript; + }; - const script = () => { - const script = document.createElement('script') - script.innerHTML = snippets.script - return script - } + const script = props => { + const script = document.createElement("script"); + if (props) { + Object.keys(props).forEach(pk => { + script.setAttribute(pk, props[pk]); + }); + } + script.innerHTML = snippets.script; + return script; + }; - const dataScript = this.dataScript(snippets.dataLayerVar) + const dataScript = this.dataScript(snippets.dataLayerVar); return { noScript, script, dataScript - } + }; }, - initialize: function ({ gtmId, events = {}, dataLayer, dataLayerName = 'dataLayer', auth = '', preview = '' }) { + initialize: function({ + gtmId, + events = {}, + dataLayer, + dataLayerName = "dataLayer", + auth = "", + preview = "", + scriptProps = {}, + noscriptProps = {} + }) { const gtm = this.gtm({ id: gtmId, events: events, @@ -37,17 +56,23 @@ const TagManager = { dataLayerName: dataLayerName, auth, preview - }) - if (dataLayer) document.head.appendChild(gtm.dataScript) - document.head.insertBefore(gtm.script(), document.head.childNodes[0]) - document.body.insertBefore(gtm.noScript(), document.body.childNodes[0]) + }); + if (dataLayer) document.head.appendChild(gtm.dataScript); + document.head.insertBefore( + gtm.script(scriptProps), + document.head.childNodes[0] + ); + document.body.insertBefore( + gtm.noScript(noscriptProps), + document.body.childNodes[0] + ); }, - dataLayer: function ({dataLayer, dataLayerName = 'dataLayer'}) { - if (window[dataLayerName]) return window[dataLayerName].push(dataLayer) - const snippets = Snippets.dataLayer(dataLayer, dataLayerName) - const dataScript = this.dataScript(snippets) - document.head.appendChild(dataScript) + dataLayer: function({ dataLayer, dataLayerName = "dataLayer" }) { + if (window[dataLayerName]) return window[dataLayerName].push(dataLayer); + const snippets = Snippets.dataLayer(dataLayer, dataLayerName); + const dataScript = this.dataScript(snippets); + document.head.appendChild(dataScript); } -} +}; -module.exports = TagManager +module.exports = TagManager; diff --git a/src/__tests__/TagManager.spec.js b/src/__tests__/TagManager.spec.js index 6c90b571..8ad0b02f 100644 --- a/src/__tests__/TagManager.spec.js +++ b/src/__tests__/TagManager.spec.js @@ -1,20 +1,35 @@ -import React from 'react' -import TagManager from '../TagManager' +import React from "react"; +import TagManager from "../TagManager"; -describe('TagManager', () => { - it('should render tagmanager', () => { - TagManager.initialize({gtmId: 'GTM-000000'}) - expect(window.dataLayer).toHaveLength(1) - }) +describe("TagManager", () => { + it("should render tagmanager", () => { + TagManager.initialize({ gtmId: "GTM-000000" }); + expect(window.dataLayer).toHaveLength(1); + }); - it('should render datalayer', () => { + it("should render datalayer", () => { const gtmArgs = { - gtmId: 'GTM-000000', + gtmId: "GTM-000000", dataLayer: { - userInfo: 'userInfo' + userInfo: "userInfo" } - } - TagManager.initialize(gtmArgs) - expect(window.dataLayer).toHaveLength(1) - }) -}) \ No newline at end of file + }; + TagManager.initialize(gtmArgs); + expect(window.dataLayer).toHaveLength(1); + }); + + it("should render script and noscript props when provided", () => { + TagManager.initialize({ + gtmId: "GTM-000000", + scriptProps: { "data-foo": "bar" }, + noscriptProps: { "data-foo": "baz" } + }); + expect(window.dataLayer).toHaveLength(1); + expect( + window.document.querySelector('script[data-foo="bar"]') + ).toBeDefined(); + expect( + window.document.querySelector('noscript[data-foo="baz"]') + ).toBeDefined(); + }); +});