@azerion/bunosaurus-plugin-google-gtag 0.0.0-stage → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/lib/gtag.d.ts +9 -0
- package/lib/gtag.js +27 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.js +78 -0
- package/lib/options.d.ts +12 -0
- package/lib/options.js +33 -0
- package/lib/vendor-gtag.d.ts +133 -0
- package/lib/vendor-gtag.js +7 -0
- package/package.json +36 -4
- package/src/gtag.ts +37 -0
- package/src/index.ts +103 -0
- package/src/options.ts +61 -0
- package/src/types.d.ts +8 -0
- package/src/vendor-gtag.ts +196 -0
package/README.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@docusaurus/plugin-google-gtag`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Global Site Tag (gtag.js) plugin for Docusaurus.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
See [plugin-google-gtag documentation](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-google-gtag).
|
package/lib/gtag.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { ClientModule } from '@docusaurus/types';
|
|
8
|
+
declare const clientModule: ClientModule;
|
|
9
|
+
export default clientModule;
|
package/lib/gtag.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
const clientModule = {
|
|
8
|
+
onRouteDidUpdate({ location, previousLocation }) {
|
|
9
|
+
if (previousLocation &&
|
|
10
|
+
(location.pathname !== previousLocation.pathname ||
|
|
11
|
+
location.search !== previousLocation.search ||
|
|
12
|
+
location.hash !== previousLocation.hash)) {
|
|
13
|
+
// Normally, the document title is updated in the next tick due to how
|
|
14
|
+
// `react-helmet-async` updates it. We want to send the current document's
|
|
15
|
+
// title to gtag instead of the old one's, so we use `setTimeout` to defer
|
|
16
|
+
// execution to the next tick.
|
|
17
|
+
// See: https://github.com/facebook/docusaurus/issues/7420
|
|
18
|
+
setTimeout(() => {
|
|
19
|
+
// Always refer to the variable on window in case it gets overridden
|
|
20
|
+
// elsewhere.
|
|
21
|
+
window.gtag('set', 'page_path', location.pathname + location.search + location.hash);
|
|
22
|
+
window.gtag('event', 'page_view');
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
export default clientModule;
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { LoadContext, Plugin } from '@docusaurus/types';
|
|
8
|
+
import type { PluginOptions, Options } from './options';
|
|
9
|
+
export {} from './vendor-gtag';
|
|
10
|
+
export default function pluginGoogleGtag(context: LoadContext, options: PluginOptions): Plugin | null;
|
|
11
|
+
export { validateThemeConfig, validateOptions } from './options';
|
|
12
|
+
export type { PluginOptions, Options };
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.validateOptions = exports.validateThemeConfig = void 0;
|
|
10
|
+
exports.default = pluginGoogleGtag;
|
|
11
|
+
function createConfigSnippet({ trackingID, anonymizeIP, }) {
|
|
12
|
+
return `gtag('config', '${trackingID}', { ${anonymizeIP ? "'anonymize_ip': true" : ''} });`;
|
|
13
|
+
}
|
|
14
|
+
function createConfigSnippets({ trackingID: trackingIDArray, anonymizeIP, }) {
|
|
15
|
+
return trackingIDArray
|
|
16
|
+
.map((trackingID) => createConfigSnippet({ trackingID, anonymizeIP }))
|
|
17
|
+
.join('\n');
|
|
18
|
+
}
|
|
19
|
+
function pluginGoogleGtag(context, options) {
|
|
20
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const firstTrackingId = options.trackingID[0];
|
|
24
|
+
return {
|
|
25
|
+
name: 'docusaurus-plugin-google-gtag',
|
|
26
|
+
contentLoaded({ actions }) {
|
|
27
|
+
actions.setGlobalData(options);
|
|
28
|
+
},
|
|
29
|
+
getClientModules() {
|
|
30
|
+
return ['./gtag'];
|
|
31
|
+
},
|
|
32
|
+
injectHtmlTags() {
|
|
33
|
+
return {
|
|
34
|
+
// Gtag includes GA by default, so we also preconnect to
|
|
35
|
+
// google-analytics.
|
|
36
|
+
headTags: [
|
|
37
|
+
{
|
|
38
|
+
tagName: 'link',
|
|
39
|
+
attributes: {
|
|
40
|
+
rel: 'preconnect',
|
|
41
|
+
href: 'https://www.google-analytics.com',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
tagName: 'link',
|
|
46
|
+
attributes: {
|
|
47
|
+
rel: 'preconnect',
|
|
48
|
+
href: 'https://www.googletagmanager.com',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
tagName: 'script',
|
|
53
|
+
attributes: {
|
|
54
|
+
async: true,
|
|
55
|
+
// We only include the first tracking id here because google says
|
|
56
|
+
// we shouldn't install multiple tags/scripts on the same page
|
|
57
|
+
// Instead we should load one script and use n * gtag("config",id)
|
|
58
|
+
// See https://developers.google.com/tag-platform/gtagjs/install#add-products
|
|
59
|
+
src: `https://www.googletagmanager.com/gtag/js?id=${firstTrackingId}`,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
tagName: 'script',
|
|
64
|
+
innerHTML: `
|
|
65
|
+
window.dataLayer = window.dataLayer || [];
|
|
66
|
+
function gtag(){dataLayer.push(arguments);}
|
|
67
|
+
gtag('js', new Date());
|
|
68
|
+
${createConfigSnippets(options)};
|
|
69
|
+
`,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
var options_1 = require("./options");
|
|
77
|
+
Object.defineProperty(exports, "validateThemeConfig", { enumerable: true, get: function () { return options_1.validateThemeConfig; } });
|
|
78
|
+
Object.defineProperty(exports, "validateOptions", { enumerable: true, get: function () { return options_1.validateOptions; } });
|
package/lib/options.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OptionValidationContext, ThemeConfig, ThemeConfigValidationContext } from '@docusaurus/types';
|
|
2
|
+
export type PluginOptions = {
|
|
3
|
+
trackingID: [string, ...string[]];
|
|
4
|
+
anonymizeIP: boolean;
|
|
5
|
+
};
|
|
6
|
+
export type Options = {
|
|
7
|
+
trackingID: string | [string, ...string[]];
|
|
8
|
+
anonymizeIP?: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare const DEFAULT_OPTIONS: Partial<PluginOptions>;
|
|
11
|
+
export declare function validateOptions({ validate, options, }: OptionValidationContext<Options, PluginOptions>): PluginOptions;
|
|
12
|
+
export declare function validateThemeConfig({ themeConfig, }: ThemeConfigValidationContext<ThemeConfig>): ThemeConfig;
|
package/lib/options.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_OPTIONS = void 0;
|
|
4
|
+
exports.validateOptions = validateOptions;
|
|
5
|
+
exports.validateThemeConfig = validateThemeConfig;
|
|
6
|
+
/**
|
|
7
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
8
|
+
*
|
|
9
|
+
* This source code is licensed under the MIT license found in the
|
|
10
|
+
* LICENSE file in the root directory of this source tree.
|
|
11
|
+
*/
|
|
12
|
+
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
13
|
+
exports.DEFAULT_OPTIONS = {
|
|
14
|
+
anonymizeIP: false,
|
|
15
|
+
};
|
|
16
|
+
const pluginOptionsSchema = utils_validation_1.Joi.object({
|
|
17
|
+
// We normalize trackingID as a string[]
|
|
18
|
+
trackingID: utils_validation_1.Joi.alternatives()
|
|
19
|
+
.try(utils_validation_1.Joi.alternatives().conditional(utils_validation_1.Joi.string().required(), {
|
|
20
|
+
then: utils_validation_1.Joi.custom((val) => [val]),
|
|
21
|
+
}), utils_validation_1.Joi.array().items(utils_validation_1.Joi.string().required()))
|
|
22
|
+
.required(),
|
|
23
|
+
anonymizeIP: utils_validation_1.Joi.boolean().default(exports.DEFAULT_OPTIONS.anonymizeIP),
|
|
24
|
+
});
|
|
25
|
+
function validateOptions({ validate, options, }) {
|
|
26
|
+
return validate(pluginOptionsSchema, options);
|
|
27
|
+
}
|
|
28
|
+
function validateThemeConfig({ themeConfig, }) {
|
|
29
|
+
if ('gtag' in themeConfig) {
|
|
30
|
+
throw new Error('The "gtag" field in themeConfig should now be specified as option for plugin-google-gtag. More information at https://github.com/facebook/docusaurus/pull/5832.');
|
|
31
|
+
}
|
|
32
|
+
return themeConfig;
|
|
33
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
declare var gtag: Gtag.Gtag;
|
|
8
|
+
declare namespace Gtag {
|
|
9
|
+
interface GtagCommands {
|
|
10
|
+
config: [
|
|
11
|
+
targetId: string,
|
|
12
|
+
config?: ControlParams | EventParams | ConfigParams | CustomParams
|
|
13
|
+
];
|
|
14
|
+
set: [targetId: string, config: CustomParams | boolean | string] | [config: CustomParams];
|
|
15
|
+
js: [config: Date];
|
|
16
|
+
event: [
|
|
17
|
+
eventName: EventNames | (string & {}),
|
|
18
|
+
eventParams?: ControlParams | EventParams | CustomParams
|
|
19
|
+
];
|
|
20
|
+
get: [
|
|
21
|
+
targetId: string,
|
|
22
|
+
fieldName: FieldNames | string,
|
|
23
|
+
callback?: (field: string | CustomParams | undefined) => any
|
|
24
|
+
];
|
|
25
|
+
consent: [
|
|
26
|
+
consentArg: ConsentArg | (string & {}),
|
|
27
|
+
consentParams: ConsentParams
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
interface Gtag {
|
|
31
|
+
<Command extends keyof GtagCommands>(command: Command, ...args: GtagCommands[Command]): void;
|
|
32
|
+
}
|
|
33
|
+
interface ConfigParams {
|
|
34
|
+
page_title?: string | undefined;
|
|
35
|
+
page_location?: string | undefined;
|
|
36
|
+
page_path?: string | undefined;
|
|
37
|
+
send_page_view?: boolean | undefined;
|
|
38
|
+
}
|
|
39
|
+
interface CustomParams {
|
|
40
|
+
[key: string]: any;
|
|
41
|
+
}
|
|
42
|
+
interface ControlParams {
|
|
43
|
+
groups?: string | string[] | undefined;
|
|
44
|
+
send_to?: string | string[] | undefined;
|
|
45
|
+
event_callback?: (() => void) | undefined;
|
|
46
|
+
event_timeout?: number | undefined;
|
|
47
|
+
}
|
|
48
|
+
type EventNames = 'add_payment_info' | 'add_shipping_info' | 'add_to_cart' | 'add_to_wishlist' | 'begin_checkout' | 'checkout_progress' | 'earn_virtual_currency' | 'exception' | 'generate_lead' | 'join_group' | 'level_end' | 'level_start' | 'level_up' | 'login' | 'page_view' | 'post_score' | 'purchase' | 'refund' | 'remove_from_cart' | 'screen_view' | 'search' | 'select_content' | 'select_item' | 'select_promotion' | 'set_checkout_option' | 'share' | 'sign_up' | 'spend_virtual_currency' | 'tutorial_begin' | 'tutorial_complete' | 'unlock_achievement' | 'timing_complete' | 'view_cart' | 'view_item' | 'view_item_list' | 'view_promotion' | 'view_search_results';
|
|
49
|
+
interface EventParams {
|
|
50
|
+
checkout_option?: string | undefined;
|
|
51
|
+
checkout_step?: number | undefined;
|
|
52
|
+
content_id?: string | undefined;
|
|
53
|
+
content_type?: string | undefined;
|
|
54
|
+
coupon?: string | undefined;
|
|
55
|
+
currency?: string | undefined;
|
|
56
|
+
description?: string | undefined;
|
|
57
|
+
fatal?: boolean | undefined;
|
|
58
|
+
items?: Item[] | undefined;
|
|
59
|
+
method?: string | undefined;
|
|
60
|
+
number?: string | undefined;
|
|
61
|
+
promotions?: Promotion[] | undefined;
|
|
62
|
+
screen_name?: string | undefined;
|
|
63
|
+
search_term?: string | undefined;
|
|
64
|
+
shipping?: Currency | undefined;
|
|
65
|
+
tax?: Currency | undefined;
|
|
66
|
+
transaction_id?: string | undefined;
|
|
67
|
+
value?: number | undefined;
|
|
68
|
+
event_label?: string | undefined;
|
|
69
|
+
event_category?: string | undefined;
|
|
70
|
+
/** @see {@link https://developers.google.com/analytics/devguides/collection/gtagjs/sending-data#specify_different_transport_mechanisms specify_different_transport_mechanisms} */
|
|
71
|
+
transport_type?: 'image' | 'xhr' | 'beacon' | undefined;
|
|
72
|
+
}
|
|
73
|
+
type Currency = string | number;
|
|
74
|
+
/**
|
|
75
|
+
* Interface of an item object used in lists for this event.
|
|
76
|
+
*
|
|
77
|
+
* Reference:
|
|
78
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#view_item_item view_item_item}
|
|
79
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#view_item_list_item view_item_list_item}
|
|
80
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#select_item_item select_item_item}
|
|
81
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#add_to_cart_item add_to_cart_item}
|
|
82
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#view_cart_item view_cart_item}
|
|
83
|
+
*/
|
|
84
|
+
interface Item {
|
|
85
|
+
item_id?: string | undefined;
|
|
86
|
+
item_name?: string | undefined;
|
|
87
|
+
affiliation?: string | undefined;
|
|
88
|
+
coupon?: string | undefined;
|
|
89
|
+
currency?: string | undefined;
|
|
90
|
+
creative_name?: string | undefined;
|
|
91
|
+
creative_slot?: string | undefined;
|
|
92
|
+
discount?: Currency | undefined;
|
|
93
|
+
index?: number | undefined;
|
|
94
|
+
item_brand?: string | undefined;
|
|
95
|
+
item_category?: string | undefined;
|
|
96
|
+
item_category2?: string | undefined;
|
|
97
|
+
item_category3?: string | undefined;
|
|
98
|
+
item_category4?: string | undefined;
|
|
99
|
+
item_category5?: string | undefined;
|
|
100
|
+
item_list_id?: string | undefined;
|
|
101
|
+
item_list_name?: string | undefined;
|
|
102
|
+
item_variant?: string | undefined;
|
|
103
|
+
location_id?: string | undefined;
|
|
104
|
+
price?: Currency | undefined;
|
|
105
|
+
promotion_id?: string | undefined;
|
|
106
|
+
promotion_name?: string | undefined;
|
|
107
|
+
quantity?: number | undefined;
|
|
108
|
+
}
|
|
109
|
+
interface Promotion {
|
|
110
|
+
creative_name?: string | undefined;
|
|
111
|
+
creative_slot?: string | undefined;
|
|
112
|
+
promotion_id?: string | undefined;
|
|
113
|
+
promotion_name?: string | undefined;
|
|
114
|
+
}
|
|
115
|
+
type FieldNames = 'client_id' | 'session_id' | 'gclid';
|
|
116
|
+
type ConsentArg = 'default' | 'update';
|
|
117
|
+
/**
|
|
118
|
+
* Reference:
|
|
119
|
+
* @see {@link https://support.google.com/tagmanager/answer/10718549#consent-types consent-types}
|
|
120
|
+
* @see {@link https://developers.google.com/tag-platform/devguides/consent consent}
|
|
121
|
+
*/
|
|
122
|
+
interface ConsentParams {
|
|
123
|
+
ad_personalization?: 'granted' | 'denied' | undefined;
|
|
124
|
+
ad_user_data?: 'granted' | 'denied' | undefined;
|
|
125
|
+
ad_storage?: 'granted' | 'denied' | undefined;
|
|
126
|
+
analytics_storage?: 'granted' | 'denied' | undefined;
|
|
127
|
+
functionality_storage?: 'granted' | 'denied' | undefined;
|
|
128
|
+
personalization_storage?: 'granted' | 'denied' | undefined;
|
|
129
|
+
security_storage?: 'granted' | 'denied' | undefined;
|
|
130
|
+
wait_for_update?: number | undefined;
|
|
131
|
+
region?: string[] | undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@azerion/bunosaurus-plugin-google-gtag",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Global Site Tag (gtag.js) plugin for Docusaurus.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc --build && copy-untyped-files",
|
|
9
|
+
"watch": "run-p -c copy:watch build:watch",
|
|
10
|
+
"build:watch": "tsc --build --watch",
|
|
11
|
+
"copy:watch": "copy-untyped-files --watch"
|
|
12
|
+
},
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/azerion/bunosaurus.git",
|
|
19
|
+
"directory": "packages/docusaurus-plugin-google-gtag"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@docusaurus/core": "npm:@azerion/bunosaurus-core@4.0.0",
|
|
24
|
+
"@docusaurus/types": "npm:@azerion/bunosaurus-types@4.0.0",
|
|
25
|
+
"@docusaurus/utils-validation": "npm:@azerion/bunosaurus-utils-validation@4.0.0",
|
|
26
|
+
"tslib": "^2.8.1"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@docusaurus/module-type-aliases": "npm:@azerion/bunosaurus-module-type-aliases@4.0.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"react": "^19.3.0",
|
|
33
|
+
"react-dom": "^19.3.0"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"bun": ">=1.4.1"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/gtag.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {ClientModule} from '@docusaurus/types';
|
|
9
|
+
|
|
10
|
+
const clientModule: ClientModule = {
|
|
11
|
+
onRouteDidUpdate({location, previousLocation}) {
|
|
12
|
+
if (
|
|
13
|
+
previousLocation &&
|
|
14
|
+
(location.pathname !== previousLocation.pathname ||
|
|
15
|
+
location.search !== previousLocation.search ||
|
|
16
|
+
location.hash !== previousLocation.hash)
|
|
17
|
+
) {
|
|
18
|
+
// Normally, the document title is updated in the next tick due to how
|
|
19
|
+
// `react-helmet-async` updates it. We want to send the current document's
|
|
20
|
+
// title to gtag instead of the old one's, so we use `setTimeout` to defer
|
|
21
|
+
// execution to the next tick.
|
|
22
|
+
// See: https://github.com/facebook/docusaurus/issues/7420
|
|
23
|
+
setTimeout(() => {
|
|
24
|
+
// Always refer to the variable on window in case it gets overridden
|
|
25
|
+
// elsewhere.
|
|
26
|
+
window.gtag(
|
|
27
|
+
'set',
|
|
28
|
+
'page_path',
|
|
29
|
+
location.pathname + location.search + location.hash,
|
|
30
|
+
);
|
|
31
|
+
window.gtag('event', 'page_view');
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default clientModule;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {LoadContext, Plugin} from '@docusaurus/types';
|
|
9
|
+
import type {PluginOptions, Options} from './options';
|
|
10
|
+
|
|
11
|
+
// Not sure why it's needed to expose vendored types 🤷️
|
|
12
|
+
export {} from './vendor-gtag';
|
|
13
|
+
|
|
14
|
+
function createConfigSnippet({
|
|
15
|
+
trackingID,
|
|
16
|
+
anonymizeIP,
|
|
17
|
+
}: {
|
|
18
|
+
trackingID: string;
|
|
19
|
+
anonymizeIP: boolean;
|
|
20
|
+
}): string {
|
|
21
|
+
return `gtag('config', '${trackingID}', { ${
|
|
22
|
+
anonymizeIP ? "'anonymize_ip': true" : ''
|
|
23
|
+
} });`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function createConfigSnippets({
|
|
27
|
+
trackingID: trackingIDArray,
|
|
28
|
+
anonymizeIP,
|
|
29
|
+
}: PluginOptions): string {
|
|
30
|
+
return trackingIDArray
|
|
31
|
+
.map((trackingID) => createConfigSnippet({trackingID, anonymizeIP}))
|
|
32
|
+
.join('\n');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default function pluginGoogleGtag(
|
|
36
|
+
context: LoadContext,
|
|
37
|
+
options: PluginOptions,
|
|
38
|
+
): Plugin | null {
|
|
39
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const firstTrackingId = options.trackingID[0];
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
name: 'docusaurus-plugin-google-gtag',
|
|
47
|
+
|
|
48
|
+
contentLoaded({actions}) {
|
|
49
|
+
actions.setGlobalData(options);
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
getClientModules() {
|
|
53
|
+
return ['./gtag'];
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
injectHtmlTags() {
|
|
57
|
+
return {
|
|
58
|
+
// Gtag includes GA by default, so we also preconnect to
|
|
59
|
+
// google-analytics.
|
|
60
|
+
headTags: [
|
|
61
|
+
{
|
|
62
|
+
tagName: 'link',
|
|
63
|
+
attributes: {
|
|
64
|
+
rel: 'preconnect',
|
|
65
|
+
href: 'https://www.google-analytics.com',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
tagName: 'link',
|
|
70
|
+
attributes: {
|
|
71
|
+
rel: 'preconnect',
|
|
72
|
+
href: 'https://www.googletagmanager.com',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
tagName: 'script',
|
|
77
|
+
attributes: {
|
|
78
|
+
async: true,
|
|
79
|
+
// We only include the first tracking id here because google says
|
|
80
|
+
// we shouldn't install multiple tags/scripts on the same page
|
|
81
|
+
// Instead we should load one script and use n * gtag("config",id)
|
|
82
|
+
// See https://developers.google.com/tag-platform/gtagjs/install#add-products
|
|
83
|
+
src: `https://www.googletagmanager.com/gtag/js?id=${firstTrackingId}`,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
tagName: 'script',
|
|
88
|
+
innerHTML: `
|
|
89
|
+
window.dataLayer = window.dataLayer || [];
|
|
90
|
+
function gtag(){dataLayer.push(arguments);}
|
|
91
|
+
gtag('js', new Date());
|
|
92
|
+
${createConfigSnippets(options)};
|
|
93
|
+
`,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export {validateThemeConfig, validateOptions} from './options';
|
|
102
|
+
|
|
103
|
+
export type {PluginOptions, Options};
|
package/src/options.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import {Joi} from '@docusaurus/utils-validation';
|
|
8
|
+
import type {
|
|
9
|
+
OptionValidationContext,
|
|
10
|
+
ThemeConfig,
|
|
11
|
+
ThemeConfigValidationContext,
|
|
12
|
+
} from '@docusaurus/types';
|
|
13
|
+
|
|
14
|
+
export type PluginOptions = {
|
|
15
|
+
trackingID: [string, ...string[]];
|
|
16
|
+
// TODO deprecate anonymizeIP after June 2023
|
|
17
|
+
// "In Google Analytics 4, IP masking is not necessary
|
|
18
|
+
// since IP addresses are not logged or stored."
|
|
19
|
+
// https://support.google.com/analytics/answer/2763052?hl=en
|
|
20
|
+
anonymizeIP: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type Options = {
|
|
24
|
+
trackingID: string | [string, ...string[]];
|
|
25
|
+
anonymizeIP?: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const DEFAULT_OPTIONS: Partial<PluginOptions> = {
|
|
29
|
+
anonymizeIP: false,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const pluginOptionsSchema = Joi.object<PluginOptions>({
|
|
33
|
+
// We normalize trackingID as a string[]
|
|
34
|
+
trackingID: Joi.alternatives()
|
|
35
|
+
.try(
|
|
36
|
+
Joi.alternatives().conditional(Joi.string().required(), {
|
|
37
|
+
then: Joi.custom((val: boolean) => [val]),
|
|
38
|
+
}),
|
|
39
|
+
Joi.array().items(Joi.string().required()),
|
|
40
|
+
)
|
|
41
|
+
.required(),
|
|
42
|
+
anonymizeIP: Joi.boolean().default(DEFAULT_OPTIONS.anonymizeIP),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export function validateOptions({
|
|
46
|
+
validate,
|
|
47
|
+
options,
|
|
48
|
+
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
|
|
49
|
+
return validate(pluginOptionsSchema, options);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function validateThemeConfig({
|
|
53
|
+
themeConfig,
|
|
54
|
+
}: ThemeConfigValidationContext<ThemeConfig>): ThemeConfig {
|
|
55
|
+
if ('gtag' in themeConfig) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
'The "gtag" field in themeConfig should now be specified as option for plugin-google-gtag. More information at https://github.com/facebook/docusaurus/pull/5832.',
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return themeConfig;
|
|
61
|
+
}
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Types directly copied from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/gtag.js
|
|
9
|
+
// I'd prefer not do that, but this should fix our StackBlitz playground
|
|
10
|
+
// See https://github.com/facebook/docusaurus/pull/12080
|
|
11
|
+
// See https://github.com/facebook/docusaurus/issues/11615
|
|
12
|
+
|
|
13
|
+
/* eslint-disable */
|
|
14
|
+
declare var gtag: Gtag.Gtag;
|
|
15
|
+
declare namespace Gtag {
|
|
16
|
+
interface GtagCommands {
|
|
17
|
+
config: [
|
|
18
|
+
targetId: string,
|
|
19
|
+
config?: ControlParams | EventParams | ConfigParams | CustomParams,
|
|
20
|
+
];
|
|
21
|
+
// eslint-disable-next-line @definitelytyped/no-single-element-tuple-type
|
|
22
|
+
set:
|
|
23
|
+
| [targetId: string, config: CustomParams | boolean | string]
|
|
24
|
+
| [config: CustomParams];
|
|
25
|
+
// eslint-disable-next-line @definitelytyped/no-single-element-tuple-type
|
|
26
|
+
js: [config: Date];
|
|
27
|
+
event: [
|
|
28
|
+
eventName: EventNames | (string & {}),
|
|
29
|
+
eventParams?: ControlParams | EventParams | CustomParams,
|
|
30
|
+
];
|
|
31
|
+
get: [
|
|
32
|
+
targetId: string,
|
|
33
|
+
fieldName: FieldNames | string,
|
|
34
|
+
callback?: (field: string | CustomParams | undefined) => any,
|
|
35
|
+
];
|
|
36
|
+
consent: [
|
|
37
|
+
consentArg: ConsentArg | (string & {}),
|
|
38
|
+
consentParams: ConsentParams,
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface Gtag {
|
|
43
|
+
<Command extends keyof GtagCommands>(
|
|
44
|
+
command: Command,
|
|
45
|
+
...args: GtagCommands[Command]
|
|
46
|
+
): void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface ConfigParams {
|
|
50
|
+
page_title?: string | undefined;
|
|
51
|
+
page_location?: string | undefined;
|
|
52
|
+
page_path?: string | undefined;
|
|
53
|
+
send_page_view?: boolean | undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface CustomParams {
|
|
57
|
+
[key: string]: any;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface ControlParams {
|
|
61
|
+
groups?: string | string[] | undefined;
|
|
62
|
+
send_to?: string | string[] | undefined;
|
|
63
|
+
event_callback?: (() => void) | undefined;
|
|
64
|
+
event_timeout?: number | undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type EventNames =
|
|
68
|
+
| 'add_payment_info'
|
|
69
|
+
| 'add_shipping_info'
|
|
70
|
+
| 'add_to_cart'
|
|
71
|
+
| 'add_to_wishlist'
|
|
72
|
+
| 'begin_checkout'
|
|
73
|
+
| 'checkout_progress'
|
|
74
|
+
| 'earn_virtual_currency'
|
|
75
|
+
| 'exception'
|
|
76
|
+
| 'generate_lead'
|
|
77
|
+
| 'join_group'
|
|
78
|
+
| 'level_end'
|
|
79
|
+
| 'level_start'
|
|
80
|
+
| 'level_up'
|
|
81
|
+
| 'login'
|
|
82
|
+
| 'page_view'
|
|
83
|
+
| 'post_score'
|
|
84
|
+
| 'purchase'
|
|
85
|
+
| 'refund'
|
|
86
|
+
| 'remove_from_cart'
|
|
87
|
+
| 'screen_view'
|
|
88
|
+
| 'search'
|
|
89
|
+
| 'select_content'
|
|
90
|
+
| 'select_item'
|
|
91
|
+
| 'select_promotion'
|
|
92
|
+
| 'set_checkout_option'
|
|
93
|
+
| 'share'
|
|
94
|
+
| 'sign_up'
|
|
95
|
+
| 'spend_virtual_currency'
|
|
96
|
+
| 'tutorial_begin'
|
|
97
|
+
| 'tutorial_complete'
|
|
98
|
+
| 'unlock_achievement'
|
|
99
|
+
| 'timing_complete'
|
|
100
|
+
| 'view_cart'
|
|
101
|
+
| 'view_item'
|
|
102
|
+
| 'view_item_list'
|
|
103
|
+
| 'view_promotion'
|
|
104
|
+
| 'view_search_results';
|
|
105
|
+
|
|
106
|
+
interface EventParams {
|
|
107
|
+
checkout_option?: string | undefined;
|
|
108
|
+
checkout_step?: number | undefined;
|
|
109
|
+
content_id?: string | undefined;
|
|
110
|
+
content_type?: string | undefined;
|
|
111
|
+
coupon?: string | undefined;
|
|
112
|
+
currency?: string | undefined;
|
|
113
|
+
description?: string | undefined;
|
|
114
|
+
fatal?: boolean | undefined;
|
|
115
|
+
items?: Item[] | undefined;
|
|
116
|
+
method?: string | undefined;
|
|
117
|
+
number?: string | undefined;
|
|
118
|
+
promotions?: Promotion[] | undefined;
|
|
119
|
+
screen_name?: string | undefined;
|
|
120
|
+
search_term?: string | undefined;
|
|
121
|
+
shipping?: Currency | undefined;
|
|
122
|
+
tax?: Currency | undefined;
|
|
123
|
+
transaction_id?: string | undefined;
|
|
124
|
+
value?: number | undefined;
|
|
125
|
+
event_label?: string | undefined;
|
|
126
|
+
event_category?: string | undefined;
|
|
127
|
+
/** @see {@link https://developers.google.com/analytics/devguides/collection/gtagjs/sending-data#specify_different_transport_mechanisms specify_different_transport_mechanisms} */
|
|
128
|
+
transport_type?: 'image' | 'xhr' | 'beacon' | undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
type Currency = string | number;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Interface of an item object used in lists for this event.
|
|
135
|
+
*
|
|
136
|
+
* Reference:
|
|
137
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#view_item_item view_item_item}
|
|
138
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#view_item_list_item view_item_list_item}
|
|
139
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#select_item_item select_item_item}
|
|
140
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#add_to_cart_item add_to_cart_item}
|
|
141
|
+
* @see {@link https://developers.google.com/analytics/devguides/collection/ga4/reference/events#view_cart_item view_cart_item}
|
|
142
|
+
*/
|
|
143
|
+
interface Item {
|
|
144
|
+
item_id?: string | undefined;
|
|
145
|
+
item_name?: string | undefined;
|
|
146
|
+
affiliation?: string | undefined;
|
|
147
|
+
coupon?: string | undefined;
|
|
148
|
+
currency?: string | undefined;
|
|
149
|
+
creative_name?: string | undefined;
|
|
150
|
+
creative_slot?: string | undefined;
|
|
151
|
+
discount?: Currency | undefined;
|
|
152
|
+
index?: number | undefined;
|
|
153
|
+
item_brand?: string | undefined;
|
|
154
|
+
item_category?: string | undefined;
|
|
155
|
+
item_category2?: string | undefined;
|
|
156
|
+
item_category3?: string | undefined;
|
|
157
|
+
item_category4?: string | undefined;
|
|
158
|
+
item_category5?: string | undefined;
|
|
159
|
+
item_list_id?: string | undefined;
|
|
160
|
+
item_list_name?: string | undefined;
|
|
161
|
+
item_variant?: string | undefined;
|
|
162
|
+
location_id?: string | undefined;
|
|
163
|
+
price?: Currency | undefined;
|
|
164
|
+
promotion_id?: string | undefined;
|
|
165
|
+
promotion_name?: string | undefined;
|
|
166
|
+
quantity?: number | undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
interface Promotion {
|
|
170
|
+
creative_name?: string | undefined;
|
|
171
|
+
creative_slot?: string | undefined;
|
|
172
|
+
promotion_id?: string | undefined;
|
|
173
|
+
promotion_name?: string | undefined;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
type FieldNames = 'client_id' | 'session_id' | 'gclid';
|
|
177
|
+
|
|
178
|
+
type ConsentArg = 'default' | 'update';
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Reference:
|
|
182
|
+
* @see {@link https://support.google.com/tagmanager/answer/10718549#consent-types consent-types}
|
|
183
|
+
* @see {@link https://developers.google.com/tag-platform/devguides/consent consent}
|
|
184
|
+
*/
|
|
185
|
+
interface ConsentParams {
|
|
186
|
+
ad_personalization?: 'granted' | 'denied' | undefined;
|
|
187
|
+
ad_user_data?: 'granted' | 'denied' | undefined;
|
|
188
|
+
ad_storage?: 'granted' | 'denied' | undefined;
|
|
189
|
+
analytics_storage?: 'granted' | 'denied' | undefined;
|
|
190
|
+
functionality_storage?: 'granted' | 'denied' | undefined;
|
|
191
|
+
personalization_storage?: 'granted' | 'denied' | undefined;
|
|
192
|
+
security_storage?: 'granted' | 'denied' | undefined;
|
|
193
|
+
wait_for_update?: number | undefined;
|
|
194
|
+
region?: string[] | undefined;
|
|
195
|
+
}
|
|
196
|
+
}
|