frontend_tracking_options()   F
last analyzed

Complexity

Conditions 24
Paths 4098

Size

Total Lines 97
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 24
eloc 58
c 3
b 0
f 0
nc 4098
nop 1
dl 0
loc 97
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Tracking gtag.js class.
4
 *
5
 * @since 7.15.0
6
 *
7
 * @author  Mircea Sandu
8
 */
9
10
// Exit if accessed directly
11
if ( ! defined( 'ABSPATH' ) ) {
12
	exit;
13
}
14
15
class MonsterInsights_Tracking_Gtag extends MonsterInsights_Tracking_Abstract {
16
	/**
17
	 * Holds the name of the tracking type.
18
	 *
19
	 * @since 7.15.0
20
	 *
21
	 * @var string name of the tracking type
22
	 */
23
	public $name = 'gtag';
24
25
	/**
26
	 * Version of the tracking class.
27
	 *
28
	 * @since 7.15.0
29
	 *
30
	 * @var string version of the tracking class
31
	 */
32
	public $version = '1.0.0';
33
34
	/**
35
	 * Primary class constructor.
36
	 *
37
	 * @since 7.15.0
38
	 */
39
	public function __construct() {
40
	}
41
42
	/**
43
	 * Array of options that will be made persistent by setting them before the pageview.
44
	 *
45
	 * @see https://developers.google.com/analytics/devguides/collection/gtagjs/setting-values
46
	 *
47
	 * @return array options for persistent values, like custom dimensions
48
	 *
49
	 * @since 7.15.0
50
	 */
51
	public function frontend_tracking_options_persistent() {
52
		return apply_filters( 'monsterinsights_frontend_tracking_options_persistent_gtag_before_pageview', [] );
53
	}
54
55
	/**
56
	 * Get frontend tracking options for the gtag script.
57
	 *
58
	 * This function is used to return an array of parameters
59
	 * for the frontend_output() function to output. These are
60
	 * generally dimensions and turned on GA features.
61
	 *
62
	 * @param bool $encoded Whether to return a JavaScript object representation of the options
63
	 *
64
	 * @return array|string options for the gtag config
65
	 *
66
	 * @since 7.15.0
67
	 */
68
	public function frontend_tracking_options( $encoded = false ) {
69
		global $wp_query;
70
		$options = [];
71
72
		$tracking_id = monsterinsights_get_v4_id();
73
		if ( empty( $tracking_id ) ) {
74
			return $encoded ? wp_json_encode( $options ) : $options;
75
		}
76
77
		$placeholder = '';
78
79
		if ( $encoded ) {
80
			$placeholder = '!@#';
81
		}
82
83
		$cross_domains = monsterinsights_get_option( 'cross_domains', [] );
84
		$allow_anchor  = monsterinsights_get_option( 'allow_anchor', false );
85
86
		if ( $allow_anchor ) {
87
			$options['allow_anchor'] = 'true';
88
		}
89
90
		if ( class_exists( 'MonsterInsights_AMP' ) ) {
91
			$options['use_amp_client_id'] = 'true';
92
		}
93
94
		$options['forceSSL'] = 'true';
95
96
		// Anonymous data.
97
		if ( monsterinsights_get_option( 'anonymize_ips', false ) ) {
98
			$options['anonymize_ip'] = 'true';
99
		}
100
101
		$options = apply_filters( 'monsterinsights_frontend_tracking_options_gtag_before_scripts', $options );
102
103
		// Add Enhanced link attribution.
104
		if ( monsterinsights_get_option( 'link_attribution', false ) ) {
105
			$options['link_attribution'] = 'true';
106
		}
107
108
		// Add cross-domain tracking.
109
		if ( is_array( $cross_domains ) && ! empty( $cross_domains ) ) {
0 ignored issues
show
introduced by
The condition is_array($cross_domains) is always false.
Loading history...
110
			$linker_domains = [];
111
			foreach ( $cross_domains as $cross_domain ) {
112
				if ( ! empty( $cross_domain['domain'] ) ) {
113
					$linker_domains[] = $cross_domain['domain'];
114
				}
115
			}
116
			$options['linker'] = [
117
				'domains' => $linker_domains,
118
			];
119
		}
120
121
		if ( monsterinsights_is_debug_mode() ) {
122
			$options['debug_mode'] = true;
123
		}
124
125
		$options = apply_filters( 'monsterinsights_frontend_tracking_options_gtag_before_pageview', $options );
126
		$options = apply_filters( 'monsterinsights_frontend_tracking_options_before_pageview', $options, $this->name, $this->version );
127
128
		if ( is_404() ) {
129
			if ( monsterinsights_get_option( 'hash_tracking', false ) ) {
130
				$options['page_path'] = "{$placeholder}'/404.html?page=' + document.location.pathname + document.location.search + location.hash + '&from=' + document.referrer{$placeholder}";
131
			} else {
132
				$options['page_path'] = "{$placeholder}'/404.html?page=' + document.location.pathname + document.location.search + '&from=' + document.referrer{$placeholder}";
133
			}
134
		} elseif ( $wp_query->is_search ) {
135
			$pushstr = "/?s=";
136
			if ( 0 === (int) $wp_query->found_posts ) {
137
				$options['page_path'] = $pushstr . 'no-results:' . rawurlencode( $wp_query->query_vars['s'] ) . "&cat=no-results";
138
			} elseif ( 1 === (int) $wp_query->found_posts ) {
139
				$options['page_path'] = $pushstr . rawurlencode( $wp_query->query_vars['s'] ) . "&cat=1-result";
140
			} elseif ( $wp_query->found_posts > 1 && $wp_query->found_posts < 6 ) {
141
				$options['page_path'] = $pushstr . rawurlencode( $wp_query->query_vars['s'] ) . "&cat=2-5-results";
142
			} else {
143
				$options['page_path'] = $pushstr . rawurlencode( $wp_query->query_vars['s'] ) . "&cat=plus-5-results";
144
			}
145
		} elseif ( monsterinsights_get_option( 'hash_tracking', false ) ) {
146
			$options['page_path'] = "{$placeholder}location.pathname + location.search + location.hash{$placeholder}";
147
		}
148
149
		if ( monsterinsights_get_option( 'userid', false ) && is_user_logged_in() ) {
150
			$value                 = get_current_user_id();
151
			$options['wp_user_id'] = $value;
152
		}
153
154
		$options = apply_filters( 'monsterinsights_frontend_tracking_options_gtag_end', $options );
155
156
		if ( $encoded ) {
157
			return str_replace(
158
				[ '"' . $placeholder, $placeholder . '"' ],
159
				'',
160
				wp_json_encode( $options )
161
			);
162
		}
163
164
		return $options;
165
	}
166
167
	/**
168
	 * Get frontend output.
169
	 *
170
	 * This function is used to return the Javascript
171
	 * to output in the head of the page for the given
172
	 * tracking method.
173
	 *
174
	 * @return string javascript to output
175
	 *
176
	 * @since 7.15.0
177
	 */
178
	public function frontend_output() {
179
		$options_v4     = $this->frontend_tracking_options( true );
180
		$persistent     = $this->frontend_tracking_options_persistent();
181
		$v4_id          = monsterinsights_get_v4_id_to_output();
182
		$src            = apply_filters( 'monsterinsights_frontend_output_gtag_src', '//www.googletagmanager.com/gtag/js?id=' . $v4_id );
183
		$compat_mode    = apply_filters( 'monsterinsights_get_option_gtagtracker_compatibility_mode', true );
184
		$compat         = $compat_mode ? 'window.gtag = __gtagTracker;' : '';
185
		$track_user     = monsterinsights_track_user();
186
		$output         = '';
187
		$reason         = '';
188
		$attr_string    = monsterinsights_get_frontend_analytics_script_atts();
189
		$gtag_async     = apply_filters( 'monsterinsights_frontend_gtag_script_async', true ) ? 'async' : '';
190
		ob_start(); ?>
191
		<!-- This site uses the Google Analytics by MonsterInsights plugin v<?php echo MONSTERINSIGHTS_VERSION; // phpcs:ignore ?> - Using Analytics tracking - https://www.monsterinsights.com/ -->
192
		<?php if ( ! $track_user ) {
193
			if ( empty( $v4_id ) ) {
194
				$reason = __( 'Note: MonsterInsights is not currently configured on this site. The site owner needs to authenticate with Google Analytics in the MonsterInsights settings panel.', 'google-analytics-for-wordpress' );
195
				$output .= '<!-- ' . esc_html( $reason ) . ' -->' . PHP_EOL;
196
			} elseif ( current_user_can( 'monsterinsights_save_settings' ) ) {
197
				$reason = __( 'Note: MonsterInsights does not track you as a logged-in site administrator to prevent site owners from accidentally skewing their own Google Analytics data.' . PHP_EOL . 'If you are testing Google Analytics code, please do so either logged out or in the private browsing/incognito mode of your web browser.', 'google-analytics-for-wordpress' );
198
				$output .= '<!-- ' . esc_html( $reason ) . ' -->' . PHP_EOL;
199
			} else {
200
				$reason = __( 'Note: The site owner has disabled Google Analytics tracking for your user role.', 'google-analytics-for-wordpress' );
201
				$output .= '<!-- ' . esc_html( $reason ) . ' -->' . PHP_EOL;
202
			}
203
			echo $output; // phpcs:ignore
204
		} ?>
205
		<?php if ( ! empty( $v4_id ) ) {
206
			do_action( 'monsterinsights_tracking_gtag_frontend_before_script_tag' );
207
			?>
208
			<script src="<?php echo $src; // phpcs:ignore ?>" <?php echo $attr_string; // phpcs:ignore ?> <?php echo esc_attr( $gtag_async ); ?>></script>
209
			<script<?php echo $attr_string; // phpcs:ignore ?>>
210
				var mi_version = '<?php echo MONSTERINSIGHTS_VERSION; // phpcs:ignore ?>';
211
				var mi_track_user = <?php echo $track_user ? 'true' : 'false'; ?>;
212
				var mi_no_track_reason = <?php echo $reason ? "'" . esc_js( $reason ) . "'" : "''"; ?>;
213
				<?php do_action( 'monsterinsights_tracking_gtag_frontend_output_after_mi_track_user' ); ?>
214
				var MonsterInsightsDefaultLocations = <?php echo $this->get_default_locations(); ?>;
0 ignored issues
show
Bug introduced by
Are you sure $this->get_default_locations() of type false|string can be used in echo? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

214
				var MonsterInsightsDefaultLocations = <?php echo /** @scrutinizer ignore-type */ $this->get_default_locations(); ?>;
Loading history...
215
				if ( typeof MonsterInsightsPrivacyGuardFilter === 'function' ) {
216
					var MonsterInsightsLocations = (typeof MonsterInsightsExcludeQuery === 'object') ? MonsterInsightsPrivacyGuardFilter( MonsterInsightsExcludeQuery ) : MonsterInsightsPrivacyGuardFilter( MonsterInsightsDefaultLocations );
217
				} else {
218
					var MonsterInsightsLocations = (typeof MonsterInsightsExcludeQuery === 'object') ? MonsterInsightsExcludeQuery : MonsterInsightsDefaultLocations;
219
				}
220
221
				<?php if ($this->should_do_optout()) { ?>
222
				var disableStrs = [
223
					<?php if (! empty( $v4_id )) { ?>
224
					'ga-disable-<?php echo esc_js( $v4_id ); ?>',
225
					<?php } ?>
226
				];
227
228
				/* Function to detect opted out users */
229
				function __gtagTrackerIsOptedOut() {
230
					for (var index = 0; index < disableStrs.length; index++) {
231
						if (document.cookie.indexOf(disableStrs[index] + '=true') > -1) {
232
							return true;
233
						}
234
					}
235
236
					return false;
237
				}
238
239
				/* Disable tracking if the opt-out cookie exists. */
240
				if (__gtagTrackerIsOptedOut()) {
241
					for (var index = 0; index < disableStrs.length; index++) {
242
						window[disableStrs[index]] = true;
243
					}
244
				}
245
246
				/* Opt-out function */
247
				function __gtagTrackerOptout() {
248
					for (var index = 0; index < disableStrs.length; index++) {
249
						document.cookie = disableStrs[index] + '=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
250
						window[disableStrs[index]] = true;
251
					}
252
				}
253
254
				if ('undefined' === typeof gaOptout) {
255
					function gaOptout() {
256
						__gtagTrackerOptout();
257
					}
258
				}
259
				<?php } ?>
260
				window.dataLayer = window.dataLayer || [];
261
262
				window.MonsterInsightsDualTracker = {
263
					helpers: {},
264
					trackers: {},
265
				};
266
				if (mi_track_user) {
267
					function __gtagDataLayer() {
268
						dataLayer.push(arguments);
269
					}
270
271
					function __gtagTracker(type, name, parameters) {
272
						if (!parameters) {
273
							parameters = {};
274
						}
275
276
						if (parameters.send_to) {
277
							__gtagDataLayer.apply(null, arguments);
278
							return;
279
						}
280
281
						if (type === 'event') {
282
							<?php if ($v4_id) { ?>
283
							parameters.send_to = monsterinsights_frontend.v4_id;
284
							var hookName = name;
285
							if (typeof parameters['event_category'] !== 'undefined') {
286
								hookName = parameters['event_category'] + ':' + name;
287
							}
288
289
							if (typeof MonsterInsightsDualTracker.trackers[hookName] !== 'undefined') {
290
								MonsterInsightsDualTracker.trackers[hookName](parameters);
291
							} else {
292
								__gtagDataLayer('event', name, parameters);
293
							}
294
							<?php } ?>
295
296
						} else {
297
							__gtagDataLayer.apply(null, arguments);
298
						}
299
					}
300
301
					__gtagTracker('js', new Date());
302
					__gtagTracker('set', {
303
						'developer_id.dZGIzZG': true,
304
						<?php
305
						if ( ! empty( $persistent ) ) {
306
							foreach ( $persistent as $key => $value ) {
307
								echo "'" . esc_js( $key ) . "' : '" . esc_js( $value ) . "',";
308
							}
309
						}
310
						?>
311
					});
312
					if ( MonsterInsightsLocations.page_location ) {
313
						__gtagTracker('set', MonsterInsightsLocations);
314
					}
315
					<?php if (! empty( $v4_id )) { ?>
316
					__gtagTracker('config', '<?php echo esc_js( $v4_id ); ?>', <?php echo $options_v4; // phpcs:ignore ?> );
0 ignored issues
show
Bug introduced by
Are you sure $options_v4 of type array|string can be used in echo? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

316
					__gtagTracker('config', '<?php echo esc_js( $v4_id ); ?>', <?php echo /** @scrutinizer ignore-type */ $options_v4; // phpcs:ignore ?> );
Loading history...
317
					<?php } ?>
318
					<?php
319
					/*
320
					 * Extend or enhance the functionality by adding custom code to frontend
321
					 * tracking via this hook.
322
					 *
323
					 * @since 7.15.0
324
					 */
325
					do_action( 'monsterinsights_frontend_tracking_gtag_after_pageview' );
326
					?>
327
					<?php echo esc_js( $compat ); ?>
328
					<?php if (apply_filters( 'monsterinsights_tracking_gtag_frontend_gatracker_compatibility', true )) { ?>
329
					(function () {
330
						/* https://developers.google.com/analytics/devguides/collection/analyticsjs/ */
331
						/* ga and __gaTracker compatibility shim. */
332
						var noopfn = function () {
333
							return null;
334
						};
335
						var newtracker = function () {
336
							return new Tracker();
337
						};
338
						var Tracker = function () {
339
							return null;
340
						};
341
						var p = Tracker.prototype;
342
						p.get = noopfn;
343
						p.set = noopfn;
344
						p.send = function () {
345
							var args = Array.prototype.slice.call(arguments);
346
							args.unshift('send');
347
							__gaTracker.apply(null, args);
348
						};
349
						var __gaTracker = function () {
350
							var len = arguments.length;
351
							if (len === 0) {
352
								return;
353
							}
354
							var f = arguments[len - 1];
355
							if (typeof f !== 'object' || f === null || typeof f.hitCallback !== 'function') {
356
								if ('send' === arguments[0]) {
357
									var hitConverted, hitObject = false, action;
358
									if ('event' === arguments[1]) {
359
										if ('undefined' !== typeof arguments[3]) {
360
											hitObject = {
361
												'eventAction': arguments[3],
362
												'eventCategory': arguments[2],
363
												'eventLabel': arguments[4],
364
												'value': arguments[5] ? arguments[5] : 1,
365
											}
366
										}
367
									}
368
									if ('pageview' === arguments[1]) {
369
										if ('undefined' !== typeof arguments[2]) {
370
											hitObject = {
371
												'eventAction': 'page_view',
372
												'page_path': arguments[2],
373
											}
374
										}
375
									}
376
									if (typeof arguments[2] === 'object') {
377
										hitObject = arguments[2];
378
									}
379
									if (typeof arguments[5] === 'object') {
380
										Object.assign(hitObject, arguments[5]);
381
									}
382
									if ('undefined' !== typeof arguments[1].hitType) {
383
										hitObject = arguments[1];
384
										if ('pageview' === hitObject.hitType) {
385
											hitObject.eventAction = 'page_view';
386
										}
387
									}
388
									if (hitObject) {
389
										action = 'timing' === arguments[1].hitType ? 'timing_complete' : hitObject.eventAction;
390
										hitConverted = mapArgs(hitObject);
391
										__gtagTracker('event', action, hitConverted);
392
									}
393
								}
394
								return;
395
							}
396
397
							function mapArgs(args) {
398
								var arg, hit = {};
399
								var gaMap = {
400
									'eventCategory': 'event_category',
401
									'eventAction': 'event_action',
402
									'eventLabel': 'event_label',
403
									'eventValue': 'event_value',
404
									'nonInteraction': 'non_interaction',
405
									'timingCategory': 'event_category',
406
									'timingVar': 'name',
407
									'timingValue': 'value',
408
									'timingLabel': 'event_label',
409
									'page': 'page_path',
410
									'location': 'page_location',
411
									'title': 'page_title',
412
									'referrer' : 'page_referrer',
413
								};
414
								for (arg in args) {
415
									<?php // Note: we do || instead of && because FBIA can't encode && properly.?>
416
									if (!(!args.hasOwnProperty(arg) || !gaMap.hasOwnProperty(arg))) {
417
										hit[gaMap[arg]] = args[arg];
418
									} else {
419
										hit[arg] = args[arg];
420
									}
421
								}
422
								return hit;
423
							}
424
425
							try {
426
								f.hitCallback();
427
							} catch (ex) {
428
							}
429
						};
430
						__gaTracker.create = newtracker;
431
						__gaTracker.getByName = newtracker;
432
						__gaTracker.getAll = function () {
433
							return [];
434
						};
435
						__gaTracker.remove = noopfn;
436
						__gaTracker.loaded = true;
437
						window['__gaTracker'] = __gaTracker;
438
					})();
439
					<?php } ?>
440
				} else {
441
					<?php if ($this->should_do_optout()) { ?>
442
					console.log("<?php echo esc_js( $reason ); ?>");
443
					(function () {
444
						function __gtagTracker() {
445
							return null;
446
						}
447
448
						window['__gtagTracker'] = __gtagTracker;
449
						window['gtag'] = __gtagTracker;
450
					})();
451
					<?php } ?>
452
				}
453
			</script>
454
		<?php } else { ?>
455
			<!-- No tracking code set -->
456
		<?php } ?>
457
		<!-- / Google Analytics by MonsterInsights -->
458
		<?php
459
		$output = ob_get_contents();
460
		ob_end_clean();
461
462
		return $output;
463
	}
464
465
	public function should_do_optout() {
466
		return ! ( defined( 'MI_NO_TRACKING_OPTOUT' ) && MI_NO_TRACKING_OPTOUT );
0 ignored issues
show
Bug introduced by
The constant MI_NO_TRACKING_OPTOUT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
467
	}
468
469
	/**
470
	 * Get current page URL and
471
	 */
472
	private function get_default_locations() {
473
		global $wp;
474
475
		$urls['page_location'] = add_query_arg( $_SERVER['QUERY_STRING'], '', trailingslashit( home_url( $wp->request ) ) );
0 ignored issues
show
Comprehensibility Best Practice introduced by
$urls was never initialized. Although not strictly required by PHP, it is generally a good practice to add $urls = array(); before regardless.
Loading history...
476
477
		if ( $referer = wp_get_referer() ) {
478
			$urls['page_referrer'] = $referer;
479
		}
480
481
		return wp_json_encode( $urls );
482
	}
483
}
484