From eec39a04057d83bb65966d9651dd6a7f02ac836e Mon Sep 17 00:00:00 2001
From: Brian Canini <canini.16@osu.edu>
Date: Tue, 18 Feb 2020 12:16:06 -0500
Subject: [PATCH] Revert "Updating drupal/google_analytics (2.2.0 => 3.0.0)"

This reverts commit 80450514ae4b7ae03e53018f6a9d3dc4d19a4487.
---
 composer.json                                 |   2 +-
 composer.lock                                 |  20 +-
 vendor/composer/installed.json                |  22 +-
 web/modules/google_analytics/.eslintrc        |   2 +-
 web/modules/google_analytics/README.txt       |  14 +-
 web/modules/google_analytics/composer.json    |   6 +-
 .../install/google_analytics.settings.yml     |   2 +-
 .../config/schema/google_analytics.schema.yml |  10 +-
 .../google_analytics.info.yml                 |   8 +-
 .../google_analytics/google_analytics.install |  40 ----
 .../google_analytics/google_analytics.module  | 175 +++++++-------
 .../js/google_analytics.admin.js              |   4 +-
 .../js/google_analytics.debug.js              |  52 +++--
 .../google_analytics/js/google_analytics.js   |  52 +++--
 .../d6_google_analytics_settings.yml          |   2 -
 .../d6_google_analytics_user_settings.yml     |   8 +-
 .../d7_google_analytics_settings.yml          |   2 -
 .../d7_google_analytics_user_settings.yml     |   8 +-
 .../Form/GoogleAnalyticsAdminSettingsForm.php | 216 +++++++-----------
 .../src/GoogleAnalitycsInterface.php          |  15 --
 .../GoogleAnalyticsSkipRowIfNotSet.php        |  30 +++
 .../GoogleAnalyticsVisibilityPages.php        |   2 -
 .../GoogleAnalyticsVisibilityRoles.php        |   2 -
 .../src/Tests/GoogleAnalyticsBasicTest.php    | 130 ++++++-----
 ...nalyticsCustomDimensionsAndMetricsTest.php |  76 ++----
 .../src/Tests/GoogleAnalyticsCustomUrls.php   |  26 +--
 .../Tests/GoogleAnalyticsJavaScriptTest.js    |  14 +-
 .../Tests/GoogleAnalyticsPhpFilterTest.php    |   6 +-
 .../src/Tests/GoogleAnalyticsSearchTest.php   |  16 +-
 .../GoogleAnalyticsStatusMessagesTest.php     |  30 ++-
 .../Tests/GoogleAnalyticsUninstallTest.php    |  10 +-
 .../google_analytics_test.info.yml            |   6 +-
 .../google_analytics_test.routing.yml         |   8 +-
 .../GoogleAnalyticsTestController.php         |  14 +-
 34 files changed, 439 insertions(+), 591 deletions(-)
 rename web/modules/google_analytics/{migrations => migration_templates}/d6_google_analytics_settings.yml (98%)
 rename web/modules/google_analytics/{migrations => migration_templates}/d6_google_analytics_user_settings.yml (71%)
 rename web/modules/google_analytics/{migrations => migration_templates}/d7_google_analytics_settings.yml (98%)
 rename web/modules/google_analytics/{migrations => migration_templates}/d7_google_analytics_user_settings.yml (71%)
 delete mode 100644 web/modules/google_analytics/src/GoogleAnalitycsInterface.php
 create mode 100644 web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsSkipRowIfNotSet.php

diff --git a/composer.json b/composer.json
index 28eac3acca..6396785c31 100644
--- a/composer.json
+++ b/composer.json
@@ -128,7 +128,7 @@
         "drupal/file_browser": "1.1",
         "drupal/focal_point": "1.0-beta6",
         "drupal/geolocation": "1.10",
-        "drupal/google_analytics": "3.0",
+        "drupal/google_analytics": "2.2",
         "drupal/google_tag": "^1.3",
         "drupal/honeypot": "^1.28",
         "drupal/image_popup": "1.1",
diff --git a/composer.lock b/composer.lock
index 2ad388a59d..72bf4e9723 100644
--- a/composer.lock
+++ b/composer.lock
@@ -5056,20 +5056,20 @@
         },
         {
             "name": "drupal/google_analytics",
-            "version": "3.0.0",
+            "version": "2.2.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/google_analytics.git",
-                "reference": "8.x-3.0"
+                "reference": "8.x-2.2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/google_analytics-8.x-3.0.zip",
-                "reference": "8.x-3.0",
-                "shasum": "18179854152cae44be2a5ed5de5550bc6e131c70"
+                "url": "https://ftp.drupal.org/files/projects/google_analytics-8.x-2.2.zip",
+                "reference": "8.x-2.2",
+                "shasum": "15cd0642ad99f3776a46b702e5012713405a0733"
             },
             "require": {
-                "drupal/core": "~8.5"
+                "drupal/core": "~8.0"
             },
             "require-dev": {
                 "drupal/php": "*",
@@ -5078,11 +5078,11 @@
             "type": "drupal-module",
             "extra": {
                 "branch-alias": {
-                    "dev-3.x": "3.x-dev"
+                    "dev-2.x": "2.x-dev"
                 },
                 "drupal": {
-                    "version": "8.x-3.0",
-                    "datestamp": "1548968580",
+                    "version": "8.x-2.2",
+                    "datestamp": "1506372845",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -5106,7 +5106,7 @@
             "description": "Allows your site to be tracked by Google Analytics by adding a Javascript tracking code to every page.",
             "homepage": "https://www.drupal.org/project/google_analytics",
             "support": {
-                "source": "https://git.drupal.org/project/google_analytics.git",
+                "source": "http://git.drupal.org/project/google_analytics.git",
                 "issues": "https://www.drupal.org/project/issues/google_analytics"
             }
         },
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 4cc57ba20f..ba8d072209 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -5209,21 +5209,21 @@
     },
     {
         "name": "drupal/google_analytics",
-        "version": "3.0.0",
-        "version_normalized": "3.0.0.0",
+        "version": "2.2.0",
+        "version_normalized": "2.2.0.0",
         "source": {
             "type": "git",
             "url": "https://git.drupalcode.org/project/google_analytics.git",
-            "reference": "8.x-3.0"
+            "reference": "8.x-2.2"
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/google_analytics-8.x-3.0.zip",
-            "reference": "8.x-3.0",
-            "shasum": "18179854152cae44be2a5ed5de5550bc6e131c70"
+            "url": "https://ftp.drupal.org/files/projects/google_analytics-8.x-2.2.zip",
+            "reference": "8.x-2.2",
+            "shasum": "15cd0642ad99f3776a46b702e5012713405a0733"
         },
         "require": {
-            "drupal/core": "~8.5"
+            "drupal/core": "~8.0"
         },
         "require-dev": {
             "drupal/php": "*",
@@ -5232,11 +5232,11 @@
         "type": "drupal-module",
         "extra": {
             "branch-alias": {
-                "dev-3.x": "3.x-dev"
+                "dev-2.x": "2.x-dev"
             },
             "drupal": {
-                "version": "8.x-3.0",
-                "datestamp": "1548968580",
+                "version": "8.x-2.2",
+                "datestamp": "1506372845",
                 "security-coverage": {
                     "status": "covered",
                     "message": "Covered by Drupal's security advisory policy"
@@ -5261,7 +5261,7 @@
         "description": "Allows your site to be tracked by Google Analytics by adding a Javascript tracking code to every page.",
         "homepage": "https://www.drupal.org/project/google_analytics",
         "support": {
-            "source": "https://git.drupal.org/project/google_analytics.git",
+            "source": "http://git.drupal.org/project/google_analytics.git",
             "issues": "https://www.drupal.org/project/issues/google_analytics"
         }
     },
diff --git a/web/modules/google_analytics/.eslintrc b/web/modules/google_analytics/.eslintrc
index 0000df370c..9bff1793be 100644
--- a/web/modules/google_analytics/.eslintrc
+++ b/web/modules/google_analytics/.eslintrc
@@ -1,5 +1,5 @@
 {
   "globals": {
-    "gtag": true
+    "ga": true
   }
 }
diff --git a/web/modules/google_analytics/README.txt b/web/modules/google_analytics/README.txt
index 4d8765ef67..d424de51cb 100644
--- a/web/modules/google_analytics/README.txt
+++ b/web/modules/google_analytics/README.txt
@@ -1,6 +1,6 @@
 
 Module: Google Analytics
-Author: Alexander Hass <https://drupal.org/user/85918>
+Author: Alexander Hass <http://drupal.org/user/85918>
 
 
 Description
@@ -45,15 +45,15 @@ user with 'Administer Google Analytics' permission.
 Like the blocks visibility settings in Drupal core, there is a choice for
 "Add if the following PHP code returns TRUE." Sample PHP snippets that can be
 used in this textarea can be found on the handbook page "Overview-approach to
-block visibility" at https://drupal.org/node/64135.
+block visibility" at http://drupal.org/node/64135.
 
 Custom dimensions and metrics
 =============================
 One example for custom dimensions tracking is the "User roles" tracking.
 
-1. In the Google Analytics (https://marketingplatform.google.com/about/analytics/)
-   Management Interface you need to setup Dimension #1 with name 
-   e.g. "User roles". This step is required. Do not miss it, please.
+1. In the Google Analytics (http://www.google.com/analytics/) Management 
+   Interface you need to setup Dimension #1 with name e.g. "User roles". This
+   step is required. Do not miss it, please.
 
 2. Enter the below configuration data into the Drupal custom dimensions settings
    form under admin/config/system/googleanalytics. You can also choose another
@@ -69,7 +69,7 @@ Advanced Settings
 =================
 You can include additional JavaScript snippets in the custom javascript
 code textarea. These can be found on the official Google Analytics pages
-and a few examples at https://drupal.org/node/248699. Support is not
+and a few examples at http://drupal.org/node/248699. Support is not
 provided for any customisations you include.
 
 To speed up page loading you may also cache the Google Analytics "analytics.js"
@@ -89,7 +89,7 @@ Body:
   <li><a href="mailto:foo@example.com">Mailto</a></li>
   <li><a href="/files/test.txt">Download file</a></li>
   <li><a class="colorbox" href="#">Open colorbox</a></li>
-  <li><a href="https://example.com/">External link</a></li>
+  <li><a href="http://example.com/">External link</a></li>
   <li><a href="/go/test">Go link</a></li>
 </ul>
 
diff --git a/web/modules/google_analytics/composer.json b/web/modules/google_analytics/composer.json
index 2204e9a4be..fcb5776898 100644
--- a/web/modules/google_analytics/composer.json
+++ b/web/modules/google_analytics/composer.json
@@ -15,10 +15,8 @@
   ],
   "support": {
     "issues": "https://www.drupal.org/project/issues/google_analytics",
-    "source": "https://git.drupal.org/project/google_analytics.git"
+    "source": "http://git.drupal.org/project/google_analytics.git"
   },
   "license": "GPL-2.0+",
-  "require": {
-    "drupal/core": "~8.5"  
-  }
+  "require": {}
 }
diff --git a/web/modules/google_analytics/config/install/google_analytics.settings.yml b/web/modules/google_analytics/config/install/google_analytics.settings.yml
index f14f25d55a..615cb36032 100644
--- a/web/modules/google_analytics/config/install/google_analytics.settings.yml
+++ b/web/modules/google_analytics/config/install/google_analytics.settings.yml
@@ -20,7 +20,7 @@ track:
   messages: {  }
   site_search: false
   adsense: false
-  displayfeatures: true
+  displayfeatures: false
 privacy:
   anonymizeip: true
 custom:
diff --git a/web/modules/google_analytics/config/schema/google_analytics.schema.yml b/web/modules/google_analytics/config/schema/google_analytics.schema.yml
index dbaa929a74..aa3aa732dd 100644
--- a/web/modules/google_analytics/config/schema/google_analytics.schema.yml
+++ b/web/modules/google_analytics/config/schema/google_analytics.schema.yml
@@ -102,9 +102,6 @@ google_analytics.settings:
               index:
                 type: integer
                 label: Index
-              name:
-                type: string
-                label: Name
               value:
                 type: string
                 label: Value
@@ -118,9 +115,6 @@ google_analytics.settings:
               index:
                 type: integer
                 label: Index
-              name:
-                type: string
-                label: Name
               value:
                 type: string
                 label: Value
@@ -130,10 +124,10 @@ google_analytics.settings:
       mapping:
         create:
           type: sequence
-          label: 'Parameters'
+          label: 'Create only fields'
           sequence:
             type: ignore
-            label: 'Parameter'
+            label: 'Create field'
         before:
           type: string
           label: 'Code snippet (before)'
diff --git a/web/modules/google_analytics/google_analytics.info.yml b/web/modules/google_analytics/google_analytics.info.yml
index a102b60e81..a1d32b1057 100644
--- a/web/modules/google_analytics/google_analytics.info.yml
+++ b/web/modules/google_analytics/google_analytics.info.yml
@@ -4,14 +4,12 @@ description: 'Allows your site to be tracked by Google Analytics by adding a Jav
 package: Statistics
 # core: 8.x
 configure: google_analytics.admin_settings_form
-dependencies:
-  - drupal:system (>= 8.5)
 test_dependencies:
   - php:php
   - token:token
 
-# Information added by Drupal.org packaging script on 2019-01-31
-version: '8.x-3.0'
+# Information added by Drupal.org packaging script on 2017-09-25
+version: '8.x-2.2'
 core: '8.x'
 project: 'google_analytics'
-datestamp: 1548968586
+datestamp: 1506372866
diff --git a/web/modules/google_analytics/google_analytics.install b/web/modules/google_analytics/google_analytics.install
index a780c784ac..259bf2c196 100644
--- a/web/modules/google_analytics/google_analytics.install
+++ b/web/modules/google_analytics/google_analytics.install
@@ -6,21 +6,6 @@
  */
 
 use Drupal\Core\Url;
-use Drupal\user\Entity\Role;
-
-/**
- * Implements hook_install().
- */
-function google_analytics_install() {
-  // Make the default install more user and GDPR friendly.
-  $role = Role::load('authenticated');
-  $role->grantPermission('opt-in or out of google analytics tracking');
-  $success = $role->save();
-  if ($success) {
-    $messenger = \Drupal::messenger();
-    $messenger->addMessage(t('Module %module granted %permission permission to authenticated users.', ['%module' => 'Google Analytics', '%permission' => t('Opt-in or out of tracking')]), 'status');
-  }
-}
 
 /**
  * Implements hook_uninstall().
@@ -62,28 +47,3 @@ function google_analytics_requirements($phase) {
 
   return $requirements;
 }
-
-/**
- * Migrate create only fields to gtag.js parameters.
- */
-function google_analytics_update_8300() {
-  $config = \Drupal::configFactory()->getEditable('google_analytics.settings');
-  $create_only_fields = $config->get('codesnippet.create');
-  $parameters = [
-    'client_id' => $create_only_fields['clientId'],
-    'cookie_name' => $create_only_fields['cookieName'],
-    'cookie_domain' => $create_only_fields['cookieDomain'],
-    'cookie_expires' => $create_only_fields['cookieExpires'],
-    'sample_rate' => $create_only_fields['sampleRate'],
-    'site_speed_sample_rate' => $create_only_fields['siteSpeedSampleRate'],
-    'use_amp_client_id' => $create_only_fields['useAmpClientId'],
-    'user_id' => $create_only_fields['userId'],
-  ];
-  $parameters = array_filter($parameters);
-
-  $config
-    ->set('codesnippet.create', $parameters)
-    ->save();
-
-  return t('Migrated create only fields to gtag.js parameters.');
-}
diff --git a/web/modules/google_analytics/google_analytics.module b/web/modules/google_analytics/google_analytics.module
index 6a8b775360..addd4ec27e 100644
--- a/web/modules/google_analytics/google_analytics.module
+++ b/web/modules/google_analytics/google_analytics.module
@@ -7,7 +7,7 @@
  * Adds the required Javascript to all your Drupal pages to allow tracking by
  * the Google Analytics statistics package.
  *
- * @author: Alexander Hass <https://drupal.org/user/85918>
+ * @author: Alexander Hass <http://drupal.org/user/85918>
  */
 
 use Drupal\Component\Serialization\Json;
@@ -22,12 +22,17 @@
 use GuzzleHttp\Exception\RequestException;
 use Drupal\google_analytics\Component\Render\GoogleAnalyticsJavaScriptSnippet;
 
+/**
+ * Define the default file extension list that should be tracked as download.
+ */
+define('GOOGLE_ANALYTICS_TRACKFILES_EXTENSIONS', '7z|aac|arc|arj|asf|asx|avi|bin|csv|doc(x|m)?|dot(x|m)?|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mp(2|3|4|e?g)|mov(ie)?|msi|msp|pdf|phps|png|ppt(x|m)?|pot(x|m)?|pps(x|m)?|ppam|sld(x|m)?|thmx|qtm?|ra(m|r)?|sea|sit|tar|tgz|torrent|txt|wav|wma|wmv|wpd|xls(x|m|b)?|xlt(x|m)|xlam|xml|z|zip');
+
 /**
  * Advertise the supported google analytics api details.
  */
 function google_analytics_api() {
   return [
-    'api' => 'gtag.js',
+    'api' => 'analytics.js',
   ];
 }
 
@@ -47,7 +52,7 @@ function google_analytics_help($route_name, RouteMatchInterface $route_match) {
       return $output;
 
     case 'google_analytics.admin_settings_form':
-      return t('<a href=":ga_url">Google Analytics</a> is a free (registration required) website traffic and marketing effectiveness service.', [':ga_url' => 'https://marketingplatform.google.com/about/analytics/']);
+      return t('<a href=":ga_url">Google Analytics</a> is a free (registration required) website traffic and marketing effectiveness service.', [':ga_url' => 'http://www.google.com/analytics/']);
   }
 }
 
@@ -88,7 +93,7 @@ function google_analytics_page_attachments(array &$page) {
     $url_custom = '';
 
     // Add link tracking.
-    $link_settings = ['account' => $id];
+    $link_settings = [];
     if ($track_outbound = $config->get('track.outbound')) {
       $link_settings['trackOutbound'] = $track_outbound;
     }
@@ -137,15 +142,12 @@ function google_analytics_page_attachments(array &$page) {
         'error' => t('Error message'),
       ];
 
-      foreach (\Drupal::messenger()->all(NULL, FALSE) as $type => $messages) {
+      foreach (drupal_get_messages(NULL, FALSE) as $type => $messages) {
         // Track only the selected message types.
         if (in_array($type, $message_types)) {
           foreach ($messages as $message) {
             // @todo: Track as exceptions?
-            $event = [];
-            $event['event_category'] = t('Messages');
-            $event['event_label'] = strip_tags((string) $message);
-            $message_events .= 'gtag("event", ' . Json::encode($status_heading[$type]) . ', ' . Json::encode($event) . ');';
+            $message_events .= 'ga("send", "event", ' . Json::encode(t('Messages')) . ', ' . Json::encode($status_heading[$type]) . ', ' . Json::encode(strip_tags($message)) . ');';
           }
         }
       }
@@ -174,7 +176,7 @@ function google_analytics_page_attachments(array &$page) {
 
     // Track access denied (403) and file not found (404) pages.
     if ($status == '403') {
-      // See https://www.google.com/support/analytics/bin/answer.py?answer=86927
+      // See http://www.google.com/support/analytics/bin/answer.py?answer=86927
       $url_custom = '"' . $base_path . '403.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
     }
     elseif ($status == '404') {
@@ -194,8 +196,7 @@ function google_analytics_page_attachments(array &$page) {
     }
 
     // Add custom dimensions and metrics.
-    $custom_map = [];
-    $custom_vars = [];
+    $custom_var = '';
     foreach (['dimension', 'metric'] as $google_analytics_custom_type) {
       $google_analytics_custom_vars = $config->get('custom.' . $google_analytics_custom_type);
       // Are there dimensions or metrics configured?
@@ -213,7 +214,7 @@ function google_analytics_page_attachments(array &$page) {
           $google_analytics_custom_var['value'] = \Drupal::token()->replace($google_analytics_custom_var['value'], $types, ['clear' => TRUE]);
 
           // Suppress empty values.
-          if (!Unicode::strlen(trim($google_analytics_custom_var['name'])) || !Unicode::strlen(trim($google_analytics_custom_var['value']))) {
+          if (!Unicode::strlen(trim($google_analytics_custom_var['value']))) {
             continue;
           }
 
@@ -230,34 +231,45 @@ function google_analytics_page_attachments(array &$page) {
             settype($google_analytics_custom_var['value'], 'float');
           };
 
-          // Build the arrays of values.
-          $custom_map['custom_map'][$google_analytics_custom_type . $google_analytics_custom_var['index']] = $google_analytics_custom_var['name'];
-          $custom_vars[$google_analytics_custom_var['name']] = $google_analytics_custom_var['value'];
+          // Add variables to tracker.
+          $custom_var .= 'ga("set", ' . Json::encode($google_analytics_custom_type . $google_analytics_custom_var['index']) . ', ' . Json::encode($google_analytics_custom_var['value']) . ');';
         }
       }
     }
 
-    $custom_var = '';
-    if (!empty($custom_map)) {
-      // Add custom variables to tracker.
-      $custom_var .= 'gtag("config", ' . Json::encode($id) . ', ' . Json::encode($custom_map) . ');';
-      $custom_var .= 'gtag("event", "custom", ' . Json::encode($custom_vars) . ');';
-    };
-
     // Build tracker code.
-    $script = 'window.dataLayer = window.dataLayer || [];';
-    $script .= 'function gtag(){dataLayer.push(arguments)};';
-    $script .= 'gtag("js", new Date());';
+    $script = '(function(i,s,o,g,r,a,m){';
+    $script .= 'i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){';
+    $script .= '(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),';
+    $script .= 'm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)';
+    $script .= '})(window,document,"script",';
+
+    // Which version of the tracking library should be used?
+    $library_tracker_url = 'https://www.google-analytics.com/' . ($debug ? 'analytics_debug.js' : 'analytics.js');
+
+    // Should a local cached copy of analytics.js be used?
+    if ($config->get('cache') && $url = _google_analytics_cache($library_tracker_url)) {
+      // A dummy query-string is added to filenames, to gain control over
+      // browser-caching. The string changes on every update or full cache
+      // flush, forcing browsers to load a new copy of the files, as the
+      // URL changed.
+      $query_string = '?' . (\Drupal::state()->get('system.css_js_query_string') ?: '0');
+
+      $script .= '"' . $url . $query_string . '"';
+    }
+    else {
+      $script .= '"' . $library_tracker_url . '"';
+    }
+    $script .= ',"ga");';
 
     // Add any custom code snippets if specified.
-    $codesnippet_parameters = $config->get('codesnippet.create');
+    $codesnippet_create = $config->get('codesnippet.create');
     $codesnippet_before = $config->get('codesnippet.before');
     $codesnippet_after = $config->get('codesnippet.after');
 
-    // Build the arguments fields list.
-    // https://developers.google.com/analytics/devguides/collection/gtagjs/sending-data
-    $arguments = ['groups' => 'default'];
-    $arguments = array_merge($arguments, $codesnippet_parameters);
+    // Build the create only fields list.
+    $create_only_fields = ['cookieDomain' => 'auto'];
+    $create_only_fields = array_merge($create_only_fields, $codesnippet_create);
 
     // Domain tracking type.
     global $cookie_domain;
@@ -268,60 +280,61 @@ function google_analytics_page_attachments(array &$page) {
     // first. For hosts such as 'localhost' or IP Addresses we don't set a
     // cookie domain.
     if ($domain_mode == 1 && count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
-      $arguments = array_merge($arguments, ['cookie_domain' => $cookie_domain]);
+      $create_only_fields = array_merge($create_only_fields, ['cookieDomain' => $cookie_domain]);
       $googleanalytics_adsense_script .= 'window.google_analytics_domain_name = ' . Json::encode($cookie_domain) . ';';
     }
     elseif ($domain_mode == 2) {
-      // Cross Domain tracking
-      // https://developers.google.com/analytics/devguides/collection/gtagjs/cross-domain
-      $arguments['linker'] = [
-        'domains' => $link_settings['trackCrossDomains'],
-      ];
+      // Cross Domain tracking. 'autoLinker' need to be enabled in 'create'.
+      $create_only_fields = array_merge($create_only_fields, ['allowLinker' => TRUE]);
       $googleanalytics_adsense_script .= 'window.google_analytics_domain_name = "none";';
     }
 
     // Track logged in users across all devices.
     if ($config->get('track.userid') && $account->isAuthenticated()) {
-      $arguments['user_id'] = google_analytics_user_id_hash($account->id());
+      $create_only_fields['userId'] = google_analytics_user_id_hash($account->id());
     }
 
-    if ($config->get('privacy.anonymizeip')) {
-      $arguments['anonymize_ip'] = TRUE;
-    }
+    // Create a tracker.
+    $script .= 'ga("create", ' . Json::encode($id) . ', ' . Json::encode($create_only_fields) . ');';
 
-    if (!empty($url_custom)) {
-      $arguments['page_path'] = 'PLACEHOLDER_URL_CUSTOM';
-    }
+    // Prepare Adsense tracking.
+    $googleanalytics_adsense_script .= 'window.google_analytics_uacct = ' . Json::encode($id) . ';';
 
     // Add enhanced link attribution after 'create', but before 'pageview' send.
-    // @see https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-link-attribution
+    // @see https://support.google.com/analytics/answer/2558867
     if ($config->get('track.linkid')) {
-      $arguments['link_attribution'] = TRUE;
+      $script .= 'ga("require", "linkid", "linkid.js");';
     }
 
-    // Disabling display features.
-    // @see https://developers.google.com/analytics/devguides/collection/gtagjs/display-features
-    if (!$config->get('track.displayfeatures')) {
-      $arguments['allow_ad_personalization_signals'] = FALSE;
+    // Add display features after 'create', but before 'pageview' send.
+    // @see https://support.google.com/analytics/answer/2444872
+    if ($config->get('track.displayfeatures')) {
+      $script .= 'ga("require", "displayfeatures");';
     }
 
-    // Convert array to JSON format.
-    $arguments_json = Json::encode($arguments);
-    // Json::encode() cannot convert every data type properly.
-    $arguments_json = str_replace('"PLACEHOLDER_URL_CUSTOM"', $url_custom, $arguments_json);
-
-    // Create a tracker.
-    if (!empty($codesnippet_before)) {
-      $script .= $codesnippet_before;
+    // Domain tracking type.
+    if ($domain_mode == 2) {
+      // Cross Domain tracking
+      // https://developers.google.com/analytics/devguides/collection/upgrade/reference/gajs-analyticsjs#cross-domain
+      $script .= 'ga("require", "linker");';
+      $script .= 'ga("linker:autoLink", ' . Json::encode($link_settings['trackCrossDomains']) . ');';
     }
-    $script .= 'gtag("config", ' . Json::encode($id) . ', ' . $arguments_json . ');';
 
-    // Prepare Adsense tracking.
-    $googleanalytics_adsense_script .= 'window.google_analytics_uacct = ' . Json::encode($id) . ';';
+    if ($config->get('privacy.anonymizeip')) {
+      $script .= 'ga("set", "anonymizeIp", true);';
+    }
 
     if (!empty($custom_var)) {
       $script .= $custom_var;
     }
+    if (!empty($codesnippet_before)) {
+      $script .= $codesnippet_before;
+    }
+    if (!empty($url_custom)) {
+      $script .= 'ga("set", "page", ' . $url_custom . ');';
+    }
+    $script .= 'ga("send", "pageview");';
+
     if (!empty($message_events)) {
       $script .= $message_events;
     }
@@ -336,33 +349,6 @@ function google_analytics_page_attachments(array &$page) {
       $script = $googleanalytics_adsense_script . $script;
     }
 
-    // Prepend tracking library directly before script code.
-    if ($debug) {
-      // Debug script has highest priority to load.
-      // @FIXME: Cannot find the debug URL!???
-      $library = 'https://www.googletagmanager.com/gtag/js?id=' . $id;
-    }
-    elseif ($config->get('cache') && _google_analytics_cache('https://www.googletagmanager.com/gtag/js')) {
-      // Should a local cached copy of gtag.js be used?
-      $query_string = '?' . (\Drupal::state()->get('system.css_js_query_string') ?: '0');
-      $library = file_url_transform_relative(file_create_url('public://google_analytics/gtag.js')) . $query_string;
-    }
-    else {
-      // Fallback to default.
-      $library = 'https://www.googletagmanager.com/gtag/js?id=' . $id;
-    }
-
-    $page['#attached']['html_head'][] = [
-      [
-        '#tag' => 'script',
-        '#attributes' => [
-          'async' => TRUE,
-          'src' => $library,
-        ],
-      ],
-      'google_analytics_tracking_file',
-    ];
-
     $page['#attached']['html_head'][] = [
       [
         '#tag' => 'script',
@@ -457,12 +443,11 @@ function google_analytics_user_profile_form_submit($form, FormStateInterface $fo
  */
 function google_analytics_cron() {
   $config = \Drupal::config('google_analytics.settings');
-  $request_time = \Drupal::time()->getRequestTime();
 
   // Regenerate the tracking code file every day.
-  if ($request_time - \Drupal::state()->get('google_analytics.last_cache') >= 86400 && $config->get('cache')) {
-    _google_analytics_cache('https://www.googletagmanager.com/gtag/js', TRUE);
-    \Drupal::state()->set('google_analytics.last_cache', $request_time);
+  if (REQUEST_TIME - \Drupal::state()->get('google_analytics.last_cache') >= 86400 && $config->get('cache')) {
+    _google_analytics_cache('https://www.google-analytics.com/analytics.js', TRUE);
+    \Drupal::state()->set('google_analytics.last_cache', REQUEST_TIME);
   }
 }
 
@@ -505,14 +490,14 @@ function google_analytics_preprocess_item_list__search_results(&$variables) {
  */
 function _google_analytics_cache($location, $synchronize = FALSE) {
   $path = 'public://google_analytics';
-  $file_destination = $path . '/gtag.js';
+  $file_destination = $path . '/' . basename($location);
 
   if (!file_exists($file_destination) || $synchronize) {
     // Download the latest tracking code.
     try {
-      $data = (string) \Drupal::httpClient()
+      $data = \Drupal::httpClient()
         ->get($location)
-        ->getBody();
+        ->getBody(TRUE);
 
       if (file_exists($file_destination)) {
         // Synchronize tracking code and and replace local file if outdated.
diff --git a/web/modules/google_analytics/js/google_analytics.admin.js b/web/modules/google_analytics/js/google_analytics.admin.js
index c989f2d678..8ee9b94cf2 100644
--- a/web/modules/google_analytics/js/google_analytics.admin.js
+++ b/web/modules/google_analytics/js/google_analytics.admin.js
@@ -3,7 +3,7 @@
  * Google Analytics admin behaviors.
  */
 
-(function ($) {
+(function ($, window) {
 
   'use strict';
 
@@ -141,4 +141,4 @@
     }
   };
 
-})(jQuery);
+})(jQuery, window);
diff --git a/web/modules/google_analytics/js/google_analytics.debug.js b/web/modules/google_analytics/js/google_analytics.debug.js
index 4895836be4..d60eca3559 100644
--- a/web/modules/google_analytics/js/google_analytics.debug.js
+++ b/web/modules/google_analytics/js/google_analytics.debug.js
@@ -35,19 +35,21 @@
           else if (drupalSettings.google_analytics.trackDownload && Drupal.google_analytics.isDownload(this.href)) {
             // Download link clicked.
             console.info("Download url '%s' has been found. Tracked download as extension '%s'.", Drupal.google_analytics.getPageUrl(this.href), Drupal.google_analytics.getDownloadExtension(this.href).toUpperCase());
-            gtag('event', Drupal.google_analytics.getDownloadExtension(this.href).toUpperCase(), {
-              event_category: 'Downloads',
-              event_label: Drupal.google_analytics.getPageUrl(this.href),
-              transport_type: 'beacon'
+            ga('send', {
+              hitType: 'event',
+              eventCategory: 'Downloads',
+              eventAction: Drupal.google_analytics.getDownloadExtension(this.href).toUpperCase(),
+              eventLabel: Drupal.google_analytics.getPageUrl(this.href),
+              transport: 'beacon'
             });
           }
           else if (Drupal.google_analytics.isInternalSpecial(this.href)) {
             // Keep the internal URL for Google Analytics website overlay intact.
             console.info("Click on internal special link '%s' has been tracked.", Drupal.google_analytics.getPageUrl(this.href));
-            // @todo: May require tracking ID
-            gtag('config', drupalSettings.google_analytics.account, {
-              page_path: Drupal.google_analytics.getPageUrl(this.href),
-              transport_type: 'beacon'
+            ga('send', {
+              hitType: 'pageview',
+              page: Drupal.google_analytics.getPageUrl(this.href),
+              transport: 'beacon'
             });
           }
           else {
@@ -59,20 +61,24 @@
           if (drupalSettings.google_analytics.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) {
             // Mailto link clicked.
             console.info("Click on e-mail '%s' has been tracked.", this.href.substring(7));
-            gtag('event', 'Click', {
-              event_category: 'Mails',
-              event_label: this.href.substring(7),
-              transport_type: 'beacon'
+            ga('send', {
+              hitType: 'event',
+              eventCategory: 'Mails',
+              eventAction: 'Click',
+              eventLabel: this.href.substring(7),
+              transport: 'beacon'
             });
           }
           else if (drupalSettings.google_analytics.trackOutbound && this.href.match(/^\w+:\/\//i)) {
             if (drupalSettings.google_analytics.trackDomainMode !== 2 || (drupalSettings.google_analytics.trackDomainMode === 2 && !Drupal.google_analytics.isCrossDomain(this.hostname, drupalSettings.google_analytics.trackCrossDomains))) {
               // External link clicked / No top-level cross domain clicked.
               console.info("Outbound link '%s' has been tracked.", this.href);
-              gtag('event', 'Click', {
-                event_category: 'Outbound links',
-                event_label: this.href,
-                transport_type: 'beacon'
+              ga('send', {
+                hitType: 'event',
+                eventCategory: 'Outbound links',
+                eventAction: 'Click',
+                eventLabel: this.href,
+                transport: 'beacon'
               });
             }
             else {
@@ -89,8 +95,9 @@
     if (drupalSettings.google_analytics.trackUrlFragments) {
       window.onhashchange = function () {
         console.info("Track URL '%s' as pageview. Hash '%s' has changed.", location.pathname + location.search + location.hash, location.hash);
-        gtag('config', drupalSettings.google_analytics.account, {
-          page_path: location.pathname + location.search + location.hash
+        ga('send', {
+          hitType: 'pageview',
+          page: location.pathname + location.search + location.hash
         });
       };
     }
@@ -102,8 +109,9 @@
         var href = $.colorbox.element().attr('href');
         if (href) {
           console.info("Colorbox transition to url '%s' has been tracked.", Drupal.google_analytics.getPageUrl(href));
-          gtag('config', drupalSettings.google_analytics.account, {
-            page_path: Drupal.google_analytics.getPageUrl(href)
+          ga('send', {
+            hitType: 'pageview',
+            page: Drupal.google_analytics.getPageUrl(href)
           });
         }
       });
@@ -171,8 +179,8 @@
    * Extract the relative internal URL from an absolute internal URL.
    *
    * Examples:
-   * - https://mydomain.com/node/1 -> /node/1
-   * - https://example.com/foo/bar -> https://example.com/foo/bar
+   * - http://mydomain.com/node/1 -> /node/1
+   * - http://example.com/foo/bar -> http://example.com/foo/bar
    *
    * @param {string} url
    *   The web url to check.
diff --git a/web/modules/google_analytics/js/google_analytics.js b/web/modules/google_analytics/js/google_analytics.js
index 46bb0fc85f..0490c2b944 100644
--- a/web/modules/google_analytics/js/google_analytics.js
+++ b/web/modules/google_analytics/js/google_analytics.js
@@ -31,37 +31,43 @@
           // for download tracking?
           else if (drupalSettings.google_analytics.trackDownload && Drupal.google_analytics.isDownload(this.href)) {
             // Download link clicked.
-            gtag('event', Drupal.google_analytics.getDownloadExtension(this.href).toUpperCase(), {
-              event_category: 'Downloads',
-              event_label: Drupal.google_analytics.getPageUrl(this.href),
-              transport_type: 'beacon'
+            ga('send', {
+              hitType: 'event',
+              eventCategory: 'Downloads',
+              eventAction: Drupal.google_analytics.getDownloadExtension(this.href).toUpperCase(),
+              eventLabel: Drupal.google_analytics.getPageUrl(this.href),
+              transport: 'beacon'
             });
           }
           else if (Drupal.google_analytics.isInternalSpecial(this.href)) {
             // Keep the internal URL for Google Analytics website overlay intact.
-            // @todo: May require tracking ID
-            gtag('config', drupalSettings.google_analytics.account, {
-              page_path: Drupal.google_analytics.getPageUrl(this.href),
-              transport_type: 'beacon'
+            ga('send', {
+              hitType: 'pageview',
+              page: Drupal.google_analytics.getPageUrl(this.href),
+              transport: 'beacon'
             });
           }
         }
         else {
           if (drupalSettings.google_analytics.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) {
             // Mailto link clicked.
-            gtag('event', 'Click', {
-              event_category: 'Mails',
-              event_label: this.href.substring(7),
-              transport_type: 'beacon'
+            ga('send', {
+              hitType: 'event',
+              eventCategory: 'Mails',
+              eventAction: 'Click',
+              eventLabel: this.href.substring(7),
+              transport: 'beacon'
             });
           }
           else if (drupalSettings.google_analytics.trackOutbound && this.href.match(/^\w+:\/\//i)) {
             if (drupalSettings.google_analytics.trackDomainMode !== 2 || (drupalSettings.google_analytics.trackDomainMode === 2 && !Drupal.google_analytics.isCrossDomain(this.hostname, drupalSettings.google_analytics.trackCrossDomains))) {
               // External link clicked / No top-level cross domain clicked.
-              gtag('event', 'Click', {
-                event_category: 'Outbound links',
-                event_label: this.href,
-                transport_type: 'beacon'
+              ga('send', {
+                hitType: 'event',
+                eventCategory: 'Outbound links',
+                eventAction: 'Click',
+                eventLabel: this.href,
+                transport: 'beacon'
               });
             }
           }
@@ -72,8 +78,9 @@
     // Track hash changes as unique pageviews, if this option has been enabled.
     if (drupalSettings.google_analytics.trackUrlFragments) {
       window.onhashchange = function () {
-        gtag('config', drupalSettings.google_analytics.account, {
-          page_path: location.pathname + location.search + location.hash
+        ga('send', {
+          hitType: 'pageview',
+          page: location.pathname + location.search + location.hash
         });
       };
     }
@@ -84,8 +91,9 @@
       $(document).on('cbox_complete', function () {
         var href = $.colorbox.element().attr('href');
         if (href) {
-          gtag('config', drupalSettings.google_analytics.account, {
-            page_path: Drupal.google_analytics.getPageUrl(href)
+          ga('send', {
+            hitType: 'pageview',
+            page: Drupal.google_analytics.getPageUrl(href)
           });
         }
       });
@@ -153,8 +161,8 @@
    * Extract the relative internal URL from an absolute internal URL.
    *
    * Examples:
-   * - https://mydomain.com/node/1 -> /node/1
-   * - https://example.com/foo/bar -> https://example.com/foo/bar
+   * - http://mydomain.com/node/1 -> /node/1
+   * - http://example.com/foo/bar -> http://example.com/foo/bar
    *
    * @param {string} url
    *   The web url to check.
diff --git a/web/modules/google_analytics/migrations/d6_google_analytics_settings.yml b/web/modules/google_analytics/migration_templates/d6_google_analytics_settings.yml
similarity index 98%
rename from web/modules/google_analytics/migrations/d6_google_analytics_settings.yml
rename to web/modules/google_analytics/migration_templates/d6_google_analytics_settings.yml
index aa71bcbe77..ad2be93ff2 100644
--- a/web/modules/google_analytics/migrations/d6_google_analytics_settings.yml
+++ b/web/modules/google_analytics/migration_templates/d6_google_analytics_settings.yml
@@ -2,7 +2,6 @@ id: d6_google_analytics_settings
 label: Google Analytics 6 configuration
 migration_tags:
   - Drupal 6
-  - Configuration
 source:
   plugin: variable
   variables:
@@ -33,7 +32,6 @@ source:
     - googleanalytics_translation_set
     - googleanalytics_visibility
     - googleanalytics_visibility_roles
-  source_module: googleanalytics
 process:
   account: googleanalytics_account
   cache: googleanalytics_cache
diff --git a/web/modules/google_analytics/migrations/d6_google_analytics_user_settings.yml b/web/modules/google_analytics/migration_templates/d6_google_analytics_user_settings.yml
similarity index 71%
rename from web/modules/google_analytics/migrations/d6_google_analytics_user_settings.yml
rename to web/modules/google_analytics/migration_templates/d6_google_analytics_user_settings.yml
index 461c19a1f8..a6dfa76004 100644
--- a/web/modules/google_analytics/migrations/d6_google_analytics_user_settings.yml
+++ b/web/modules/google_analytics/migration_templates/d6_google_analytics_user_settings.yml
@@ -12,9 +12,11 @@ process:
   key: 'constants/key'
   module: 'constants/module'
   settings:
-    plugin: skip_row_if_not_set
-    index: 'custom'
-    source: data/googleanalytics
+    # Based on skip_row_if_not_set
+    plugin: google_analytics_skip_row_if_not_set
+    key: custom
+    module: googleanalytics
+    source: data
 destination:
   plugin: user_data
 migration_dependencies:
diff --git a/web/modules/google_analytics/migrations/d7_google_analytics_settings.yml b/web/modules/google_analytics/migration_templates/d7_google_analytics_settings.yml
similarity index 98%
rename from web/modules/google_analytics/migrations/d7_google_analytics_settings.yml
rename to web/modules/google_analytics/migration_templates/d7_google_analytics_settings.yml
index 25f48ea5b3..ab3beece9f 100644
--- a/web/modules/google_analytics/migrations/d7_google_analytics_settings.yml
+++ b/web/modules/google_analytics/migration_templates/d7_google_analytics_settings.yml
@@ -2,7 +2,6 @@ id: d7_google_analytics_settings
 label: Google Analytics 7 configuration
 migration_tags:
   - Drupal 7
-  - Configuration
 source:
   plugin: variable
   variables:
@@ -35,7 +34,6 @@ source:
     - googleanalytics_translation_set
     - googleanalytics_visibility_pages
     - googleanalytics_visibility_roles
-  source_module: googleanalytics    
 process:
   account: googleanalytics_account
   premium: googleanalytics_premium
diff --git a/web/modules/google_analytics/migrations/d7_google_analytics_user_settings.yml b/web/modules/google_analytics/migration_templates/d7_google_analytics_user_settings.yml
similarity index 71%
rename from web/modules/google_analytics/migrations/d7_google_analytics_user_settings.yml
rename to web/modules/google_analytics/migration_templates/d7_google_analytics_user_settings.yml
index a84278d3cc..6d4e21719e 100644
--- a/web/modules/google_analytics/migrations/d7_google_analytics_user_settings.yml
+++ b/web/modules/google_analytics/migration_templates/d7_google_analytics_user_settings.yml
@@ -12,9 +12,11 @@ process:
   key: 'constants/key'
   module: 'constants/module'
   settings:
-    plugin: skip_row_if_not_set
-    index: 'custom'
-    source: data/googleanalytics
+    # Based on skip_row_if_not_set
+    plugin: google_analytics_skip_row_if_not_set
+    key: custom
+    module: googleanalytics
+    source: data
 destination:
   plugin: user_data
 migration_dependencies:
diff --git a/web/modules/google_analytics/src/Form/GoogleAnalyticsAdminSettingsForm.php b/web/modules/google_analytics/src/Form/GoogleAnalyticsAdminSettingsForm.php
index bd39c33b3c..197f0275c6 100644
--- a/web/modules/google_analytics/src/Form/GoogleAnalyticsAdminSettingsForm.php
+++ b/web/modules/google_analytics/src/Form/GoogleAnalyticsAdminSettingsForm.php
@@ -3,33 +3,15 @@
 namespace Drupal\google_analytics\Form;
 
 use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Extension\ModuleHandler;
 use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
-use Drupal\Core\Session\AccountInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\google_analytics\GoogleAnalitycsInterface;
 
 /**
  * Configure Google_Analytics settings for this site.
  */
 class GoogleAnalyticsAdminSettingsForm extends ConfigFormBase {
 
-  protected $moduleHandler;
-
-  protected $currentUser;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct(ConfigFactoryInterface $config_factory, AccountInterface $currentUser, ModuleHandler $moduleHandler) {
-    parent::__construct($config_factory);
-    $this->currentUser = $currentUser;
-    $this->moduleHandler = $moduleHandler;
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -58,7 +40,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
 
     $form['general']['google_analytics_account'] = [
       '#default_value' => $config->get('account'),
-      '#description' => $this->t('This ID is unique to each site you want to track separately, and is in the form of UA-xxxxxxx-yy. To get a Web Property ID, <a href=":analytics">register your site with Google Analytics</a>, or if you already have registered your site, go to your Google Analytics Settings page to see the ID next to every site profile. <a href=":webpropertyid">Find more information in the documentation</a>.', [':analytics' => 'https://marketingplatform.google.com/about/analytics/', ':webpropertyid' => Url::fromUri('https://developers.google.com/analytics/resources/concepts/gaConceptsAccounts', ['fragment' => 'webProperty'])->toString()]),
+      '#description' => $this->t('This ID is unique to each site you want to track separately, and is in the form of UA-xxxxxxx-yy. To get a Web Property ID, <a href=":analytics">register your site with Google Analytics</a>, or if you already have registered your site, go to your Google Analytics Settings page to see the ID next to every site profile. <a href=":webpropertyid">Find more information in the documentation</a>.', [':analytics' => 'http://www.google.com/analytics/', ':webpropertyid' => Url::fromUri('https://developers.google.com/analytics/resources/concepts/gaConceptsAccounts', ['fragment' => 'webProperty'])->toString()]),
       '#maxlength' => 20,
       '#placeholder' => 'UA-',
       '#required' => TRUE,
@@ -151,7 +133,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     ];
 
     // Page specific visibility configurations.
-    $account = $this->currentUser;
+    $account = \Drupal::currentUser();
     $php_access = $account->hasPermission('use PHP for google analytics tracking visibility');
     $visibility_request_path_pages = $config->get('visibility.request_path_pages');
 
@@ -168,18 +150,18 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     }
     else {
       $options = [
-        $this->t('Every page except the listed pages'),
-        $this->t('The listed pages only'),
+        t('Every page except the listed pages'),
+        t('The listed pages only'),
       ];
-      $description = $this->t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", ['%blog' => '/blog', '%blog-wildcard' => '/blog/*', '%front' => '<front>']);
+      $description = t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", ['%blog' => '/blog', '%blog-wildcard' => '/blog/*', '%front' => '<front>']);
 
-      if ($this->moduleHandler->moduleExists('php') && $php_access) {
-        $options[] = $this->t('Pages on which this PHP code returns <code>TRUE</code> (experts only)');
-        $title = $this->t('Pages or PHP code');
-        $description .= ' ' . $this->t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', ['%php' => '<?php ?>']);
+      if (\Drupal::moduleHandler()->moduleExists('php') && $php_access) {
+        $options[] = t('Pages on which this PHP code returns <code>TRUE</code> (experts only)');
+        $title = t('Pages or PHP code');
+        $description .= ' ' . t('If the PHP option is chosen, enter PHP code between %php. Note that executing incorrect PHP code can break your Drupal site.', ['%php' => '<?php ?>']);
       }
       else {
-        $title = $this->t('Pages');
+        $title = t('Pages');
       }
       $form['tracking']['page_visibility_settings']['google_analytics_visibility_request_path_mode'] = [
         '#type' => 'radios',
@@ -210,8 +192,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#type' => 'radios',
       '#title' => $this->t('Add tracking for specific roles'),
       '#options' => [
-        $this->t('Add to the selected roles only'),
-        $this->t('Add to every role except the selected ones'),
+        t('Add to the selected roles only'),
+        t('Add to every role except the selected ones'),
       ],
       '#default_value' => $config->get('visibility.user_role_mode'),
     ];
@@ -231,14 +213,14 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#title' => $this->t('Users'),
       '#group' => 'tracking_scope',
     ];
-    $t_permission = ['%permission' => $this->t('Opt-in or out of tracking')];
+    $t_permission = ['%permission' => $this->t('opt-in or out of tracking')];
     $form['tracking']['user_visibility_settings']['google_analytics_visibility_user_account_mode'] = [
       '#type' => 'radios',
       '#title' => $this->t('Allow users to customize tracking on their account page'),
       '#options' => [
-        $this->t('No customization allowed'),
-        $this->t('Tracking on by default, users with %permission permission can opt out', $t_permission),
-        $this->t('Tracking off by default, users with %permission permission can opt in', $t_permission),
+        t('No customization allowed'),
+        t('Tracking on by default, users with %permission permission can opt out', $t_permission),
+        t('Tracking off by default, users with %permission permission can opt in', $t_permission),
       ],
       '#default_value' => !empty($visibility_user_account_mode) ? $visibility_user_account_mode : 0,
     ];
@@ -275,7 +257,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#title_display' => 'invisible',
       '#type' => 'textfield',
       '#default_value' => $config->get('track.files_extensions'),
-      '#description' => $this->t('A file extension list separated by the | character that will be tracked as download when clicked. Regular expressions are supported. For example: @extensions', ['@extensions' => GoogleAnalitycsInterface::GOOGLE_ANALYTICS_TRACKFILES_EXTENSIONS]),
+      '#description' => $this->t('A file extension list separated by the | character that will be tracked as download when clicked. Regular expressions are supported. For example: @extensions', ['@extensions' => GOOGLE_ANALYTICS_TRACKFILES_EXTENSIONS]),
       '#maxlength' => 500,
       '#states' => [
         'enabled' => [
@@ -289,7 +271,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     ];
 
     $colorbox_dependencies = '<div class="admin-requirements">';
-    $colorbox_dependencies .= $this->t('Requires: @module-list', ['@module-list' => ($this->moduleHandler->moduleExists('colorbox') ? $this->t('@module (<span class="admin-enabled">enabled</span>)', ['@module' => 'Colorbox']) : $this->t('@module (<span class="admin-missing">disabled</span>)', ['@module' => 'Colorbox']))]);
+    $colorbox_dependencies .= t('Requires: @module-list', ['@module-list' => (\Drupal::moduleHandler()->moduleExists('colorbox') ? t('@module (<span class="admin-enabled">enabled</span>)', ['@module' => 'Colorbox']) : t('@module (<span class="admin-missing">disabled</span>)', ['@module' => 'Colorbox']))]);
     $colorbox_dependencies .= '</div>';
 
     $form['tracking']['linktracking']['google_analytics_trackcolorbox'] = [
@@ -297,7 +279,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#title' => $this->t('Track content in colorbox modal dialogs'),
       '#description' => $this->t('Enable to track the content shown in colorbox modal windows.') . $colorbox_dependencies,
       '#default_value' => $config->get('track.colorbox'),
-      '#disabled' => ($this->moduleHandler->moduleExists('colorbox') ? FALSE : TRUE),
+      '#disabled' => (\Drupal::moduleHandler()->moduleExists('colorbox') ? FALSE : TRUE),
     ];
 
     $form['tracking']['linktracking']['google_analytics_tracklinkid'] = [
@@ -339,7 +321,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     ];
 
     $site_search_dependencies = '<div class="admin-requirements">';
-    $site_search_dependencies .= $this->t('Requires: @module-list', ['@module-list' => ($this->moduleHandler->moduleExists('search') ? $this->t('@module (<span class="admin-enabled">enabled</span>)', ['@module' => 'Search']) : $this->t('@module (<span class="admin-missing">disabled</span>)', ['@module' => 'Search']))]);
+    $site_search_dependencies .= t('Requires: @module-list', ['@module-list' => (\Drupal::moduleHandler()->moduleExists('search') ? t('@module (<span class="admin-enabled">enabled</span>)', ['@module' => 'Search']) : t('@module (<span class="admin-missing">disabled</span>)', ['@module' => 'Search']))]);
     $site_search_dependencies .= '</div>';
 
     $form['tracking']['search_and_advertising']['google_analytics_site_search'] = [
@@ -347,7 +329,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#title' => $this->t('Track internal search'),
       '#description' => $this->t('If checked, internal search keywords are tracked. You must configure your Google account to use the internal query parameter <strong>search</strong>. For more information see <a href=":url">Setting Up Site Search for a Profile</a>.', [':url' => 'https://support.google.com/analytics/answer/1012264']) . $site_search_dependencies,
       '#default_value' => $config->get('track.site_search'),
-      '#disabled' => ($this->moduleHandler->moduleExists('search') ? FALSE : TRUE),
+      '#disabled' => (\Drupal::moduleHandler()->moduleExists('search') ? FALSE : TRUE),
     ];
     $form['tracking']['search_and_advertising']['google_analytics_trackadsense'] = [
       '#type' => 'checkbox',
@@ -387,7 +369,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#type' => 'table',
       '#header' => [
         ['data' => $this->t('Index')],
-        ['data' => $this->t('Name')],
         ['data' => $this->t('Value')],
       ],
     ];
@@ -407,14 +388,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         '#title_display' => 'invisible',
         '#type' => 'textfield',
       ];
-      $form['google_analytics_custom_dimension']['indexes'][$i]['name'] = [
-        '#default_value' => isset($google_analytics_custom_dimension[$i]['name']) ? $google_analytics_custom_dimension[$i]['name'] : '',
-        '#description' => $this->t('The custom dimension name.'),
-        '#maxlength' => 255,
-        '#title' => $this->t('Custom dimension name #@index', ['@index' => $i]),
-        '#title_display' => 'invisible',
-        '#type' => 'textfield',
-      ];
       $form['google_analytics_custom_dimension']['indexes'][$i]['value'] = [
         '#default_value' => isset($google_analytics_custom_dimension[$i]['value']) ? $google_analytics_custom_dimension[$i]['value'] : '',
         '#description' => $this->t('The custom dimension value.'),
@@ -425,16 +398,16 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         '#element_validate' => [[get_class($this), 'tokenElementValidate']],
         '#token_types' => ['node'],
       ];
-      if ($this->moduleHandler->moduleExists('token')) {
+      if (\Drupal::moduleHandler()->moduleExists('token')) {
         $form['google_analytics_custom_dimension']['indexes'][$i]['value']['#element_validate'][] = 'token_element_validate';
       }
     }
 
     $form['google_analytics_custom_dimension']['google_analytics_description'] = [
       '#type' => 'item',
-      '#description' => $this->t('You can supplement Google Analytics\' basic IP address tracking of visitors by segmenting users based on custom dimensions. Section 7 of the <a href=":ga_tos">Google Analytics terms of service</a> requires that You will not (and will not allow any third party to) use the Service to track, collect or upload any data that personally identifies an individual (such as a name, userid, email address or billing information), or other data which can be reasonably linked to such information by Google. You will have and abide by an appropriate Privacy Policy and will comply with all applicable laws and regulations relating to the collection of information from Visitors. You must post a Privacy Policy and that Privacy Policy must provide notice of Your use of cookies that are used to collect traffic data, and You must not circumvent any privacy features (e.g., an opt-out) that are part of the Service.', [':ga_tos' => 'https://www.google.com/analytics/terms/gb.html']),
+      '#description' => $this->t('You can supplement Google Analytics\' basic IP address tracking of visitors by segmenting users based on custom dimensions. Section 7 of the <a href=":ga_tos">Google Analytics terms of service</a> requires that You will not (and will not allow any third party to) use the Service to track, collect or upload any data that personally identifies an individual (such as a name, userid, email address or billing information), or other data which can be reasonably linked to such information by Google. You will have and abide by an appropriate Privacy Policy and will comply with all applicable laws and regulations relating to the collection of information from Visitors. You must post a Privacy Policy and that Privacy Policy must provide notice of Your use of cookies that are used to collect traffic data, and You must not circumvent any privacy features (e.g., an opt-out) that are part of the Service.', [':ga_tos' => 'http://www.google.com/analytics/terms/gb.html']),
     ];
-    if ($this->moduleHandler->moduleExists('token')) {
+    if (\Drupal::moduleHandler()->moduleExists('token')) {
       $form['google_analytics_custom_dimension']['google_analytics_token_tree'] = [
         '#theme' => 'token_tree_link',
         '#token_types' => ['node'],
@@ -453,7 +426,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#type' => 'table',
       '#header' => [
         ['data' => $this->t('Index')],
-        ['data' => $this->t('Name')],
         ['data' => $this->t('Value')],
       ],
     ];
@@ -472,14 +444,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         '#title_display' => 'invisible',
         '#type' => 'textfield',
       ];
-      $form['google_analytics_custom_metric']['indexes'][$i]['name'] = [
-        '#default_value' => isset($google_analytics_custom_metric[$i]['name']) ? $google_analytics_custom_metric[$i]['name'] : '',
-        '#description' => $this->t('The custom metric name.'),
-        '#maxlength' => 255,
-        '#title' => $this->t('Custom metric name #@index', ['@index' => $i]),
-        '#title_display' => 'invisible',
-        '#type' => 'textfield',
-      ];
       $form['google_analytics_custom_metric']['indexes'][$i]['value'] = [
         '#default_value' => isset($google_analytics_custom_metric[$i]['value']) ? $google_analytics_custom_metric[$i]['value'] : '',
         '#description' => $this->t('The custom metric value.'),
@@ -490,16 +454,16 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         '#element_validate' => [[get_class($this), 'tokenElementValidate']],
         '#token_types' => ['node'],
       ];
-      if ($this->moduleHandler->moduleExists('token')) {
+      if (\Drupal::moduleHandler()->moduleExists('token')) {
         $form['google_analytics_custom_metric']['indexes'][$i]['value']['#element_validate'][] = 'token_element_validate';
       }
     }
 
     $form['google_analytics_custom_metric']['google_analytics_description'] = [
       '#type' => 'item',
-      '#description' => $this->t('You can supplement Google Analytics\' basic IP address tracking of visitors by segmenting users based on custom metrics. Section 7 of the <a href=":ga_tos">Google Analytics terms of service</a> requires that You will not (and will not allow any third party to) use the Service to track, collect or upload any data that personally identifies an individual (such as a name, userid, email address or billing information), or other data which can be reasonably linked to such information by Google. You will have and abide by an appropriate Privacy Policy and will comply with all applicable laws and regulations relating to the collection of information from Visitors. You must post a Privacy Policy and that Privacy Policy must provide notice of Your use of cookies that are used to collect traffic data, and You must not circumvent any privacy features (e.g., an opt-out) that are part of the Service.', [':ga_tos' => 'https://www.google.com/analytics/terms/gb.html']),
+      '#description' => $this->t('You can supplement Google Analytics\' basic IP address tracking of visitors by segmenting users based on custom metrics. Section 7 of the <a href=":ga_tos">Google Analytics terms of service</a> requires that You will not (and will not allow any third party to) use the Service to track, collect or upload any data that personally identifies an individual (such as a name, userid, email address or billing information), or other data which can be reasonably linked to such information by Google. You will have and abide by an appropriate Privacy Policy and will comply with all applicable laws and regulations relating to the collection of information from Visitors. You must post a Privacy Policy and that Privacy Policy must provide notice of Your use of cookies that are used to collect traffic data, and You must not circumvent any privacy features (e.g., an opt-out) that are part of the Service.', [':ga_tos' => 'http://www.google.com/analytics/terms/gb.html']),
     ];
-    if ($this->moduleHandler->moduleExists('token')) {
+    if (\Drupal::moduleHandler()->moduleExists('token')) {
       $form['google_analytics_custom_metric']['google_analytics_token_tree'] = [
         '#theme' => 'token_tree_link',
         '#token_types' => ['node'],
@@ -521,7 +485,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     ];
 
     // Allow for tracking of the originating node when viewing translation sets.
-    if ($this->moduleHandler->moduleExists('content_translation')) {
+    if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
       $form['advanced']['google_analytics_translation_set'] = [
         '#type' => 'checkbox',
         '#title' => $this->t('Track translation sets as one unit'),
@@ -536,15 +500,15 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#type' => 'details',
       '#title' => $this->t('Custom JavaScript code'),
       '#open' => TRUE,
-      '#description' => $this->t('You can add custom Google Analytics <a href=":snippets">code snippets</a> here. These will be added every time tracking is in effect. Before you add your custom code, you should read the <a href=":ga_concepts_overview">Google Analytics Tracking Code - Functional Overview</a> and the <a href=":ga_js_api">Google Analytics Tracking API</a> documentation. <strong>Do not include the &lt;script&gt; tags</strong>, and always end your code with a semicolon (;).', [':snippets' => 'https://drupal.org/node/248699', ':ga_concepts_overview' => 'https://developers.google.com/analytics/resources/concepts/gaConceptsTrackingOverview', ':ga_js_api' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/method-reference']),
+      '#description' => $this->t('You can add custom Google Analytics <a href=":snippets">code snippets</a> here. These will be added every time tracking is in effect. Before you add your custom code, you should read the <a href=":ga_concepts_overview">Google Analytics Tracking Code - Functional Overview</a> and the <a href=":ga_js_api">Google Analytics Tracking API</a> documentation. <strong>Do not include the &lt;script&gt; tags</strong>, and always end your code with a semicolon (;).', [':snippets' => 'http://drupal.org/node/248699', ':ga_concepts_overview' => 'https://developers.google.com/analytics/resources/concepts/gaConceptsTrackingOverview', ':ga_js_api' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/method-reference']),
     ];
     $form['advanced']['codesnippet']['google_analytics_codesnippet_create'] = [
       '#type' => 'textarea',
-      '#title' => $this->t('Parameters'),
+      '#title' => $this->t('Create only fields'),
       '#default_value' => $this->getNameValueString($config->get('codesnippet.create')),
       '#rows' => 5,
-      '#description' => $this->t('Enter one value per line, in the format name|value. Settings in this textarea will be added to <code>gtag("config", "UA-XXXX-Y", {"name":"value"});</code>. For more information, read <a href=":url">documentation</a> in the gtag.js reference.', [':url' => 'https://developers.google.com/analytics/devguides/collection/gtagjs/']),
-      '#element_validate' => [[get_class($this), 'validateParameterValues']],
+      '#description' => $this->t('Enter one value per line, in the format name|value. Settings in this textarea will be added to <code>ga("create", "UA-XXXX-Y", {"name":"value"});</code>. For more information, read <a href=":url">create only fields</a> documentation in the Analytics.js field reference.', [':url' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#create']),
+      '#element_validate' => [[get_class($this), 'validateCreateFieldValues']],
     ];
     $form['advanced']['codesnippet']['google_analytics_codesnippet_before'] = [
       '#type' => 'textarea',
@@ -552,7 +516,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#default_value' => $config->get('codesnippet.before'),
       '#disabled' => $user_access_add_js_snippets,
       '#rows' => 5,
-      '#description' => $this->t('Code in this textarea will be added <strong>before</strong> <code>gtag("config", "UA-XXXX-Y");</code>.') . $user_access_add_js_snippets_permission_warning,
+      '#description' => $this->t('Code in this textarea will be added <strong>before</strong> <code>ga("send", "pageview");</code>.') . $user_access_add_js_snippets_permission_warning,
     ];
     $form['advanced']['codesnippet']['google_analytics_codesnippet_after'] = [
       '#type' => 'textarea',
@@ -560,7 +524,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#default_value' => $config->get('codesnippet.after'),
       '#disabled' => $user_access_add_js_snippets,
       '#rows' => 5,
-      '#description' => $this->t('Code in this textarea will be added <strong>after</strong> <code>gtag("config", "UA-XXXX-Y");</code>. This is useful if you\'d like to track a site in two accounts.') . $user_access_add_js_snippets_permission_warning,
+      '#description' => $this->t('Code in this textarea will be added <strong>after</strong> <code>ga("send", "pageview");</code>. This is useful if you\'d like to track a site in two accounts.') . $user_access_add_js_snippets_permission_warning,
     ];
 
     $form['advanced']['google_analytics_debug'] = [
@@ -611,13 +575,13 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
     $form_state->setValue('google_analytics_account', str_replace(['–', '—', '−'], '-', $form_state->getValue('google_analytics_account')));
 
     if (!preg_match('/^UA-\d+-\d+$/', $form_state->getValue('google_analytics_account'))) {
-      $form_state->setErrorByName('google_analytics_account', $this->t('A valid Google Analytics Web Property ID is case sensitive and formatted like UA-xxxxxxx-yy.'));
+      $form_state->setErrorByName('google_analytics_account', t('A valid Google Analytics Web Property ID is case sensitive and formatted like UA-xxxxxxx-yy.'));
     }
 
     // If multiple top-level domains has been selected, a domain names list is
     // required.
     if ($form_state->getValue('google_analytics_domain_mode') == 2 && $form_state->isValueEmpty('google_analytics_cross_domains')) {
-      $form_state->setErrorByName('google_analytics_cross_domains', $this->t('A list of top-level domains is required if <em>Multiple top-level domains</em> has been selected.'));
+      $form_state->setErrorByName('google_analytics_cross_domains', t('A list of top-level domains is required if <em>Multiple top-level domains</em> has been selected.'));
     }
     // Clear the domain list if cross domains are disabled.
     if ($form_state->getValue('google_analytics_domain_mode') != 2) {
@@ -625,12 +589,12 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
     }
 
     // Verify that every path is prefixed with a slash, but don't check PHP
-    // code snippets and do not check for slashes if no paths configured.
-    if ($form_state->getValue('google_analytics_visibility_request_path_mode') != 2 && !empty($form_state->getValue('google_analytics_visibility_request_path_pages'))) {
+    // code snippets.
+    if ($form_state->getValue('google_analytics_visibility_request_path_mode') != 2) {
       $pages = preg_split('/(\r\n?|\n)/', $form_state->getValue('google_analytics_visibility_request_path_pages'));
       foreach ($pages as $page) {
         if (strpos($page, '/') !== 0 && $page !== '<front>') {
-          $form_state->setErrorByName('google_analytics_visibility_request_path_pages', $this->t('Path "@page" not prefixed with slash.', ['@page' => $page]));
+          $form_state->setErrorByName('google_analytics_visibility_request_path_pages', t('Path "@page" not prefixed with slash.', ['@page' => $page]));
           // Drupal forms show one error only.
           break;
         }
@@ -639,7 +603,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
 
     // Disallow empty list of download file extensions.
     if ($form_state->getValue('google_analytics_trackfiles') && $form_state->isValueEmpty('google_analytics_trackfiles_extensions')) {
-      $form_state->setErrorByName('google_analytics_trackfiles_extensions', $this->t('List of download file extensions cannot empty.'));
+      $form_state->setErrorByName('google_analytics_trackfiles_extensions', t('List of download file extensions cannot empty.'));
     }
     // Clear obsolete local cache if cache has been disabled.
     if ($form_state->isValueEmpty('google_analytics_cache') && $form['advanced']['google_analytics_cache']['#default_value']) {
@@ -648,16 +612,16 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
 
     // This is for the Newbie's who cannot read a text area description.
     if (stristr($form_state->getValue('google_analytics_codesnippet_before'), 'google-analytics.com/analytics.js')) {
-      $form_state->setErrorByName('google_analytics_codesnippet_before', $this->t('Do not add the tracker code provided by Google into the javascript code snippets! This module already builds the tracker code based on your Google Analytics account number and settings.'));
+      $form_state->setErrorByName('google_analytics_codesnippet_before', t('Do not add the tracker code provided by Google into the javascript code snippets! This module already builds the tracker code based on your Google Analytics account number and settings.'));
     }
     if (stristr($form_state->getValue('google_analytics_codesnippet_after'), 'google-analytics.com/analytics.js')) {
-      $form_state->setErrorByName('google_analytics_codesnippet_after', $this->t('Do not add the tracker code provided by Google into the javascript code snippets! This module already builds the tracker code based on your Google Analytics account number and settings.'));
+      $form_state->setErrorByName('google_analytics_codesnippet_after', t('Do not add the tracker code provided by Google into the javascript code snippets! This module already builds the tracker code based on your Google Analytics account number and settings.'));
     }
     if (preg_match('/(.*)<\/?script(.*)>(.*)/i', $form_state->getValue('google_analytics_codesnippet_before'))) {
-      $form_state->setErrorByName('google_analytics_codesnippet_before', $this->t('Do not include the &lt;script&gt; tags in the javascript code snippets.'));
+      $form_state->setErrorByName('google_analytics_codesnippet_before', t('Do not include the &lt;script&gt; tags in the javascript code snippets.'));
     }
     if (preg_match('/(.*)<\/?script(.*)>(.*)/i', $form_state->getValue('google_analytics_codesnippet_after'))) {
-      $form_state->setErrorByName('google_analytics_codesnippet_after', $this->t('Do not include the &lt;script&gt; tags in the javascript code snippets.'));
+      $form_state->setErrorByName('google_analytics_codesnippet_after', t('Do not include the &lt;script&gt; tags in the javascript code snippets.'));
     }
   }
 
@@ -822,7 +786,7 @@ protected static function containsForbiddenToken($token_string) {
   }
 
   /**
-   * The #element_validate callback for parameters.
+   * The #element_validate callback for create only fields.
    *
    * @param array $element
    *   An associative array containing the properties and children of the
@@ -832,8 +796,8 @@ protected static function containsForbiddenToken($token_string) {
    *
    * @see form_process_pattern()
    */
-  public static function validateParameterValues(array $element, FormStateInterface $form_state) {
-    $values = static::extractParameterValues($element['#value']);
+  public static function validateCreateFieldValues(array $element, FormStateInterface $form_state) {
+    $values = static::extractCreateFieldValues($element['#value']);
 
     if (!is_array($values)) {
       $form_state->setError($element, t('The %element-title field contains invalid input.', ['%element-title' => $element['#title']]));
@@ -841,11 +805,11 @@ public static function validateParameterValues(array $element, FormStateInterfac
     else {
       // Check that name and value are valid for the field type.
       foreach ($values as $name => $value) {
-        if ($error = static::validateParameterName($name)) {
+        if ($error = static::validateCreateFieldName($name)) {
           $form_state->setError($element, $error);
           break;
         }
-        if ($error = static::validateParameterValue($value)) {
+        if ($error = static::validateCreateFieldValue($value)) {
           $form_state->setError($element, $error);
           break;
         }
@@ -866,7 +830,7 @@ public static function validateParameterValues(array $element, FormStateInterfac
    *
    * @see \Drupal\options\Plugin\Field\FieldType\ListTextItem::allowedValuesString()
    */
-  protected static function extractParameterValues($string) {
+  protected static function extractCreateFieldValues($string) {
     $values = [];
 
     $list = explode("\n", $string);
@@ -892,7 +856,7 @@ protected static function extractParameterValues($string) {
   }
 
   /**
-   * Checks whether a parameter name is valid.
+   * Checks whether a field name is valid.
    *
    * @param string $name
    *   The option value entered by the user.
@@ -900,39 +864,32 @@ protected static function extractParameterValues($string) {
    * @return string|null
    *   The error message if the specified value is invalid, NULL otherwise.
    */
-  protected static function validateParameterName($name) {
+  protected static function validateCreateFieldName($name) {
     // List of supported field names:
     // https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#create
-    $allowed_parameters = [
-      'client_id',
-      'currency',
-      'country',
-      'cookie_name',
-      'cookie_domain',
-      'cookie_expires',
-      'sample_rate',
-      'send_page_view',
-      'site_speed_sample_rate',
-      'use_amp_client_id',
-    ];
-
-    if ($name == 'allow_ad_personalization_signals') {
-      return t('Parameter name %name is disallowed. Please configure <em>Track display features</em> under <em>Tracking scope > Search and Advertising</em>.', ['%name' => $name]);
-    }
-    if ($name == 'anonymize_ip') {
-      return t('Parameter name %name is disallowed. Please configure <em>Anonymize visitors IP address</em> under <em>Tracking scope > Privacy</em>.', ['%name' => $name]);
-    }
-    if ($name == 'link_attribution') {
-      return t('Parameter name %name is disallowed. Please configure <em>Track enhanced link attribution</em> under <em>Tracking scope > Links and downloads</em>.', ['%name' => $name]);
-    }
-    if ($name == 'linker') {
-      return t('Parameter name %name is disallowed. Please configure <em>Multiple top-level domains</em> under <em>Tracking scope > Domains</em> to enable cross domain tracking.', ['%name' => $name]);
-    }
-    if ($name == 'user_id') {
-      return t('Parameter name %name is disallowed. Please configure <em>Track User ID</em> under <em>Tracking scope > Users</em>.', ['%name' => $name]);
-    }
-    if (!in_array($name, $allowed_parameters)) {
-      return t('Parameter name %name is unknown. Parameters are case sensitive. Please see <a href=":url">documentation</a> for supported parameters.', ['%name' => $name, ':url' => 'https://developers.google.com/analytics/devguides/collection/gtagjs/']);
+    $create_only_fields = [
+      'allowAnchor',
+      'alwaysSendReferrer',
+      'clientId',
+      'cookieName',
+      'cookieDomain',
+      'cookieExpires',
+      'legacyCookieDomain',
+      'legacyHistoryImport',
+      'sampleRate',
+      'siteSpeedSampleRate',
+      'storage',
+      'userId',
+    ];
+
+    if ($name == 'name') {
+      return t('Create only field name %name is a disallowed field name. Changing the <em>Tracker Name</em> is currently not supported.', ['%name' => $name]);
+    }
+    if ($name == 'allowLinker') {
+      return t('Create only field name %name is a disallowed field name. Please select <em>Multiple top-level domains</em> under <em>What are you tracking</em> to enable cross domain tracking.', ['%name' => $name]);
+    }
+    if (!in_array($name, $create_only_fields)) {
+      return t('Create only field name %name is an unknown field name. Field names are case sensitive. Please see <a href=":url">create only fields</a> documentation for supported field names.', ['%name' => $name, ':url' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#create']);
     }
   }
 
@@ -945,12 +902,12 @@ protected static function validateParameterName($name) {
    * @return string|null
    *   The error message if the specified value is invalid, NULL otherwise.
    */
-  protected static function validateParameterValue($value) {
+  protected static function validateCreateFieldValue($value) {
     if (!is_bool($value) && !Unicode::strlen($value)) {
-      return t('A parameter requires a value.');
+      return t('A create only field requires a value.');
     }
     if (Unicode::strlen($value) > 255) {
-      return t('The value of a parameter must be a string at most 255 characters long.');
+      return t('The value of a create only field must be a string at most 255 characters long.');
     }
   }
 
@@ -1004,12 +961,13 @@ protected static function convertFormValueDataTypes(array $values) {
 
       // Convert other known fields.
       switch ($name) {
-        case 'sample_rate':
+        case 'sampleRate':
           // Float types.
           settype($value, 'float');
           break;
 
-        case 'cookie_expires':
+        case 'siteSpeedSampleRate':
+        case 'cookieExpires':
           // Integer types.
           settype($value, 'integer');
           break;
@@ -1021,16 +979,4 @@ protected static function convertFormValueDataTypes(array $values) {
     return $values;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      // Load the service required to construct this class.
-      $container->get('config.factory'),
-      $container->get('current_user'),
-      $container->get('module_handler')
-    );
-  }
-
 }
diff --git a/web/modules/google_analytics/src/GoogleAnalitycsInterface.php b/web/modules/google_analytics/src/GoogleAnalitycsInterface.php
deleted file mode 100644
index 0c98290328..0000000000
--- a/web/modules/google_analytics/src/GoogleAnalitycsInterface.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-namespace Drupal\google_analytics;
-
-/**
- * Provides an interface.
- */
-interface GoogleAnalitycsInterface {
-
-  /**
-   * Define the default file extension list that should be tracked as download.
-   */
-  const GOOGLE_ANALYTICS_TRACKFILES_EXTENSIONS = '7z|aac|arc|arj|asf|asx|avi|bin|csv|doc(x|m)?|dot(x|m)?|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mp(2|3|4|e?g)|mov(ie)?|msi|msp|pdf|phps|png|ppt(x|m)?|pot(x|m)?|pps(x|m)?|ppam|sld(x|m)?|thmx|qtm?|ra(m|r)?|sea|sit|tar|tgz|torrent|txt|wav|wma|wmv|wpd|xls(x|m|b)?|xlt(x|m)|xlam|xml|z|zip';
-
-}
diff --git a/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsSkipRowIfNotSet.php b/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsSkipRowIfNotSet.php
new file mode 100644
index 0000000000..089d68519e
--- /dev/null
+++ b/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsSkipRowIfNotSet.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\google_analytics\Plugin\migrate\process;
+
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\MigrateExecutableInterface;
+use Drupal\migrate\Row;
+use Drupal\migrate\MigrateSkipRowException;
+
+/**
+ * If the source evaluates to empty, we skip the current row.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "google_analytics_skip_row_if_not_set",
+ *   handle_multiples = TRUE
+ * )
+ */
+class GoogleAnalyticsSkipRowIfNotSet extends ProcessPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
+    if (!isset($value[$this->configuration['module']][$this->configuration['key']])) {
+      throw new MigrateSkipRowException();
+    }
+    return $value[$this->configuration['module']][$this->configuration['key']];
+  }
+
+}
diff --git a/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsVisibilityPages.php b/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsVisibilityPages.php
index 8374c5520d..f7986db9ce 100644
--- a/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsVisibilityPages.php
+++ b/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsVisibilityPages.php
@@ -29,8 +29,6 @@ class GoogleAnalyticsVisibilityPages extends ProcessPluginBase implements Contai
   protected $moduleHandler;
 
   /**
-   * The migration process plugin.
-   *
    * The migration process plugin, configured for lookups in the d6_user_role
    * and d7_user_role migrations.
    *
diff --git a/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsVisibilityRoles.php b/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsVisibilityRoles.php
index 2fe62b405c..6d6dab7f4f 100644
--- a/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsVisibilityRoles.php
+++ b/web/modules/google_analytics/src/Plugin/migrate/process/GoogleAnalyticsVisibilityRoles.php
@@ -28,8 +28,6 @@ class GoogleAnalyticsVisibilityRoles extends ProcessPluginBase implements Contai
   protected $moduleHandler;
 
   /**
-   * The migration process plugin.
-   *
    * The migration process plugin, configured for lookups in the d6_user_role
    * and d7_user_role migrations.
    *
diff --git a/web/modules/google_analytics/src/Tests/GoogleAnalyticsBasicTest.php b/web/modules/google_analytics/src/Tests/GoogleAnalyticsBasicTest.php
index c5875e2063..04926f183d 100644
--- a/web/modules/google_analytics/src/Tests/GoogleAnalyticsBasicTest.php
+++ b/web/modules/google_analytics/src/Tests/GoogleAnalyticsBasicTest.php
@@ -82,7 +82,7 @@ public function testGoogleAnalyticsConfiguration() {
     $this->assertFieldByName('google_analytics_codesnippet_create');
     $this->assertFieldByName('google_analytics_codesnippet_before');
     $this->assertFieldByName('google_analytics_codesnippet_after');
-    $this->assertNoFieldByXPath("//textarea[@name='google_analytics_codesnippet_create' and @disabled='disabled']", NULL, '"Parameters" field is enabled.');
+    $this->assertNoFieldByXPath("//textarea[@name='google_analytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.');
     $this->assertNoFieldByXPath("//textarea[@name='google_analytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is enabled.');
     $this->assertNoFieldByXPath("//textarea[@name='google_analytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is enabled.');
 
@@ -90,11 +90,11 @@ public function testGoogleAnalyticsConfiguration() {
     $this->drupalLogin($this->noSnippetUser);
     $this->drupalGet('admin/config/system/google-analytics');
 
-    // User should *not* have access to snippets, but parameters field.
+    // User should *not* have access to snippets, but create fields.
     $this->assertFieldByName('google_analytics_codesnippet_create');
     $this->assertFieldByName('google_analytics_codesnippet_before');
     $this->assertFieldByName('google_analytics_codesnippet_after');
-    $this->assertNoFieldByXPath("//textarea[@name='google_analytics_codesnippet_create' and @disabled='disabled']", NULL, '"Parameters" field is enabled.');
+    $this->assertNoFieldByXPath("//textarea[@name='google_analytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.');
     $this->assertFieldByXPath("//textarea[@name='google_analytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is disabled.');
     $this->assertFieldByXPath("//textarea[@name='google_analytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is disabled.');
   }
@@ -119,7 +119,7 @@ public function testGoogleAnalyticsPageVisibility() {
     // Verify that no tracking code is embedded into the webpage; if there is
     // only the module installed, but UA code not configured. See #2246991.
     $this->drupalGet('');
-    $this->assertNoRaw('https://www.googletagmanager.com/gtag/js?id=', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed without UA code configured.');
+    $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed without UA code configured.');
 
     $ua_code = 'UA-123456-1';
     $this->config('google_analytics.settings')->set('account', $ua_code)->save();
@@ -133,14 +133,14 @@ public function testGoogleAnalyticsPageVisibility() {
 
     // Check tracking code visibility.
     $this->drupalGet('');
-    $this->assertRaw('gtag("config", "' . $ua_code . '"', '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed for authenticated users.');
+    $this->assertRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed for authenticated users.');
 
     // Test whether tracking code is not included on pages to omit.
     $this->drupalGet('admin');
     $this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin page.');
     $this->drupalGet('admin/config/system/google-analytics');
     // Checking for tracking URI here, as $ua_code is displayed in the form.
-    $this->assertNoRaw('https://www.googletagmanager.com/gtag/js?id=', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin subpage.');
+    $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is not displayed on admin subpage.');
 
     // Test whether tracking code display is properly flipped.
     $this->config('google_analytics.settings')->set('visibility.request_path_mode', 1)->save();
@@ -148,7 +148,7 @@ public function testGoogleAnalyticsPageVisibility() {
     $this->assertRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin page.');
     $this->drupalGet('admin/config/system/google-analytics');
     // Checking for tracking URI here, as $ua_code is displayed in the form.
-    $this->assertRaw('https://www.googletagmanager.com/gtag/js?id=', '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin subpage.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPageVisibility]: Tracking code is displayed on admin subpage.');
     $this->drupalGet('');
     $this->assertNoRaw($ua_code, '[testGoogleAnalyticsPageVisibility]: Tracking code is NOT displayed on front page.');
 
@@ -161,6 +161,18 @@ public function testGoogleAnalyticsPageVisibility() {
     $this->config('google_analytics.settings')->set('visibility.request_path_mode', 0)->save();
     // Enable tracking code for all user roles.
     $this->config('google_analytics.settings')->set('visibility.user_role_roles', [])->save();
+
+    $base_path = base_path();
+
+    // Test whether 403 forbidden tracking code is shown if user has no access.
+    $this->drupalGet('admin');
+    $this->assertResponse(403);
+    $this->assertRaw($base_path . '403.html', '[testGoogleAnalyticsPageVisibility]: 403 Forbidden tracking code shown if user has no access.');
+
+    // Test whether 404 not found tracking code is shown on non-existent pages.
+    $this->drupalGet($this->randomMachineName(64));
+    $this->assertResponse(404);
+    $this->assertRaw($base_path . '404.html', '[testGoogleAnalyticsPageVisibility]: 404 Not Found tracking code shown on non-existent page.');
   }
 
   /**
@@ -177,76 +189,75 @@ public function testGoogleAnalyticsTrackingCode() {
 
     /* Sample JS code as added to page:
     <script type="text/javascript" src="/sites/all/modules/google_analytics/google_analytics.js?w"></script>
-    <!-- Global Site Tag (gtag.js) - Google Analytics -->
-    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-123456-7"></script>
     <script>
-    window.dataLayer = window.dataLayer || [];
-    function gtag(){dataLayer.push(arguments)};
-    gtag('js', new Date());
-    gtag('config', 'UA-123456-7');
+    (function(i,s,o,g,r,a,m){
+    i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){
+    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+    })(window,document,"script","https://www.google-analytics.com/analytics.js","ga");
+    ga('create', 'UA-123456-7');
+    ga('send', 'pageview');
     </script>
+    <!-- End Google Analytics -->
      */
 
     // Test whether tracking code uses latest JS.
     $this->config('google_analytics.settings')->set('cache', 0)->save();
     $this->drupalGet('');
-    $this->assertRaw('<script async src="https://www.googletagmanager.com/gtag/js?id=' . $ua_code . '"></script>');
-    $this->assertRaw('window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments)};gtag("js", new Date());');
-    $this->assertRaw('"google_analytics":{"account":"' . $ua_code . '"');
-
-    // Enable anonymizing of IP addresses.
-    $this->config('google_analytics.settings')->set('privacy.anonymizeip', 1)->save();
-    $this->drupalGet('');
-    $this->assertRaw('"anonymize_ip":true', '[testGoogleAnalyticsTrackingCode]: Anonymize visitors IP address found on frontpage.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Latest tracking code used.');
 
     // Test whether anonymize visitors IP address feature has been enabled.
     $this->config('google_analytics.settings')->set('privacy.anonymizeip', 0)->save();
     $this->drupalGet('');
-    $this->assertNoRaw('"anonymize_ip":true', '[testGoogleAnalyticsTrackingCode]: Anonymize visitors IP address not found on frontpage.');
+    $this->assertNoRaw('ga("set", "anonymizeIp", true);', '[testGoogleAnalyticsTrackingCode]: Anonymize visitors IP address not found on frontpage.');
+    // Enable anonymizing of IP addresses.
+    $this->config('google_analytics.settings')->set('privacy.anonymizeip', 1)->save();
+    $this->drupalGet('');
+    $this->assertRaw('ga("set", "anonymizeIp", true);', '[testGoogleAnalyticsTrackingCode]: Anonymize visitors IP address found on frontpage.');
 
     // Test if track Enhanced Link Attribution is enabled.
     $this->config('google_analytics.settings')->set('track.linkid', 1)->save();
     $this->drupalGet('');
-    $this->assertRaw('"link_attribution":true', '[testGoogleAnalyticsTrackingCode]: Tracking code for Enhanced Link Attribution is enabled.');
+    $this->assertRaw('ga("require", "linkid", "linkid.js");', '[testGoogleAnalyticsTrackingCode]: Tracking code for Enhanced Link Attribution is enabled.');
 
     // Test if track Enhanced Link Attribution is disabled.
     $this->config('google_analytics.settings')->set('track.linkid', 0)->save();
     $this->drupalGet('');
-    $this->assertNoRaw('"link_attribution":true', '[testGoogleAnalyticsTrackingCode]: Tracking code for Enhanced Link Attribution is not enabled.');
+    $this->assertNoRaw('ga("require", "linkid", "linkid.js");', '[testGoogleAnalyticsTrackingCode]: Tracking code for Enhanced Link Attribution is not enabled.');
+
+    // Test if tracking of url fragments is enabled.
+    $this->config('google_analytics.settings')->set('track.urlfragments', 1)->save();
+    $this->drupalGet('');
+    $this->assertRaw('ga("set", "page", location.pathname + location.search + location.hash);', '[testGoogleAnalyticsTrackingCode]: Tracking code for url fragments is enabled.');
+
+    // Test if tracking of url fragments is disabled.
+    $this->config('google_analytics.settings')->set('track.urlfragments', 0)->save();
+    $this->drupalGet('');
+    $this->assertNoRaw('ga("set", "page", location.pathname + location.search + location.hash);', '[testGoogleAnalyticsTrackingCode]: Tracking code for url fragments is not enabled.');
 
     // Test if tracking of User ID is enabled.
     $this->config('google_analytics.settings')->set('track.userid', 1)->save();
     $this->drupalGet('');
-    $this->assertRaw('"user_id":"', '[testGoogleAnalyticsTrackingCode]: Tracking code for User ID is enabled.');
+    $this->assertRaw(', {"cookieDomain":"auto","userId":"', '[testGoogleAnalyticsTrackingCode]: Tracking code for User ID is enabled.');
 
     // Test if tracking of User ID is disabled.
     $this->config('google_analytics.settings')->set('track.userid', 0)->save();
     $this->drupalGet('');
-    $this->assertNoRaw('"user_id":"', '[testGoogleAnalyticsTrackingCode]: Tracking code for User ID is disabled.');
-
-    // Test if track display features is disabled.
-    $this->config('google_analytics.settings')->set('track.displayfeatures', 0)->save();
-    $this->drupalGet('');
-    $this->assertRaw('"allow_ad_personalization_signals":false', '[testGoogleAnalyticsTrackingCode]: Tracking code for display features is not enabled.');
+    $this->assertNoRaw(', {"cookieDomain":"auto","userId":"', '[testGoogleAnalyticsTrackingCode]: Tracking code for User ID is disabled.');
 
     // Test if track display features is enabled.
     $this->config('google_analytics.settings')->set('track.displayfeatures', 1)->save();
     $this->drupalGet('');
-    $this->assertNoRaw('"allow_ad_personalization_signals":false', '[testGoogleAnalyticsTrackingCode]: Tracking code for display features is enabled.');
+    $this->assertRaw('ga("require", "displayfeatures");', '[testGoogleAnalyticsTrackingCode]: Tracking code for display features is enabled.');
 
-    // Test if tracking of url fragments is enabled.
-    $this->config('google_analytics.settings')->set('track.urlfragments', 1)->save();
-    $this->drupalGet('');
-    $this->assertRaw('"page_path":location.pathname + location.search + location.hash});', '[testGoogleAnalyticsTrackingCode]: Tracking code for url fragments is enabled.');
-
-    // Test if tracking of url fragments is disabled.
-    $this->config('google_analytics.settings')->set('track.urlfragments', 0)->save();
+    // Test if track display features is disabled.
+    $this->config('google_analytics.settings')->set('track.displayfeatures', 0)->save();
     $this->drupalGet('');
-    $this->assertNoRaw('"page_path":location.pathname + location.search + location.hash});', '[testGoogleAnalyticsTrackingCode]: Tracking code for url fragments is not enabled.');
+    $this->assertNoRaw('ga("require", "displayfeatures");', '[testGoogleAnalyticsTrackingCode]: Tracking code for display features is not enabled.');
 
     // Test whether single domain tracking is active.
     $this->drupalGet('');
-    $this->assertRaw('{"groups":"default"}', '[testGoogleAnalyticsTrackingCode]: Single domain tracking is active.');
+    $this->assertRaw('{"cookieDomain":"auto"}', '[testGoogleAnalyticsTrackingCode]: Single domain tracking is active.');
 
     // Enable "One domain with multiple subdomains".
     $this->config('google_analytics.settings')->set('domain_mode', 1)->save();
@@ -257,11 +268,11 @@ function gtag(){dataLayer.push(arguments)};
     // reliable.
     global $cookie_domain;
     if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
-      $this->assertRaw('"cookie_domain":"' . $cookie_domain . '"', '[testGoogleAnalyticsTrackingCode]: One domain with multiple subdomains is active on real host.');
+      $this->assertRaw('{"cookieDomain":"' . $cookie_domain . '"}', '[testGoogleAnalyticsTrackingCode]: One domain with multiple subdomains is active on real host.');
     }
     else {
       // Special cases, Localhost and IP addresses don't show 'cookieDomain'.
-      $this->assertNoRaw('"cookie_domain":"' . $cookie_domain . '"', '[testGoogleAnalyticsTrackingCode]: One domain with multiple subdomains may be active on localhost (test result is not reliable).');
+      $this->assertNoRaw('{"cookieDomain":"' . $cookie_domain . '"}', '[testGoogleAnalyticsTrackingCode]: One domain with multiple subdomains may be active on localhost (test result is not reliable).');
     }
 
     // Enable "Multiple top-level domains" tracking.
@@ -270,8 +281,9 @@ function gtag(){dataLayer.push(arguments)};
       ->set('cross_domains', "www.example.com\nwww.example.net")
       ->save();
     $this->drupalGet('');
-    $this->assertRaw('gtag("config", "' . $ua_code . '", {"groups":"default","linker":', '[testGoogleAnalyticsTrackingCode]: "linker" has been found. Cross domain tracking is active.');
-    $this->assertRaw('gtag("config", "' . $ua_code . '", {"groups":"default","linker":{"domains":["www.example.com","www.example.net"]}});', '[testGoogleAnalyticsTrackingCode]: "domains" has been found. Cross domain tracking is active.');
+    $this->assertRaw('ga("create", "' . $ua_code . '", {"cookieDomain":"auto","allowLinker":true', '[testGoogleAnalyticsTrackingCode]: "allowLinker" has been found. Cross domain tracking is active.');
+    $this->assertRaw('ga("require", "linker");', '[testGoogleAnalyticsTrackingCode]: Require linker has been found. Cross domain tracking is active.');
+    $this->assertRaw('ga("linker:autoLink", ["www.example.com","www.example.net"]);', '[testGoogleAnalyticsTrackingCode]: "linker:autoLink" has been found. Cross domain tracking is active.');
     $this->assertRaw('"trackDomainMode":2,', '[testGoogleAnalyticsTrackingCode]: Domain mode value is of type integer.');
     $this->assertRaw('"trackCrossDomains":["www.example.com","www.example.net"]', '[testGoogleAnalyticsTrackingCode]: Cross domain tracking with www.example.com and www.example.net is active.');
     $this->config('google_analytics.settings')->set('domain_mode', 0)->save();
@@ -279,8 +291,7 @@ function gtag(){dataLayer.push(arguments)};
     // Test whether debugging script has been enabled.
     $this->config('google_analytics.settings')->set('debug', 1)->save();
     $this->drupalGet('');
-    // @FIXME
-    //$this->assertRaw('https://www.google-analytics.com/analytics_debug.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been enabled.');
+    $this->assertRaw('https://www.google-analytics.com/analytics_debug.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been enabled.');
 
     // Check if text and link is shown on 'Status Reports' page.
     // Requires 'administer site configuration' permission.
@@ -290,25 +301,26 @@ function gtag(){dataLayer.push(arguments)};
     // Test whether debugging script has been disabled.
     $this->config('google_analytics.settings')->set('debug', 0)->save();
     $this->drupalGet('');
-    $this->assertRaw('https://www.googletagmanager.com/gtag/js?id=', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been disabled.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsTrackingCode]: Google debugging script has been disabled.');
 
     // Test whether the CREATE and BEFORE and AFTER code is added to the
     // tracking code.
-    $codesnippet_parameters = [
-      'cookie_domain' => 'foo.example.com',
-      'cookie_name' => 'myNewName',
-      'cookie_expires' => 20000,
-      'sample_rate' => 4.3,
+    $codesnippet_create = [
+      'cookieDomain' => 'foo.example.com',
+      'cookieName' => 'myNewName',
+      'cookieExpires' => 20000,
+      'allowAnchor' => TRUE,
+      'sampleRate' => 4.3,
     ];
     $this->config('google_analytics.settings')
-      ->set('codesnippet.create', $codesnippet_parameters)
-      ->set('codesnippet.before', 'gtag("set", {"currency":"USD"});')
-      ->set('codesnippet.after', 'gtag("config", "UA-123456-3", {"groups":"default"});if(1 == 1 && 2 < 3 && 2 > 1){console.log("Google Analytics: Custom condition works.");}')
+      ->set('codesnippet.create', $codesnippet_create)
+      ->set('codesnippet.before', 'ga("set", "forceSSL", true);')
+      ->set('codesnippet.after', 'ga("create", "UA-123456-3", {"name": "newTracker"});if(1 == 1 && 2 < 3 && 2 > 1){console.log("Google Analytics: Custom condition works.");}ga("newTracker.send", "pageview");')
       ->save();
     $this->drupalGet('');
-    $this->assertRaw('gtag("config", "' . $ua_code . '", {"groups":"default","cookie_domain":"foo.example.com","cookie_name":"myNewName","cookie_expires":20000,"sample_rate":4.3});', '[testGoogleAnalyticsTrackingCode]: Config parameters have been found.');
-    $this->assertRaw('gtag("set", {"currency":"USD"});', '[testGoogleAnalyticsTrackingCode]: Before codesnippet has been found.');
-    $this->assertRaw('gtag("config", "UA-123456-3", {"groups":"default"});', '[testGoogleAnalyticsTrackingCode]: After codesnippet custom UA code has been found.');
+    $this->assertRaw('ga("create", "' . $ua_code . '", {"cookieDomain":"foo.example.com","cookieName":"myNewName","cookieExpires":20000,"allowAnchor":true,"sampleRate":4.3});', '[testGoogleAnalyticsTrackingCode]: Create only fields have been found.');
+    $this->assertRaw('ga("set", "forceSSL", true);', '[testGoogleAnalyticsTrackingCode]: Before codesnippet will force http pages to also send all beacons using https.');
+    $this->assertRaw('ga("create", "UA-123456-3", {"name": "newTracker"});', '[testGoogleAnalyticsTrackingCode]: After codesnippet with "newTracker" tracker has been found.');
     $this->assertRaw('if(1 == 1 && 2 < 3 && 2 > 1){console.log("Google Analytics: Custom condition works.");}', '[testGoogleAnalyticsTrackingCode]: JavaScript code is not HTML escaped.');
   }
 
diff --git a/web/modules/google_analytics/src/Tests/GoogleAnalyticsCustomDimensionsAndMetricsTest.php b/web/modules/google_analytics/src/Tests/GoogleAnalyticsCustomDimensionsAndMetricsTest.php
index db7b5b9376..9404debc01 100644
--- a/web/modules/google_analytics/src/Tests/GoogleAnalyticsCustomDimensionsAndMetricsTest.php
+++ b/web/modules/google_analytics/src/Tests/GoogleAnalyticsCustomDimensionsAndMetricsTest.php
@@ -59,41 +59,31 @@ public function testGoogleAnalyticsCustomDimensions() {
     $google_analytics_custom_dimension = [
       1 => [
         'index' => 1,
-        'name' => 'bar1',
         'value' => 'Bar 1',
       ],
       2 => [
         'index' => 2,
-        'name' => 'bar2',
         'value' => 'Bar 2',
       ],
       3 => [
         'index' => 3,
-        'name' => 'bar2',
         'value' => 'Bar 3',
       ],
       4 => [
         'index' => 4,
-        'name' => 'bar4',
         'value' => 'Bar 4',
       ],
       5 => [
         'index' => 5,
-        'name' => 'bar5',
         'value' => 'Bar 5',
       ],
     ];
     $this->config('google_analytics.settings')->set('custom.dimension', $google_analytics_custom_dimension)->save();
     $this->drupalGet('');
 
-    $custom_map = [];
-    $custom_vars = [];
     foreach ($google_analytics_custom_dimension as $dimension) {
-      $custom_map['custom_map']['dimension' . $dimension['index']] = $dimension['name'];
-      $custom_vars[$dimension['name']] = $dimension['value'];
+      $this->assertRaw('ga("set", ' . Json::encode('dimension' . $dimension['index']) . ', ' . Json::encode($dimension['value']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Dimension #' . $dimension['index'] . ' is shown.');
     }
-    $this->assertRaw('gtag("config", ' . Json::encode($ua_code) . ', ' . Json::encode($custom_map) . ');');
-    $this->assertRaw('gtag("event", "custom", ' . Json::encode($custom_vars) . ');');
 
     // Test whether tokens are replaced in custom dimension values.
     $site_slogan = $this->randomMachineName(16);
@@ -102,40 +92,33 @@ public function testGoogleAnalyticsCustomDimensions() {
     $google_analytics_custom_dimension = [
       1 => [
         'index' => 1,
-        'name' => 'site_slogan',
         'value' => 'Value: [site:slogan]',
       ],
       2 => [
         'index' => 2,
-        'name' => 'machine_name',
         'value' => $this->randomMachineName(16),
       ],
       3 => [
         'index' => 3,
-        'name' => 'foo3',
         'value' => '',
       ],
       // #2300701: Custom dimensions and custom metrics not outputed on zero
       // value.
       4 => [
         'index' => 4,
-        'name' => 'bar4',
         'value' => '0',
       ],
       5 => [
         'index' => 5,
-        'name' => 'node_type',
         'value' => '[node:type]',
       ],
       // Test google_analytics_tokens().
       6 => [
         'index' => 6,
-        'name' => 'current_user_role_names',
         'value' => '[current-user:role-names]',
       ],
       7 => [
         'index' => 7,
-        'name' => 'current_user_role_ids',
         'value' => '[current-user:role-ids]',
       ],
     ];
@@ -144,26 +127,18 @@ public function testGoogleAnalyticsCustomDimensions() {
 
     // Test on frontpage.
     $this->drupalGet('');
-    $this->assertRaw(Json::encode('dimension1') . ':' . Json::encode($google_analytics_custom_dimension['1']['name']));
-    $this->assertRaw(Json::encode($google_analytics_custom_dimension['1']['name']) . ':' . Json::encode("Value: $site_slogan"));
-    $this->assertRaw(Json::encode('dimension2') . ':' . Json::encode($google_analytics_custom_dimension['2']['name']));
-    $this->assertRaw(Json::encode($google_analytics_custom_dimension['2']['name']) . ':' . Json::encode($google_analytics_custom_dimension['2']['value']));
-    $this->assertNoRaw(Json::encode('dimension3') . ':' . Json::encode($google_analytics_custom_dimension['3']['name']));
-    $this->assertNoRaw(Json::encode($google_analytics_custom_dimension['3']['name']) . ':' . Json::encode(''));
-    $this->assertRaw(Json::encode('dimension4') . ':' . Json::encode($google_analytics_custom_dimension['4']['name']));
-    $this->assertRaw(Json::encode($google_analytics_custom_dimension['4']['name']) . ':' . Json::encode('0'));
-    $this->assertNoRaw(Json::encode('dimension5') . ':' . Json::encode($google_analytics_custom_dimension['5']['name']));
-    $this->assertNoRaw(Json::encode($google_analytics_custom_dimension['5']['name']) . ':' . Json::encode('article'));
-    $this->assertRaw(Json::encode('dimension6') . ':' . Json::encode($google_analytics_custom_dimension['6']['name']));
-    $this->assertRaw(Json::encode($google_analytics_custom_dimension['6']['name']) . ':' . Json::encode(implode(',', \Drupal::currentUser()->getRoles())));
-    $this->assertRaw(Json::encode('dimension7') . ':' . Json::encode($google_analytics_custom_dimension['7']['name']));
-    $this->assertRaw(Json::encode($google_analytics_custom_dimension['7']['name']) . ':' . Json::encode(implode(',', array_keys(\Drupal::currentUser()->getRoles()))));
+    $this->assertRaw('ga("set", ' . Json::encode('dimension1') . ', ' . Json::encode("Value: $site_slogan") . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Tokens have been replaced in dimension value.');
+    $this->assertRaw('ga("set", ' . Json::encode('dimension2') . ', ' . Json::encode($google_analytics_custom_dimension['2']['value']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Random value is shown.');
+    $this->assertNoRaw('ga("set", ' . Json::encode('dimension3') . ', ' . Json::encode('') . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Empty value is not shown.');
+    $this->assertRaw('ga("set", ' . Json::encode('dimension4') . ', ' . Json::encode('0') . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Value 0 is shown.');
+    $this->assertNoRaw('ga("set", ' . Json::encode('dimension5') . ', ' . Json::encode('article') . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Node tokens are shown.');
+    $this->assertRaw('ga("set", ' . Json::encode('dimension6') . ', ' . Json::encode(implode(',', \Drupal::currentUser()->getRoles())) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: List of roles shown.');
+    $this->assertRaw('ga("set", ' . Json::encode('dimension7') . ', ' . Json::encode(implode(',', array_keys(\Drupal::currentUser()->getRoles()))) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: List of role IDs shown.');
 
     // Test on a node.
     $this->drupalGet('node/' . $node->id());
     $this->assertText($node->getTitle());
-    $this->assertRaw(Json::encode('dimension5') . ':' . Json::encode($google_analytics_custom_dimension['5']['name']));
-    $this->assertRaw(Json::encode($google_analytics_custom_dimension['5']['name']) . ':' . Json::encode('article'));
+    $this->assertRaw('ga("set", ' . Json::encode('dimension5') . ', ' . Json::encode('article') . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Node tokens are shown.');
   }
 
   /**
@@ -177,27 +152,22 @@ public function testGoogleAnalyticsCustomMetrics() {
     $google_analytics_custom_metric = [
       1 => [
         'index' => 1,
-        'name' => 'foo1',
         'value' => '6',
       ],
       2 => [
         'index' => 2,
-        'name' => 'foo2',
         'value' => '8000',
       ],
       3 => [
         'index' => 3,
-        'name' => 'foo3',
         'value' => '7.8654',
       ],
       4 => [
         'index' => 4,
-        'name' => 'foo4',
         'value' => '1123.4',
       ],
       5 => [
         'index' => 5,
-        'name' => 'foo5',
         'value' => '5,67',
       ],
     ];
@@ -205,37 +175,28 @@ public function testGoogleAnalyticsCustomMetrics() {
     $this->config('google_analytics.settings')->set('custom.metric', $google_analytics_custom_metric)->save();
     $this->drupalGet('');
 
-    $custom_map = [];
-    $custom_vars = [];
     foreach ($google_analytics_custom_metric as $metric) {
-      $custom_map['custom_map']['metric' . $metric['index']] = $metric['name'];
-      $custom_vars[$metric['name']] = (float) $metric['value'];
+      $this->assertRaw('ga("set", ' . Json::encode('metric' . $metric['index']) . ', ' . Json::encode((float) $metric['value']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Metric #' . $metric['index'] . ' is shown.');
     }
-    $this->assertRaw('gtag("config", ' . Json::encode($ua_code) . ', ' . Json::encode($custom_map) . ');');
-    $this->assertRaw('gtag("event", "custom", ' . Json::encode($custom_vars) . ');');
 
     // Test whether tokens are replaced in custom metric values.
     $google_analytics_custom_metric = [
       1 => [
         'index' => 1,
-        'name' => 'bar1',
         'value' => '[current-user:roles:count]',
       ],
       2 => [
         'index' => 2,
-        'name' => 'bar2',
         'value' => mt_rand(),
       ],
       3 => [
         'index' => 3,
-        'name' => 'bar3',
         'value' => '',
       ],
       // #2300701: Custom dimensions and custom metrics not outputed on zero
       // value.
       4 => [
         'index' => 4,
-        'name' => 'bar4',
         'value' => '0',
       ],
     ];
@@ -243,14 +204,10 @@ public function testGoogleAnalyticsCustomMetrics() {
     $this->verbose('<pre>' . print_r($google_analytics_custom_metric, TRUE) . '</pre>');
 
     $this->drupalGet('');
-    $this->assertRaw(Json::encode('metric1') . ':' . Json::encode($google_analytics_custom_metric['1']['name']));
-    $this->assertRaw(Json::encode($google_analytics_custom_metric['1']['name']) . ':');
-    $this->assertRaw(Json::encode('metric2') . ':' . Json::encode($google_analytics_custom_metric['2']['name']));
-    $this->assertRaw(Json::encode($google_analytics_custom_metric['2']['name']) . ':' . Json::encode($google_analytics_custom_metric['2']['value']));
-    $this->assertNoRaw(Json::encode('metric3') . ':' . Json::encode($google_analytics_custom_metric['3']['name']));
-    $this->assertNoRaw(Json::encode($google_analytics_custom_metric['3']['name']) . ':' . Json::encode(''));
-    $this->assertRaw(Json::encode('metric4') . ':' . Json::encode($google_analytics_custom_metric['4']['name']));
-    $this->assertRaw(Json::encode($google_analytics_custom_metric['4']['name']) . ':' . Json::encode(0));
+    $this->assertRaw('ga("set", ' . Json::encode('metric1') . ', ', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Tokens have been replaced in metric value.');
+    $this->assertRaw('ga("set", ' . Json::encode('metric2') . ', ' . Json::encode($google_analytics_custom_metric['2']['value']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Random value is shown.');
+    $this->assertNoRaw('ga("set", ' . Json::encode('metric3') . ', ' . Json::encode('') . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Empty value is not shown.');
+    $this->assertRaw('ga("set", ' . Json::encode('metric4') . ', ' . Json::encode(0) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Value 0 is shown.');
   }
 
   /**
@@ -261,15 +218,10 @@ public function testGoogleAnalyticsCustomDimensionsTokenFormValidation() {
 
     // Check form validation.
     $edit['google_analytics_account'] = $ua_code;
-    $edit['google_analytics_custom_dimension[indexes][1][name]'] = 'current_user_name';
     $edit['google_analytics_custom_dimension[indexes][1][value]'] = '[current-user:name]';
-    $edit['google_analytics_custom_dimension[indexes][2][name]'] = 'current_user_edit_url';
     $edit['google_analytics_custom_dimension[indexes][2][value]'] = '[current-user:edit-url]';
-    $edit['google_analytics_custom_dimension[indexes][3][name]'] = 'user_name';
     $edit['google_analytics_custom_dimension[indexes][3][value]'] = '[user:name]';
-    $edit['google_analytics_custom_dimension[indexes][4][name]'] = 'term_name';
     $edit['google_analytics_custom_dimension[indexes][4][value]'] = '[term:name]';
-    $edit['google_analytics_custom_dimension[indexes][5][name]'] = 'term_tid';
     $edit['google_analytics_custom_dimension[indexes][5][value]'] = '[term:tid]';
 
     $this->drupalPostForm('admin/config/system/google-analytics', $edit, t('Save configuration'));
diff --git a/web/modules/google_analytics/src/Tests/GoogleAnalyticsCustomUrls.php b/web/modules/google_analytics/src/Tests/GoogleAnalyticsCustomUrls.php
index 139a23031c..cbf14a7841 100644
--- a/web/modules/google_analytics/src/Tests/GoogleAnalyticsCustomUrls.php
+++ b/web/modules/google_analytics/src/Tests/GoogleAnalyticsCustomUrls.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\google_analytics\Tests;
 
-use Drupal\Component\Serialization\Json;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -39,33 +39,19 @@ protected function setUp() {
   /**
    * Tests if user password page urls are overridden.
    */
-  public function testGoogleAnalyticsCustomUrls() {
+  public function testGoogleAnalyticsUserPasswordPage() {
     $base_path = base_path();
     $ua_code = 'UA-123456-1';
-    $this->config('google_analytics.settings')
-      ->set('account', $ua_code)
-      ->set('privacy.anonymizeip', 0)
-      ->set('track.displayfeatures', 1)
-      ->save();
+    $this->config('google_analytics.settings')->set('account', $ua_code)->save();
 
     $this->drupalGet('user/password', ['query' => ['name' => 'foo']]);
-    $this->assertRaw('gtag("config", ' . Json::encode($ua_code) . ', {"groups":"default","page_path":"' . $base_path . 'user/password"});');
+    $this->assertRaw('ga("set", "page", "' . $base_path . 'user/password"');
 
     $this->drupalGet('user/password', ['query' => ['name' => 'foo@example.com']]);
-    $this->assertRaw('gtag("config", ' . Json::encode($ua_code) . ', {"groups":"default","page_path":"' . $base_path . 'user/password"});');
+    $this->assertRaw('ga("set", "page", "' . $base_path . 'user/password"');
 
     $this->drupalGet('user/password');
-    $this->assertNoRaw('"page_path":"' . $base_path . 'user/password"});', '[testGoogleAnalyticsCustomUrls]: Custom url not set.');
-
-    // Test whether 403 forbidden tracking code is shown if user has no access.
-    $this->drupalGet('admin');
-    $this->assertResponse(403);
-    $this->assertRaw($base_path . '403.html', '[testGoogleAnalyticsCustomUrls]: 403 Forbidden tracking code shown if user has no access.');
-
-    // Test whether 404 not found tracking code is shown on non-existent pages.
-    $this->drupalGet($this->randomMachineName(64));
-    $this->assertResponse(404);
-    $this->assertRaw($base_path . '404.html', '[testGoogleAnalyticsCustomUrls]: 404 Not Found tracking code shown on non-existent page.');
+    $this->assertNoRaw('ga("set", "page",', '[testGoogleAnalyticsCustomUrls]: Custom url not set.');
   }
 
 }
diff --git a/web/modules/google_analytics/src/Tests/GoogleAnalyticsJavaScriptTest.js b/web/modules/google_analytics/src/Tests/GoogleAnalyticsJavaScriptTest.js
index 45f8d52a47..ded59bf5c9 100644
--- a/web/modules/google_analytics/src/Tests/GoogleAnalyticsJavaScriptTest.js
+++ b/web/modules/google_analytics/src/Tests/GoogleAnalyticsJavaScriptTest.js
@@ -81,7 +81,7 @@
   Drupal.google_analytics.test.assertTrue(Drupal.google_analytics.isInternal(base_url + drupalSettings.path.baseUrl + 'node/1?foo=bar'), "Link '" + base_url + drupalSettings.path.baseUrl + "node/1?foo=bar' has been detected as internal link.");
   Drupal.google_analytics.test.assertTrue(Drupal.google_analytics.isInternal(base_url + drupalSettings.path.baseUrl + 'node/1?foo=bar#foo'), "Link '" + base_url + drupalSettings.path.baseUrl + "node/1?foo=bar#foo' has been detected as internal link.");
   Drupal.google_analytics.test.assertTrue(Drupal.google_analytics.isInternal(base_url + drupalSettings.path.baseUrl + 'go/foo'), "Link '" + base_url + drupalSettings.path.baseUrl + "go/foo' has been detected as internal link.");
-  Drupal.google_analytics.test.assertFalse(Drupal.google_analytics.isInternal('https://example.com/node/3'), "Link 'https://example.com/node/3' has been detected as external link.");
+  Drupal.google_analytics.test.assertFalse(Drupal.google_analytics.isInternal('http://example.com/node/3'), "Link 'http://example.com/node/3' has been detected as external link.");
   console.groupEnd();
 
   console.group("Test 'isInternalSpecial':");
@@ -90,11 +90,9 @@
   console.groupEnd();
 
   console.group("Test 'getPageUrl':");
-  Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(window.location.href), "Absolute internal URL '" + base_path + "' has been extracted from full qualified url '" + window.location.href + "'.");
-  Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(base_path), "Absolute internal URL '" + base_path + "' has been extracted from absolute url '" + base_path + "'.");
-  //Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(base_url + drupalSettings.path.baseUrl + 'node/1'), "Absolute internal URL '" + drupalSettings.path.baseUrl + "node/1' has been extracted from full qualified url '" + base_url + base_path + "'.");
-  //Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(drupalSettings.path.baseUrl + 'node/1'), "Absolute internal URL '" + drupalSettings.path.baseUrl + "node/1' has been extracted from absolute url '" + base_path + "'.");
-  Drupal.google_analytics.test.assertSame('https://example.com/node/2', Drupal.google_analytics.getPageUrl('https://example.com/node/2'), "Full qualified external url 'https://example.com/node/2' has been extracted.");
+  Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(base_url + drupalSettings.path.baseUrl + 'node/1'), "Absolute internal URL '" + drupalSettings.path.baseUrl + "node/1' has been extracted from full qualified url '" + base_url + base_path + "'.");
+  Drupal.google_analytics.test.assertSame(base_path, Drupal.google_analytics.getPageUrl(drupalSettings.path.baseUrl + 'node/1'), "Absolute internal URL '" + drupalSettings.path.baseUrl + "node/1' has been extracted from absolute url '" + base_path + "'.");
+  Drupal.google_analytics.test.assertSame('http://example.com/node/2', Drupal.google_analytics.getPageUrl('http://example.com/node/2'), "Full qualified external url 'http://example.com/node/2' has been extracted.");
   Drupal.google_analytics.test.assertSame('//example.com/node/2', Drupal.google_analytics.getPageUrl('//example.com/node/2'), "Full qualified external url '//example.com/node/2' has been extracted.");
   console.groupEnd();
 
@@ -111,9 +109,9 @@
   if (drupalSettings.google_analytics.trackCrossDomains) {
     console.dir(drupalSettings.google_analytics.trackCrossDomains);
     Drupal.google_analytics.test.assertTrue(Drupal.google_analytics.isCrossDomain('example.com', drupalSettings.google_analytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list.");
-    Drupal.google_analytics.test.assertTrue(Drupal.google_analytics.isCrossDomain('example.net', drupalSettings.google_analytics.trackCrossDomains), "URL 'example.net' has been found in cross domain list.");
+    Drupal.google_analytics.test.assertTrue(Drupal.google_analytics.isCrossDomain('example.net', drupalSettings.google_analytics.trackCrossDomains), "URL 'example.com' has been found in cross domain list.");
     Drupal.google_analytics.test.assertFalse(Drupal.google_analytics.isCrossDomain('www.example.com', drupalSettings.google_analytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list.");
-    Drupal.google_analytics.test.assertFalse(Drupal.google_analytics.isCrossDomain('www.example.net', drupalSettings.google_analytics.trackCrossDomains), "URL 'www.example.net' not found in cross domain list.");
+    Drupal.google_analytics.test.assertFalse(Drupal.google_analytics.isCrossDomain('www.example.net', drupalSettings.google_analytics.trackCrossDomains), "URL 'www.example.com' not found in cross domain list.");
   }
   else {
     console.warn('Cross domain tracking is not enabled. Tests skipped.');
diff --git a/web/modules/google_analytics/src/Tests/GoogleAnalyticsPhpFilterTest.php b/web/modules/google_analytics/src/Tests/GoogleAnalyticsPhpFilterTest.php
index ffdcf3f581..df4af7617e 100644
--- a/web/modules/google_analytics/src/Tests/GoogleAnalyticsPhpFilterTest.php
+++ b/web/modules/google_analytics/src/Tests/GoogleAnalyticsPhpFilterTest.php
@@ -63,13 +63,13 @@ public function testGoogleAnalyticsPhpFilter() {
     // Check tracking code visibility.
     $this->config('google_analytics.settings')->set('visibility.request_path_pages', '<?php return TRUE; ?>')->save();
     $this->drupalGet('');
-    $this->assertRaw('https://www.googletagmanager.com/gtag/js?id=', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on frontpage page.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on frontpage page.');
     $this->drupalGet('admin');
-    $this->assertRaw('https://www.googletagmanager.com/gtag/js?id=', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on admin page.');
+    $this->assertRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is displayed on admin page.');
 
     $this->config('google_analytics.settings')->set('visibility.request_path_pages', '<?php return FALSE; ?>')->save();
     $this->drupalGet('');
-    $this->assertNoRaw('https://www.googletagmanager.com/gtag/js?id=', '[testGoogleAnalyticsPhpFilter]: Tracking is not displayed on frontpage page.');
+    $this->assertNoRaw('https://www.google-analytics.com/analytics.js', '[testGoogleAnalyticsPhpFilter]: Tracking is not displayed on frontpage page.');
 
     // Test administration form.
     $this->config('google_analytics.settings')->set('visibility.request_path_pages', '<?php return TRUE; ?>')->save();
diff --git a/web/modules/google_analytics/src/Tests/GoogleAnalyticsSearchTest.php b/web/modules/google_analytics/src/Tests/GoogleAnalyticsSearchTest.php
index 8e30bc5c97..ec6af115b4 100644
--- a/web/modules/google_analytics/src/Tests/GoogleAnalyticsSearchTest.php
+++ b/web/modules/google_analytics/src/Tests/GoogleAnalyticsSearchTest.php
@@ -2,7 +2,6 @@
 
 namespace Drupal\google_analytics\Tests;
 
-use Drupal\Component\Serialization\Json;
 use Drupal\simpletest\WebTestBase;
 
 /**
@@ -45,18 +44,14 @@ protected function setUp() {
    */
   public function testGoogleAnalyticsSearchTracking() {
     $ua_code = 'UA-123456-1';
-    $this->config('google_analytics.settings')
-      ->set('account', $ua_code)
-      ->set('privacy.anonymizeip', 0)
-      ->set('track.displayfeatures', 1)
-      ->save();
+    $this->config('google_analytics.settings')->set('account', $ua_code)->save();
 
     // Check tracking code visibility.
     $this->drupalGet('');
     $this->assertRaw($ua_code, '[testGoogleAnalyticsSearch]: Tracking code is displayed for authenticated users.');
 
     $this->drupalGet('search/node');
-    $this->assertNoRaw('gtag("config", ' . Json::encode($ua_code) . ', {"groups":"default","page_path":"', '[testGoogleAnalyticsSearch]: Custom url not set.');
+    $this->assertNoRaw('ga("set", "page",', '[testGoogleAnalyticsSearch]: Custom url not set.');
 
     // Enable site search support.
     $this->config('google_analytics.settings')->set('track.site_search', 1)->save();
@@ -66,13 +61,14 @@ public function testGoogleAnalyticsSearchTracking() {
     $search['keys'] = $this->randomMachineName(8);
 
     // Create a node to search for.
+    // Create a node.
     $edit = [];
     $edit['title[0][value]'] = 'This is a test title';
     $edit['body[0][value]'] = 'This test content contains ' . $search['keys'] . ' string.';
 
     // Fire a search, it's expected to get 0 results.
     $this->drupalPostForm('search/node', $search, t('Search'));
-    $this->assertRaw('gtag("config", ' . Json::encode($ua_code) . ', {"groups":"default","page_path":(window.google_analytics_search_results) ?', '[testGoogleAnalyticsSearch]: Search results tracker is displayed.');
+    $this->assertRaw('ga("set", "page", (window.google_analytics_search_results) ?', '[testGoogleAnalyticsSearch]: Search results tracker is displayed.');
     $this->assertRaw('window.google_analytics_search_results = 0;', '[testGoogleAnalyticsSearch]: Search yielded no results.');
 
     // Save the node.
@@ -83,7 +79,7 @@ public function testGoogleAnalyticsSearchTracking() {
     $this->cronRun();
 
     $this->drupalPostForm('search/node', $search, t('Search'));
-    $this->assertRaw('gtag("config", ' . Json::encode($ua_code) . ', {"groups":"default","page_path":(window.google_analytics_search_results) ?', '[testGoogleAnalyticsSearch]: Search results tracker is displayed.');
+    $this->assertRaw('ga("set", "page", (window.google_analytics_search_results) ?', '[testGoogleAnalyticsSearch]: Search results tracker is displayed.');
     $this->assertRaw('window.google_analytics_search_results = 1;', '[testGoogleAnalyticsSearch]: One search result found.');
 
     $this->drupalPostForm('node/add/page', $edit, t('Save'));
@@ -93,7 +89,7 @@ public function testGoogleAnalyticsSearchTracking() {
     $this->cronRun();
 
     $this->drupalPostForm('search/node', $search, t('Search'));
-    $this->assertRaw('gtag("config", ' . Json::encode($ua_code) . ', {"groups":"default","page_path":(window.google_analytics_search_results) ?', '[testGoogleAnalyticsSearch]: Search results tracker is displayed.');
+    $this->assertRaw('ga("set", "page", (window.google_analytics_search_results) ?', '[testGoogleAnalyticsSearch]: Search results tracker is displayed.');
     $this->assertRaw('window.google_analytics_search_results = 2;', '[testGoogleAnalyticsSearch]: Two search results found.');
   }
 
diff --git a/web/modules/google_analytics/src/Tests/GoogleAnalyticsStatusMessagesTest.php b/web/modules/google_analytics/src/Tests/GoogleAnalyticsStatusMessagesTest.php
index 25a5771692..2082fccc32 100644
--- a/web/modules/google_analytics/src/Tests/GoogleAnalyticsStatusMessagesTest.php
+++ b/web/modules/google_analytics/src/Tests/GoogleAnalyticsStatusMessagesTest.php
@@ -44,28 +44,24 @@ public function testGoogleAnalyticsStatusMessages() {
     $this->config('google_analytics.settings')->set('track.messages', ['error' => 'error'])->save();
 
     $this->drupalPostForm('user/login', [], t('Log in'));
-    $this->assertRaw('gtag("event", "Error message", {"event_category":"Messages","event_label":"Username field is required."});', '[testGoogleAnalyticsStatusMessages]: Event message "Username field is required." is shown.');
-    $this->assertRaw('gtag("event", "Error message", {"event_category":"Messages","event_label":"Password field is required."});', '[testGoogleAnalyticsStatusMessages]: Event message "Password field is required." is shown.');
+    $this->assertRaw('ga("send", "event", "Messages", "Error message", "Username field is required.");', '[testGoogleAnalyticsStatusMessages]: Event message "Username field is required." is shown.');
+    $this->assertRaw('ga("send", "event", "Messages", "Error message", "Password field is required.");', '[testGoogleAnalyticsStatusMessages]: Event message "Password field is required." is shown.');
 
     // Testing this drupal_set_message() requires an extra test module.
-    $this->drupalGet('google-analytics-test/drupal-messenger-add-message');
-    $this->assertNoRaw('gtag("event", "Status message", {"event_category":"Messages","event_label":"Example status message."});', '[testGoogleAnalyticsStatusMessages]: Example status message is not enabled for tracking.');
-    $this->assertNoRaw('gtag("event", "Warning message", {"event_category":"Messages","event_label":"Example warning message."});', '[testGoogleAnalyticsStatusMessages]: Example warning message is not enabled for tracking.');
-    $this->assertRaw('gtag("event", "Error message", {"event_category":"Messages","event_label":"Example error message."});', '[testGoogleAnalyticsStatusMessages]: Example error message is shown.');
-    $this->assertRaw('gtag("event", "Error message", {"event_category":"Messages","event_label":"Example error message with html tags and link."});', '[testGoogleAnalyticsStatusMessages]: HTML has been stripped successful from Example error message with html tags and link.');
+    $this->drupalGet('google-analytics-test/drupal-set-message');
+    $this->assertNoRaw('ga("send", "event", "Messages", "Status message", "Example status message.");', '[testGoogleAnalyticsStatusMessages]: Example status message is not enabled for tracking.');
+    $this->assertNoRaw('ga("send", "event", "Messages", "Warning message", "Example warning message.");', '[testGoogleAnalyticsStatusMessages]: Example warning message is not enabled for tracking.');
+    $this->assertRaw('ga("send", "event", "Messages", "Error message", "Example error message.");', '[testGoogleAnalyticsStatusMessages]: Example error message is shown.');
+    $this->assertRaw('ga("send", "event", "Messages", "Error message", "Example error message with html tags and link.");', '[testGoogleAnalyticsStatusMessages]: HTML has been stripped successful from Example error message with html tags and link.');
 
     // Enable logging of status, warnings and errors.
-    $this->config('google_analytics.settings')->set('track.messages', [
-      'status' => 'status',
-      'warning' => 'warning',
-      'error' => 'error',
-    ])->save();
+    $this->config('google_analytics.settings')->set('track.messages', ['status' => 'status', 'warning' => 'warning', 'error' => 'error'])->save();
 
-    $this->drupalGet('google-analytics-test/drupal-messenger-add-message');
-    $this->assertRaw('gtag("event", "Status message", {"event_category":"Messages","event_label":"Example status message."});', '[testGoogleAnalyticsStatusMessages]: Example status message is enabled for tracking.');
-    $this->assertRaw('gtag("event", "Warning message", {"event_category":"Messages","event_label":"Example warning message."});', '[testGoogleAnalyticsStatusMessages]: Example warning message is enabled for tracking.');
-    $this->assertRaw('gtag("event", "Error message", {"event_category":"Messages","event_label":"Example error message."});', '[testGoogleAnalyticsStatusMessages]: Example error message is shown.');
-    $this->assertRaw('gtag("event", "Error message", {"event_category":"Messages","event_label":"Example error message with html tags and link."});', '[testGoogleAnalyticsStatusMessages]: HTML has been stripped successful from Example error message with html tags and link.');
+    $this->drupalGet('google-analytics-test/drupal-set-message');
+    $this->assertRaw('ga("send", "event", "Messages", "Status message", "Example status message.");', '[testGoogleAnalyticsStatusMessages]: Example status message is enabled for tracking.');
+    $this->assertRaw('ga("send", "event", "Messages", "Warning message", "Example warning message.");', '[testGoogleAnalyticsStatusMessages]: Example warning message is enabled for tracking.');
+    $this->assertRaw('ga("send", "event", "Messages", "Error message", "Example error message.");', '[testGoogleAnalyticsStatusMessages]: Example error message is shown.');
+    $this->assertRaw('ga("send", "event", "Messages", "Error message", "Example error message with html tags and link.");', '[testGoogleAnalyticsStatusMessages]: HTML has been stripped successful from Example error message with html tags and link.');
   }
 
 }
diff --git a/web/modules/google_analytics/src/Tests/GoogleAnalyticsUninstallTest.php b/web/modules/google_analytics/src/Tests/GoogleAnalyticsUninstallTest.php
index bcffc740b1..f73f0a7c42 100644
--- a/web/modules/google_analytics/src/Tests/GoogleAnalyticsUninstallTest.php
+++ b/web/modules/google_analytics/src/Tests/GoogleAnalyticsUninstallTest.php
@@ -45,16 +45,16 @@ public function testGoogleAnalyticsUninstall() {
     // Show tracker in pages.
     $this->config('google_analytics.settings')->set('account', $ua_code)->save();
 
-    // Enable local caching of gtag.js.
+    // Enable local caching of analytics.js.
     $this->config('google_analytics.settings')->set('cache', 1)->save();
 
-    // Load page to get the gtag.js downloaded into local cache.
+    // Load page to get the analytics.js downloaded into local cache.
     $this->drupalGet('');
 
-    // Test if the directory and gtag.js exists.
+    // Test if the directory and analytics.js exists.
     $this->assertTrue(file_prepare_directory($cache_path), 'Cache directory "public://google_analytics" has been found.');
-    $this->assertTrue(file_exists($cache_path . '/gtag.js'), 'Cached analytics.js tracking file has been found.');
-    $this->assertTrue(file_exists($cache_path . '/gtag.js.gz'), 'Cached analytics.js.gz tracking file has been found.');
+    $this->assertTrue(file_exists($cache_path . '/analytics.js'), 'Cached analytics.js tracking file has been found.');
+    $this->assertTrue(file_exists($cache_path . '/analytics.js.gz'), 'Cached analytics.js.gz tracking file has been found.');
 
     // Uninstall the module.
     $edit = [];
diff --git a/web/modules/google_analytics/tests/modules/google_analytics_test/google_analytics_test.info.yml b/web/modules/google_analytics/tests/modules/google_analytics_test/google_analytics_test.info.yml
index 1bb1f5c8ca..7399b11b6a 100644
--- a/web/modules/google_analytics/tests/modules/google_analytics_test/google_analytics_test.info.yml
+++ b/web/modules/google_analytics/tests/modules/google_analytics_test/google_analytics_test.info.yml
@@ -4,8 +4,8 @@ description: 'Support module for Google Analytics testing.'
 package: Testing
 # core: 8.x
 
-# Information added by Drupal.org packaging script on 2019-01-31
-version: '8.x-3.0'
+# Information added by Drupal.org packaging script on 2017-09-25
+version: '8.x-2.2'
 core: '8.x'
 project: 'google_analytics'
-datestamp: 1548968586
+datestamp: 1506372866
diff --git a/web/modules/google_analytics/tests/modules/google_analytics_test/google_analytics_test.routing.yml b/web/modules/google_analytics/tests/modules/google_analytics_test/google_analytics_test.routing.yml
index dd12ce3fd6..8b7b092da3 100644
--- a/web/modules/google_analytics/tests/modules/google_analytics_test/google_analytics_test.routing.yml
+++ b/web/modules/google_analytics/tests/modules/google_analytics_test/google_analytics_test.routing.yml
@@ -1,7 +1,7 @@
-google_analytics_test.drupal_messenger_add_message:
-  path: '/google-analytics-test/drupal-messenger-add-message'
+google_analytics_test.drupal_set_message:
+  path: '/google-analytics-test/drupal-set-message'
   defaults:
-    _title: 'Set messages with Drupal::messenger()'
-    _controller: '\Drupal\google_analytics_test\Controller\GoogleAnalyticsTestController::drupalAddMessageTest'
+    _title: 'Set messages with drupal_set_message()'
+    _controller: '\Drupal\google_analytics_test\Controller\GoogleAnalyticsTestController::drupalSetMessageTest'
   requirements:
     _access: 'TRUE'
diff --git a/web/modules/google_analytics/tests/modules/google_analytics_test/src/Controller/GoogleAnalyticsTestController.php b/web/modules/google_analytics/tests/modules/google_analytics_test/src/Controller/GoogleAnalyticsTestController.php
index 9cfc9553db..074049cb97 100644
--- a/web/modules/google_analytics/tests/modules/google_analytics_test/src/Controller/GoogleAnalyticsTestController.php
+++ b/web/modules/google_analytics/tests/modules/google_analytics_test/src/Controller/GoogleAnalyticsTestController.php
@@ -12,15 +12,15 @@ class GoogleAnalyticsTestController extends ControllerBase {
   /**
    * Tests setting messages and removing one before it is displayed.
    *
-   * @return array
-   *   Empty array, we just test the setting of messages.
+   * @return string
+   *   Empty string, we just test the setting of messages.
    */
-  public function drupalAddMessageTest() {
+  public function drupalSetMessageTest() {
     // Set some messages.
-    $this->messenger()->addMessage($this->t('Example status message.'), 'status');
-    $this->messenger()->addMessage($this->t('Example warning message.'), 'warning');
-    $this->messenger()->addMessage($this->t('Example error message.'), 'error');
-    $this->messenger()->addMessage($this->t('Example error <em>message</em> with html tags and <a href="https://example.com/">link</a>.'), 'error');
+    drupal_set_message('Example status message.', 'status');
+    drupal_set_message('Example warning message.', 'warning');
+    drupal_set_message('Example error message.', 'error');
+    drupal_set_message('Example error <em>message</em> with html tags and <a href="http://example.com/">link</a>.', 'error');
 
     return [];
   }
-- 
GitLab