From d280bfb5230fe1d07e8d01ec47cfc6cbbbf28987 Mon Sep 17 00:00:00 2001 From: Chris Gross <gross.364@osu.edu> Date: Wed, 10 Aug 2016 13:03:12 -0400 Subject: [PATCH] weekly build --- profiles/wcm_base/CHANGELOG.txt | 4 ++ .../contrib/google_analytics/README.txt | 59 ++++++++++++----- .../googleanalytics.admin.inc | 46 ++++++++++--- .../google_analytics/googleanalytics.admin.js | 9 +++ .../google_analytics/googleanalytics.debug.js | 64 ++++++++++++++----- .../google_analytics/googleanalytics.info | 6 +- .../google_analytics/googleanalytics.install | 9 +-- .../google_analytics/googleanalytics.js | 58 +++++++++++++---- .../google_analytics/googleanalytics.module | 36 +++++++++-- .../google_analytics/googleanalytics.test | 62 ++++++++++++++++-- .../googleanalytics.variable.inc | 4 ++ profiles/wcm_base/wcm_base.make | 2 +- 12 files changed, 282 insertions(+), 77 deletions(-) diff --git a/profiles/wcm_base/CHANGELOG.txt b/profiles/wcm_base/CHANGELOG.txt index 4b7d4740..9ce5c4b5 100644 --- a/profiles/wcm_base/CHANGELOG.txt +++ b/profiles/wcm_base/CHANGELOG.txt @@ -1,3 +1,7 @@ +WCM Base 7.x-1.x, 2016-08-10 +---------------------------- +-WCM Base: Updated Google Analytics to 2.3. + WCM Base 7.x-1.x, 2016-08-03 ---------------------------- -WCM Base: Updated Panopoly to 1.38. diff --git a/profiles/wcm_base/modules/contrib/google_analytics/README.txt b/profiles/wcm_base/modules/contrib/google_analytics/README.txt index fab2f2ec..25fd22aa 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/README.txt +++ b/profiles/wcm_base/modules/contrib/google_analytics/README.txt @@ -12,12 +12,20 @@ Requirements * Google Analytics user account - Installation ============ Copy the 'googleanalytics' module directory in to your Drupal sites/all/modules directory as usual. +Upgrading from 6.x-3.x and 7.x-1.x +================================== +If you upgrade from 6.x-3.x and 7.x-1.x (ga.js) to 7.x-2.x (analytics.js) you +should verify if you used custom variables. Write down your settings or make a +screenshot. You need to re-configure the settings to use custom dimensions or +metrics. There is no automatic upgrade path for custom variables feature. All +other module settings are upgraded automatically. + +See https://support.google.com/analytics/answer/2795983?hl=en for more details. Usage ===== @@ -27,12 +35,8 @@ All pages will now have the required JavaScript added to the HTML footer can confirm this by viewing the page source from your browser. -New approach to page tracking in 5.x-1.5 and 6.x-1.1 -==================================================== -With 5.x-1.5 and 6.x-1.1 there are new settings on the settings page at -admin/config/system/googleanalytics. The "Page specific tracking" area now -comes with an interface that copies Drupal's block visibility settings. - +Page specific tracking +====================== The default is set to "Add to every page except the listed pages". By default the following pages are listed for exclusion: @@ -44,23 +48,24 @@ node/*/* user/*/* These defaults are changeable by the website administrator or any other -user with 'administer google analytics' permission. +user with 'Administer Google Analytics' permission. -Like the blocks visibility settings in Drupal core, there is now 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 http://drupal.org/node/64135. +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 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 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 Management Interface (http://www.google.com/analytics/) + 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 custom dimensions settings form - under admin/config/system/googleanalytics. You can also choose another index, - but keep it always in sync with the index used in step #1. +2. Enter the below configuration data into the Drupal custom dimensions settings + form under admin/config/system/googleanalytics. You can also choose another + index, but keep it always in sync with the index used in step #1. Index: 1 Value: [current-user:role-names] @@ -77,3 +82,23 @@ provided for any customisations you include. To speed up page loading you may also cache the Google Analytics "analytics.js" file locally. + +Manual JS debugging +=================== +For manual debugging of the JS code you are able to create a test node. This +is the example HTML code for this test node. You need to enable debugging mode +in your Drupal configuration of Google Analytics settings to see verbose +messages in your browsers JS console. + +Title: Google Analytics test page + +Body: +<ul> + <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="http://example.com/">External link</a></li> + <li><a href="/go/test">Go link</a></li> +</ul> + +Text format: Full HTML diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.inc b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.inc index 4449077d..d32939a3 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.inc +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.inc @@ -224,6 +224,18 @@ function googleanalytics_admin_settings_form($form_state) { ), ), ); + + $colorbox_dependencies = '<div class="admin-requirements">'; + $colorbox_dependencies .= t('Requires: !module-list', array('!module-list' => (module_exists('colorbox') ? t('@module (<span class="admin-enabled">enabled</span>)', array('@module' => 'Colorbox')) : t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => 'Colorbox'))))); + $colorbox_dependencies .= '</div>'; + + $form['tracking']['linktracking']['googleanalytics_trackcolorbox'] = array( + '#type' => 'checkbox', + '#title' => t('Track content in colorbox modal dialogs'), + '#default_value' => variable_get('googleanalytics_trackcolorbox', 1), + '#description' => t('Enable to track the content shown in colorbox modal windows.') . $colorbox_dependencies, + '#disabled' => (module_exists('colorbox') ? FALSE : TRUE), + ); $form['tracking']['linktracking']['googleanalytics_tracklinkid'] = array( '#type' => 'checkbox', '#title' => t('Track enhanced link attribution'), @@ -246,7 +258,7 @@ function googleanalytics_admin_settings_form($form_state) { '#type' => 'checkboxes', '#title' => t('Track messages of type'), '#default_value' => variable_get('googleanalytics_trackmessages', array()), - '#description' => t('This will track the selected message types shown to users. Tracking of form validation errors may help you identifying usability issues in your site. For each visit (user session), a maximum of approximately 500 combined GATC requests (both events and page views) can be tracked. Every message is tracked as one individual event. Note that - as the number of events in a session approaches the limit - additional events might not be tracked. Messages from excluded pages cannot tracked.'), + '#description' => t('This will track the selected message types shown to users. Tracking of form validation errors may help you identifying usability issues in your site. For each visit (user session), a maximum of approximately 500 combined GATC requests (both events and page views) can be tracked. Every message is tracked as one individual event. Note that - as the number of events in a session approaches the limit - additional events might not be tracked. Messages from excluded pages cannot be tracked.'), '#options' => array( 'status' => t('Status message'), 'warning' => t('Warning message'), @@ -305,7 +317,7 @@ function googleanalytics_admin_settings_form($form_state) { $form['googleanalytics_custom_dimension'] = array( '#collapsed' => TRUE, '#collapsible' => TRUE, - '#description' => t('You can set values for Google Analytics <a href="@custom_var_documentation">Custom Dimensions</a> here. You must have already configured your custom dimensions in the <a href="@setup_documentation">Google Analytics Management Interface</a>. You may use tokens. Global and user tokens are always available; on node pages, node tokens are also available. A dimension <em>value</em> is allowed to have a maximum lenght of 150 bytes. Expect longer values to get trimmed.', array('@custom_var_documentation' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets', '@setup_documentation' => 'https://support.google.com/analytics/answer/2709829')), + '#description' => t('You can set values for Google Analytics <a href="@custom_var_documentation">Custom Dimensions</a> here. You must have already configured your custom dimensions in the <a href="@setup_documentation">Google Analytics Management Interface</a>. You may use tokens. Global and user tokens are always available; on node pages, node tokens are also available. A dimension <em>value</em> is allowed to have a maximum length of 150 bytes. Expect longer values to get trimmed.', array('@custom_var_documentation' => 'https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets', '@setup_documentation' => 'https://support.google.com/analytics/answer/2709829')), '#theme' => 'googleanalytics_admin_custom_var_table', '#title' => t('Custom dimensions'), '#tree' => TRUE, @@ -428,6 +440,8 @@ function googleanalytics_admin_settings_form($form_state) { ); } + $user_access_add_js_snippets = !user_access('add JS snippets for google analytics'); + $user_access_add_js_snippets_permission_warning = $user_access_add_js_snippets ? ' <em>' . t('This field has been disabled because you do not have sufficient permissions to edit it.') . '</em>' : ''; $form['advanced']['codesnippet'] = array( '#type' => 'fieldset', '#title' => t('Custom JavaScript code'), @@ -447,15 +461,17 @@ function googleanalytics_admin_settings_form($form_state) { '#type' => 'textarea', '#title' => t('Code snippet (before)'), '#default_value' => variable_get('googleanalytics_codesnippet_before', ''), + '#disabled' => $user_access_add_js_snippets, '#rows' => 5, - '#description' => t('Code in this textarea will be added <strong>before</strong> <code>ga("send", "pageview");</code>.'), + '#description' => 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']['googleanalytics_codesnippet_after'] = array( '#type' => 'textarea', '#title' => t('Code snippet (after)'), '#default_value' => variable_get('googleanalytics_codesnippet_after', ''), + '#disabled' => $user_access_add_js_snippets, '#rows' => 5, - '#description' => 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.'), + '#description' => 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']['googleanalytics_debug'] = array( @@ -541,6 +557,12 @@ function googleanalytics_admin_settings_form_validate($form, &$form_state) { /** * Layout for the custom variables table in the admin settings form. + * + * @param array $variables + * An array contains the form elements. + * + * @return string + * The rendered output. */ function theme_googleanalytics_admin_custom_var_table($variables) { $form = $variables['form']; @@ -551,7 +573,7 @@ function theme_googleanalytics_admin_custom_var_table($variables) { ); $rows = array(); - foreach (element_children($form['indexes']) as $key => $id) { + foreach (element_children($form['indexes']) as $id) { $rows[] = array( 'data' => array( drupal_render($form['indexes'][$id]['index']), @@ -600,11 +622,18 @@ function googleanalytics_token_element_validate(&$element, &$form_state) { return $element; } +/** + * @param array $value + * An array of token values. + * + * @return array + * A unique array of invalid tokens. + */ function _googleanalytics_get_forbidden_tokens($value) { $invalid_tokens = array(); $value_tokens = is_string($value) ? token_scan($value) : $value; - foreach ($value_tokens as $type => $tokens) { + foreach ($value_tokens as $tokens) { if (array_filter($tokens, '_googleanalytics_contains_forbidden_token')) { $invalid_tokens = array_merge($invalid_tokens, array_values($tokens)); } @@ -617,8 +646,9 @@ function _googleanalytics_get_forbidden_tokens($value) { /** * Validate if a string contains forbidden tokens not allowed by privacy rules. * - * @param $token_string + * @param string $token_string * A string with one or more tokens to be validated. + * * @return boolean * TRUE if blacklisted token has been found, otherwise FALSE. */ @@ -724,7 +754,7 @@ function _googleanalytics_extract_create_field_values($string) { $list = array_map('trim', $list); $list = array_filter($list, 'strlen'); - foreach ($list as $position => $text) { + foreach ($list as $text) { // Check for an explicit key. $matches = array(); if (preg_match('/(.*)\|(.*)/', $text, $matches)) { diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.js b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.js index 083eeaa3..c81470d7 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.js +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.admin.js @@ -65,6 +65,15 @@ Drupal.behaviors.trackingSettingsSummary = { if ($('input#edit-googleanalytics-trackfiles', context).is(':checked')) { vals.push(Drupal.t('Downloads')); } + if ($('input#edit-googleanalytics-trackcolorbox', context).is(':checked')) { + vals.push(Drupal.t('Colorbox')); + } + if ($('input#edit-googleanalytics-tracklinkid', context).is(':checked')) { + vals.push(Drupal.t('Link attribution')); + } + if ($('input#edit-googleanalytics-trackurlfragments', context).is(':checked')) { + vals.push(Drupal.t('URL fragments')); + } if (!vals.length) { return Drupal.t('Not tracked'); } diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.debug.js b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.debug.js index 861f7fdb..a0be81ae 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.debug.js +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.debug.js @@ -8,16 +8,16 @@ $(document).ready(function() { // clicks on all elements. $(document.body).bind("mousedown keyup touchstart", function(event) { console.group("Running Google Analytics for Drupal."); - console.info(event); + console.info("Event '%s' has been detected.", event.type); // Catch the closest surrounding link of a clicked element. $(event.target).closest("a,area").each(function() { - console.info("Element '%o' has been detected. Link '%s' found.", this, this.href); + console.info("Closest element '%o' has been found. URL '%s' extracted.", this, this.href); // Is the clicked URL internal? if (Drupal.googleanalytics.isInternal(this.href)) { // Skip 'click' tracking, if custom tracking events are bound. - if ($(this).is('.colorbox')) { + if ($(this).is('.colorbox') && (Drupal.settings.googleanalytics.trackColorbox)) { // Do nothing here. The custom event will handle all tracking. console.info("Click on .colorbox item has been detected."); } @@ -25,12 +25,22 @@ $(document).ready(function() { else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) { // Download link clicked. console.info("Download url '%s' has been found. Tracked download as extension '%s'.", Drupal.googleanalytics.getPageUrl(this.href), Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase()); - ga("send", "event", "Downloads", Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), Drupal.googleanalytics.getPageUrl(this.href)); + ga("send", { + "hitType": "event", + "eventCategory": "Downloads", + "eventAction": Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), + "eventLabel": Drupal.googleanalytics.getPageUrl(this.href), + "transport": "beacon" + }); } else if (Drupal.googleanalytics.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.googleanalytics.getPageUrl(this.href)); - ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(this.href) }); + ga("send", { + "hitType": "pageview", + "page": Drupal.googleanalytics.getPageUrl(this.href), + "transport": "beacon" + }); } else { // e.g. anchor in same page or other internal page link @@ -41,13 +51,25 @@ $(document).ready(function() { if (Drupal.settings.googleanalytics.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)); - ga("send", "event", "Mails", "Click", this.href.substring(7)); + ga("send", { + "hitType": "event", + "eventCategory": "Mails", + "eventAction": "Click", + "eventLabel": this.href.substring(7), + "transport": "beacon" + }); } else if (Drupal.settings.googleanalytics.trackOutbound && this.href.match(/^\w+:\/\//i)) { - if (Drupal.settings.googleanalytics.trackDomainMode != 2 || (Drupal.settings.googleanalytics.trackDomainMode == 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { + if (Drupal.settings.googleanalytics.trackDomainMode !== 2 || (Drupal.settings.googleanalytics.trackDomainMode === 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { // External link clicked / No top-level cross domain clicked. console.info("Outbound link '%s' has been tracked.", this.href); - ga("send", "event", "Outbound links", "Click", this.href); + ga("send", { + "hitType": "event", + "eventCategory": "Outbound links", + "eventAction": "Click", + "eventLabel": this.href, + "transport": "beacon" + }); } else { console.info("Internal link '%s' clicked, not tracked.", this.href); @@ -63,19 +85,27 @@ $(document).ready(function() { if (Drupal.settings.googleanalytics.trackUrlFragments) { window.onhashchange = function() { console.info("Track URL '%s' as pageview. Hash '%s' has changed.", location.pathname + location.search + location.hash, location.hash); - ga('send', 'pageview', location.pathname + location.search + location.hash); - } + ga("send", { + "hitType": "pageview", + "page": location.pathname + location.search + location.hash + }); + }; } // Colorbox: This event triggers when the transition has completed and the // newly loaded content has been revealed. - $(document).bind("cbox_complete", function () { - var href = $.colorbox.element().attr("href"); - if (href) { - console.info("Colorbox transition to url '%s' has been tracked.", Drupal.googleanalytics.getPageUrl(href)); - ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(href) }); - } - }); + if (Drupal.settings.googleanalytics.trackColorbox) { + $(document).bind("cbox_complete", function () { + var href = $.colorbox.element().attr("href"); + if (href) { + console.info("Colorbox transition to url '%s' has been tracked.", Drupal.googleanalytics.getPageUrl(href)); + ga("send", { + "hitType": "pageview", + "page": Drupal.googleanalytics.getPageUrl(href) + }); + } + }); + } }); diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.info b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.info index adbf134a..2b814605 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.info +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.info @@ -5,9 +5,9 @@ package = Statistics configure = admin/config/system/googleanalytics files[] = googleanalytics.test test_dependencies[] = token -; Information added by Drupal.org packaging script on 2014-11-29 -version = "7.x-2.1" +; Information added by Drupal.org packaging script on 2016-08-09 +version = "7.x-2.3" core = "7.x" project = "google_analytics" -datestamp = "1417276982" +datestamp = "1470779953" diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.install b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.install index d7b2edfb..a4f4e83a 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.install +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.install @@ -25,6 +25,7 @@ function googleanalytics_uninstall() { variable_del('googleanalytics_roles'); variable_del('googleanalytics_site_search'); variable_del('googleanalytics_trackadsense'); + variable_del('googleanalytics_trackcolorbox'); variable_del('googleanalytics_trackdoubleclick'); variable_del('googleanalytics_tracker_anonymizeip'); variable_del('googleanalytics_trackfiles'); @@ -446,16 +447,16 @@ function googleanalytics_update_7200() { if (!empty($googleanalytics_codesnippet_before) && stristr($googleanalytics_codesnippet_before, '_gaq.push(')) { variable_set('googleanalytics_codesnippet_before_backup_7200', $googleanalytics_codesnippet_before); variable_del('googleanalytics_codesnippet_before'); - drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet has been saved in database table '{variable}' as 'googleanalytics_codesnippet_before_backup_7200'. You need to manually upgrade the custom 'before' code snippet."), 'warning'); - $messages[] = t('Manual upgrade of custom "before" code snippet is required.'); + drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet (ga.js) has been saved in database table '{variable}' as 'googleanalytics_codesnippet_before_backup_7200'. You need to manually upgrade the custom 'before' code snippet to analytics.js API."), 'warning'); + $messages[] = t('Manual upgrade of custom "before" code snippet from ja.js to analytics.js API is required.'); } $googleanalytics_codesnippet_after = variable_get('googleanalytics_codesnippet_after', ''); if (!empty($googleanalytics_codesnippet_after) && stristr($googleanalytics_codesnippet_after, '_gaq.push(')) { variable_set('googleanalytics_codesnippet_after_backup_7200', $googleanalytics_codesnippet_after); variable_del('googleanalytics_codesnippet_after'); - drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet has been saved in database table '{variable}' as 'googleanalytics_codesnippet_before_backup_7200'. You need to manually upgrade the custom 'before' code snippet."), 'warning'); - $messages[] = t('Manual upgrade of custom "after" code snippet is required.'); + drupal_set_message(Database::getConnection()->prefixTables("A backup of your previous Google Analytics code snippet (ga.js) has been saved in database table '{variable}' as 'googleanalytics_codesnippet_after_backup_7200'. You need to manually upgrade the custom 'after' code snippet to analytics.js API."), 'warning'); + $messages[] = t('Manual upgrade of custom "after" code snippet from ja.js to analytics.js API is required.'); } return empty($messages) ? t('No custom code snipped found. Nothing to do.') : implode(' ', $messages); diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.js b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.js index 1eed3c32..8d5bde1b 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.js +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.js @@ -14,29 +14,51 @@ $(document).ready(function() { // Is the clicked URL internal? if (Drupal.googleanalytics.isInternal(this.href)) { // Skip 'click' tracking, if custom tracking events are bound. - if ($(this).is('.colorbox')) { + if ($(this).is('.colorbox') && (Drupal.settings.googleanalytics.trackColorbox)) { // Do nothing here. The custom event will handle all tracking. //console.info("Click on .colorbox item has been detected."); } // Is download tracking activated and the file extension configured for download tracking? else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) { // Download link clicked. - ga("send", "event", "Downloads", Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), Drupal.googleanalytics.getPageUrl(this.href)); + ga("send", { + "hitType": "event", + "eventCategory": "Downloads", + "eventAction": Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), + "eventLabel": Drupal.googleanalytics.getPageUrl(this.href), + "transport": "beacon" + }); } else if (Drupal.googleanalytics.isInternalSpecial(this.href)) { // Keep the internal URL for Google Analytics website overlay intact. - ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(this.href) }); + ga("send", { + "hitType": "pageview", + "page": Drupal.googleanalytics.getPageUrl(this.href), + "transport": "beacon" + }); } } else { if (Drupal.settings.googleanalytics.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) { // Mailto link clicked. - ga("send", "event", "Mails", "Click", this.href.substring(7)); + ga("send", { + "hitType": "event", + "eventCategory": "Mails", + "eventAction": "Click", + "eventLabel": this.href.substring(7), + "transport": "beacon" + }); } else if (Drupal.settings.googleanalytics.trackOutbound && this.href.match(/^\w+:\/\//i)) { - if (Drupal.settings.googleanalytics.trackDomainMode != 2 || (Drupal.settings.googleanalytics.trackDomainMode == 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { + if (Drupal.settings.googleanalytics.trackDomainMode !== 2 || (Drupal.settings.googleanalytics.trackDomainMode === 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { // External link clicked / No top-level cross domain clicked. - ga("send", "event", "Outbound links", "Click", this.href); + ga("send", { + "hitType": "event", + "eventCategory": "Outbound links", + "eventAction": "Click", + "eventLabel": this.href, + "transport": "beacon" + }); } } } @@ -46,18 +68,26 @@ $(document).ready(function() { // Track hash changes as unique pageviews, if this option has been enabled. if (Drupal.settings.googleanalytics.trackUrlFragments) { window.onhashchange = function() { - ga('send', 'pageview', location.pathname + location.search + location.hash); - } + ga("send", { + "hitType": "pageview", + "page": location.pathname + location.search + location.hash + }); + }; } // Colorbox: This event triggers when the transition has completed and the // newly loaded content has been revealed. - $(document).bind("cbox_complete", function () { - var href = $.colorbox.element().attr("href"); - if (href) { - ga("send", "pageview", { "page": Drupal.googleanalytics.getPageUrl(href) }); - } - }); + if (Drupal.settings.googleanalytics.trackColorbox) { + $(document).bind("cbox_complete", function () { + var href = $.colorbox.element().attr("href"); + if (href) { + ga("send", { + "hitType": "pageview", + "page": Drupal.googleanalytics.getPageUrl(href) + }); + } + }); + } }); diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.module b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.module index 4051b1b9..b45ee103 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.module +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.module @@ -69,6 +69,11 @@ function googleanalytics_permission() { 'description' => t('Enter PHP code in the field for tracking visibility settings.'), 'restrict access' => TRUE, ), + 'add JS snippets for google analytics' => array( + 'title' => t('Add JavaScript snippets'), + 'description' => 'Enter JavaScript code snippets for advanced Google Analytics functionality.', + 'restrict access' => TRUE, + ), ); } @@ -125,6 +130,9 @@ function googleanalytics_page_alter(&$page) { $link_settings['trackDownload'] = $track_download; $link_settings['trackDownloadExtensions'] = $trackfiles_extensions; } + if (module_exists('colorbox') && ($track_colorbox = variable_get('googleanalytics_trackcolorbox', 1))) { + $link_settings['trackColorbox'] = $track_colorbox; + } if ($track_domain_mode = variable_get('googleanalytics_domain_mode', 0)) { $link_settings['trackDomainMode'] = $track_domain_mode; } @@ -294,10 +302,7 @@ function googleanalytics_page_alter(&$page) { // Track logged in users across all devices. if (variable_get('googleanalytics_trackuserid', 0) && user_is_logged_in()) { - // The USER_ID value should be a unique, persistent, and non-personally - // identifiable string identifier that represents a user or signed-in - // account across devices. - $create_only_fields['userId'] = drupal_hmac_base64($user->uid, drupal_get_private_key() . drupal_get_hash_salt()); + $create_only_fields['userId'] = google_analytics_user_id_hash($user->uid); } // Create a tracker. @@ -352,13 +357,30 @@ function googleanalytics_page_alter(&$page) { // Custom tracking. Prepend before all other JavaScript. // @TODO: https://support.google.com/adsense/answer/98142 // sounds like it could be appended to $script. - drupal_add_js($googleanalytics_adsense_script, array('type' => 'inline', 'group' => JS_LIBRARY-1)); + drupal_add_js($googleanalytics_adsense_script, array('type' => 'inline', 'group' => JS_LIBRARY-1, 'requires_jquery' => FALSE)); } - drupal_add_js($script, array('scope' => 'header', 'type' => 'inline')); + drupal_add_js($script, array('scope' => 'header', 'type' => 'inline', 'requires_jquery' => FALSE)); } } +/** + * Generate user id hash to implement USER_ID. + * + * The USER_ID value should be a unique, persistent, and non-personally + * identifiable string identifier that represents a user or signed-in + * account across devices. + * + * @param int $uid + * User id. + * + * @return string + * User id hash. + */ +function google_analytics_user_id_hash($uid) { + return drupal_hmac_base64($uid, drupal_get_private_key() . drupal_get_hash_salt()); +} + /** * Implements hook_field_extra_fields(). */ @@ -456,7 +478,7 @@ function googleanalytics_preprocess_search_results(&$variables) { // found. But the pager item mumber can tell the number of search results. global $pager_total_items; - drupal_add_js('window.googleanalytics_search_results = ' . intval($pager_total_items[0]) . ';', array('type' => 'inline', 'group' => JS_LIBRARY-1)); + drupal_add_js('window.googleanalytics_search_results = ' . intval($pager_total_items[0]) . ';', array('type' => 'inline', 'group' => JS_LIBRARY-1, 'requires_jquery' => FALSE)); } } diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test index 0b64bb82..745047a8 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.test @@ -6,6 +6,13 @@ */ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { + /** + * User without permissions to edit snippets. + * + * @var \StdClass + */ + protected $noSnippetUser; + public static function getInfo() { return array( 'name' => 'Google Analytics basic tests', @@ -25,6 +32,8 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { ); // User to set up google_analytics. + $this->noSnippetUser = $this->drupalCreateUser($permissions); + $permissions[] = 'add JS snippets for google analytics'; $this->admin_user = $this->drupalCreateUser($permissions); $this->drupalLogin($this->admin_user); } @@ -48,6 +57,26 @@ class GoogleAnalyticsBasicTest extends DrupalWebTestCase { $edit['googleanalytics_account'] = $this->randomName(2); $this->drupalPost('admin/config/system/googleanalytics', $edit, t('Save configuration')); $this->assertRaw(t('A valid Google Analytics Web Property ID is case sensitive and formatted like UA-xxxxxxx-yy.'), '[testGoogleAnalyticsConfiguration]: Invalid Web Property ID number validated.'); + + // User should have access to code snippets. + $this->assertFieldByName('googleanalytics_codesnippet_create'); + $this->assertFieldByName('googleanalytics_codesnippet_before'); + $this->assertFieldByName('googleanalytics_codesnippet_after'); + $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.'); + $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is enabled.'); + $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is enabled.'); + + // Login as user without JS permissions. + $this->drupalLogin($this->noSnippetUser); + $this->drupalGet('admin/config/system/googleanalytics'); + + // User should *not* have access to snippets, but create fields. + $this->assertFieldByName('googleanalytics_codesnippet_create'); + $this->assertFieldByName('googleanalytics_codesnippet_before'); + $this->assertFieldByName('googleanalytics_codesnippet_after'); + $this->assertNoFieldByXPath("//textarea[@name='googleanalytics_codesnippet_create' and @disabled='disabled']", NULL, '"Create only fields" is enabled.'); + $this->assertFieldByXPath("//textarea[@name='googleanalytics_codesnippet_before' and @disabled='disabled']", NULL, '"Code snippet (before)" is disabled.'); + $this->assertFieldByXPath("//textarea[@name='googleanalytics_codesnippet_after' and @disabled='disabled']", NULL, '"Code snippet (after)" is disabled.'); } function testGoogleAnalyticsPageVisibility() { @@ -284,6 +313,7 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase { // User to set up google_analytics. $this->admin_user = $this->drupalCreateUser($permissions); + $this->drupalLogin($this->admin_user); } function testGoogleAnalyticsCustomDimensions() { @@ -362,34 +392,30 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase { 1 => array( 'index' => 1, 'value' => '6', - 'value_expected' => 6, ), 2 => array( 'index' => 2, 'value' => '8000', - 'value_expected' => 8000, ), 3 => array( 'index' => 3, 'value' => '7.8654', - 'value_expected' => 7.8654, ), 4 => array( 'index' => 4, 'value' => '1123.4', - 'value_expected' => 1123.4, ), 5 => array( 'index' => 5, 'value' => '5,67', - 'value_expected' => 5, ), ); + variable_set('googleanalytics_custom_metric', $googleanalytics_custom_metric); $this->drupalGet(''); foreach ($googleanalytics_custom_metric as $metric) { - $this->assertRaw('ga("set", ' . drupal_json_encode('metric' . $metric['index']) . ', ' . drupal_json_encode($metric['value_expected']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Metric #' . $metric['index'] . ' is shown.'); + $this->assertRaw('ga("set", ' . drupal_json_encode('metric' . $metric['index']) . ', ' . drupal_json_encode((float) $metric['value']) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Metric #' . $metric['index'] . ' is shown.'); } // Test whether tokens are replaced in custom metric values. @@ -421,6 +447,30 @@ class GoogleAnalyticsCustomDimensionsAndMetricsTest extends DrupalWebTestCase { $this->assertNoRaw('ga("set", ' . drupal_json_encode('metric3') . ', ' . drupal_json_encode('') . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Empty value is not shown.'); $this->assertRaw('ga("set", ' . drupal_json_encode('metric4') . ', ' . drupal_json_encode(0) . ');', '[testGoogleAnalyticsCustomDimensionsAndMetrics]: Value 0 is shown.'); } + + /** + * Tests if Custom Dimensions token form validation works. + */ + public function testGoogleAnalyticsCustomDimensionsTokenFormValidation() { + $ua_code = 'UA-123456-1'; + + // Check form validation. + $edit['googleanalytics_account'] = $ua_code; + $edit['googleanalytics_custom_dimension[indexes][1][value]'] = '[current-user:name]'; + $edit['googleanalytics_custom_dimension[indexes][2][value]'] = '[current-user:edit-url]'; + $edit['googleanalytics_custom_dimension[indexes][3][value]'] = '[user:name]'; + $edit['googleanalytics_custom_dimension[indexes][4][value]'] = '[term:name]'; + $edit['googleanalytics_custom_dimension[indexes][5][value]'] = '[term:tid]'; + + $this->drupalPost('admin/config/system/googleanalytics', $edit, t('Save configuration')); + + $this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 1)), '@invalid-tokens' => implode(', ', array('[current-user:name]'))))); + $this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 2)), '@invalid-tokens' => implode(', ', array('[current-user:edit-url]'))))); + $this->assertRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 3)), '@invalid-tokens' => implode(', ', array('[user:name]'))))); + // BUG #2037595 + //$this->assertNoRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 4)), '@invalid-tokens' => implode(', ', array('[term:name]'))))); + //$this->assertNoRaw(t('The %element-title is using the following forbidden tokens with personal identifying information: @invalid-tokens.', array('%element-title' => t('Custom dimension value #@index', array('@index' => 5)), '@invalid-tokens' => implode(', ', array('[term:tid]'))))); + } } class GoogleAnalyticsStatusMessagesTest extends DrupalWebTestCase { diff --git a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.variable.inc b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.variable.inc index 6a657350..9d142a27 100644 --- a/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.variable.inc +++ b/profiles/wcm_base/modules/contrib/google_analytics/googleanalytics.variable.inc @@ -40,6 +40,10 @@ function googleanalytics_variable_group_info() { /** * Validate Web Property ID variable. + * + * @param array $variable + * + * @return string */ function googleanalytics_validate_googleanalytics_account($variable) { // Replace all type of dashes (n-dash, m-dash, minus) with the normal dashes. diff --git a/profiles/wcm_base/wcm_base.make b/profiles/wcm_base/wcm_base.make index 88da825b..fbc9d624 100644 --- a/profiles/wcm_base/wcm_base.make +++ b/profiles/wcm_base/wcm_base.make @@ -58,7 +58,7 @@ projects[file_entity][patch][2533816] = http://drupal.org/files/issues/2537982-f projects[file_entity_swf][version] = 1.0-rc2 projects[file_entity_swf][subdir] = contrib -projects[google_analytics][version] = 2.1 +projects[google_analytics][version] = 2.3 projects[google_analytics][subdir] = contrib projects[jquery_update][version] = 2.7 -- GitLab