diff --git a/googleanalytics.admin.inc b/googleanalytics.admin.inc index d3d9f6d3ba2f0dc768e762ac9e2c42b9b48fb1b8..741e6a8e2e64bcdaff8c06641bf896c0fc30d769 100644 --- a/googleanalytics.admin.inc +++ b/googleanalytics.admin.inc @@ -178,6 +178,53 @@ function googleanalytics_admin_settings_form($form_state) { '#default_value' => variable_get('googleanalytics_trackadsense', FALSE), ); + $form['tracking']['domain_tracking'] = array( + '#type' => 'fieldset', + '#title' => t('Domains'), + ); + + global $cookie_domain; + $multiple_sub_domains = array(); + foreach (array('www', 'app', 'shop') as $subdomain) { + if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) { + $multiple_sub_domains[] = $subdomain . $cookie_domain; + } + // IP addresses or localhost. + else { + $multiple_sub_domains[] = $subdomain . '.example.com'; + } + } + + $multiple_toplevel_domains = array(); + foreach (array('.com', '.net', '.org') as $tldomain) { + $host = $_SERVER['HTTP_HOST']; + $domain = substr($host, 0, strrpos($host, '.')); + if (count(explode('.', $host)) > 2 && !is_numeric(str_replace('.', '', $host))) { + $multiple_toplevel_domains[] = $domain . $tldomain; + } + // IP addresses or localhost + else { + $multiple_toplevel_domains[] = 'www.example' . $tldomain; + } + } + + $form['tracking']['domain_tracking']['googleanalytics_domain_mode'] = array( + '#type' => 'radios', + '#title' => t('What are you tracking?'), + '#options' => array( + 0 => t('A single domain (default)') . '
' . t('Domain: @domain', array('@domain' => $_SERVER['HTTP_HOST'])) . '
', + 1 => t('One domain with multiple subdomains') . '
' . t('Examples: @domains', array('@domains' => implode(', ', $multiple_sub_domains))) . '
', + 2 => t('Multiple top-level domains') . '
' . t('Examples: @domains', array('@domains' => implode(', ', $multiple_toplevel_domains))) . '
', + ), + '#default_value' => variable_get('googleanalytics_domain_mode', 0), + ); + $form['tracking']['domain_tracking']['googleanalytics_cross_domains'] = array( + '#title' => t('List of top-level domains'), + '#type' => 'textarea', + '#default_value' => variable_get('googleanalytics_cross_domains', ''), + '#description' => t('If you selected "Multiple top-level domains" above, enter all related top-level domains. Add one domain per line. By default, the data in your reports only includes the path and name of the page, and not the domain name. For more information see section Show separate domain names in Tracking multiple domains.'), + ); + // Backward compatibility only. // TODO: If currently not in use, hide the UI and later remove the code. $segmentation = variable_get('googleanalytics_segmentation', array()); @@ -362,6 +409,7 @@ function googleanalytics_admin_settings_form_validate($form, &$form_state) { // Trim some text values. $form_state['values']['googleanalytics_account'] = trim($form_state['values']['googleanalytics_account']); $form_state['values']['googleanalytics_pages'] = trim($form_state['values']['googleanalytics_pages']); + $form_state['values']['googleanalytics_cross_domains'] = trim($form_state['values']['googleanalytics_cross_domains']); $form_state['values']['googleanalytics_codesnippet_before'] = trim($form_state['values']['googleanalytics_codesnippet_before']); $form_state['values']['googleanalytics_codesnippet_after'] = trim($form_state['values']['googleanalytics_codesnippet_after']); @@ -369,6 +417,11 @@ function googleanalytics_admin_settings_form_validate($form, &$form_state) { form_set_error('googleanalytics_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['values']['googleanalytics_domain_mode'] == 2 && empty($form_state['values']['googleanalytics_cross_domains'])) { + form_set_error('googleanalytics_cross_domains', t('A list of top-level domains is required if Multiple top-level domains has been selected.')); + } + // Clear obsolete local cache if cache has been disabled. if (empty($form_state['values']['googleanalytics_cache']) && $form['advanced']['googleanalytics_cache']['#default_value']) { googleanalytics_clear_js_cache(); diff --git a/googleanalytics.admin.js b/googleanalytics.admin.js index ec97f6a09671d39ea7f7389ebc10063c03a5e3ff..6602768dc53f6cc35b396675549fae8ef7acb1b4 100644 --- a/googleanalytics.admin.js +++ b/googleanalytics.admin.js @@ -80,6 +80,19 @@ Drupal.behaviors.trackingSettingsSummary = { } return Drupal.t('@items tracked', {'@items' : vals.join(', ')}); }); + + $('fieldset#edit-domain-tracking', context).drupalSetSummary(function (context) { + var $radio = $('input[name="googleanalytics_domain_mode"]:checked', context); + if ($radio.val() == 0) { + return Drupal.t('A single domain'); + } + else if ($radio.val() == 1) { + return Drupal.t('One domain with multiple subdomains'); + } + else { + return Drupal.t('Multiple top-level domains'); + } + }); } }; diff --git a/googleanalytics.install b/googleanalytics.install index c8cb6295e67386faeca720f43986002e02037b35..c392ac500f72aaa2715fcfe0a6fbd77c56b5fd6d 100644 --- a/googleanalytics.install +++ b/googleanalytics.install @@ -40,8 +40,10 @@ function googleanalytics_uninstall() { variable_del('googleanalytics_cache'); variable_del('googleanalytics_codesnippet_before'); variable_del('googleanalytics_codesnippet_after'); + variable_del('googleanalytics_cross_domains'); variable_del('googleanalytics_custom'); variable_del('googleanalytics_custom_vars'); + variable_del('googleanalytics_domain_mode'); variable_del('googleanalytics_js_scope'); variable_del('googleanalytics_last_cache'); variable_del('googleanalytics_pages'); diff --git a/googleanalytics.js b/googleanalytics.js index b398527e54f2765c3fc08106add90c8adffd88a2..f48f3e1640501f858fc56b823fdf747a8dd458fe 100644 --- a/googleanalytics.js +++ b/googleanalytics.js @@ -3,6 +3,14 @@ $(document).ready(function() { + // Accepts a string; returns the string with regex metacharacters escaped. The returned string + // can safely be used at any point within a regex to match the provided literal string. Escaped + // characters are [ ] { } ( ) * + ? - . , \ ^ $ # and whitespace. The character | is excluded + // in this function as it's used to separate the domains names. + RegExp.escapeDomains = function(text) { + return text.replace(/[-[\]{}()*+?.,\\^$#\s]/g, "\\$&"); + } + // Attach onclick event to document only and catch clicks on all elements. $(document.body).click(function(event) { // Catch only the first parent link of a clicked element. @@ -15,6 +23,8 @@ $(document).ready(function() { var isInternalSpecial = new RegExp("(\/go\/.*)$", "i"); // Expression to check for download links. var isDownload = new RegExp("\\.(" + ga.trackDownloadExtensions + ")$", "i"); + // Expression to check for the sites cross domains. + var isCrossDomain = new RegExp("^(https?|ftp|news|nntp|telnet|irc|ssh|sftp|webcal):\/\/.*(" + RegExp.escapeDomains(ga.trackCrossDomains) + ")", "i"); // Is the clicked URL internal? if (isInternal.test(this.href)) { @@ -36,7 +46,12 @@ $(document).ready(function() { _gaq.push(["_trackEvent", "Mails", "Click", this.href.substring(7)]); } else if (ga.trackOutbound && this.href) { - if (ga.trackOutboundAsPageview) { + if (ga.trackDomainMode == 2 && isCrossDomain.test(this.href)) { + // Top-level cross domain clicked. + _gaq.push(["_link", this.href]); + setTimeout('document.location = "' + this.href + '"', 100); + } + else if (ga.trackOutboundAsPageview) { // Track all external links as page views after URL cleanup. // Currently required, if click should be tracked as goal. _gaq.push(["_trackPageview", '/outbound/' + this.href.replace(/^(https?|ftp|news|nntp|telnet|irc|ssh|sftp|webcal):\/\//i, '').split('/').join('--')]); diff --git a/googleanalytics.module b/googleanalytics.module index 332b6699b0723474c97b7321e228196998459dac..5069a94c5971b912b36cf39c080a341efd4124e9 100644 --- a/googleanalytics.module +++ b/googleanalytics.module @@ -114,6 +114,14 @@ function googleanalytics_page_alter(&$page) { if ($track_outbound_as_pageview = variable_get('googleanalytics_trackoutboundaspageview', 0)) { $link_settings['trackOutboundAsPageview'] = $track_outbound_as_pageview; } + if ($track_domain_mode = variable_get('googleanalytics_domain_mode', 0)) { + $link_settings['trackDomainMode'] = $track_domain_mode; + } + if ($track_cross_domains = variable_get('googleanalytics_cross_domains', '')) { + $domains = preg_split('/(\r\n?|\n)/', $track_cross_domains); + $link_settings['trackCrossDomains'] = implode('|', $domains); + } + if (!empty($link_settings)) { drupal_add_js(array('googleanalytics' => $link_settings), 'setting'); drupal_add_js(drupal_get_path('module', 'googleanalytics') . '/googleanalytics.js'); @@ -213,6 +221,21 @@ function googleanalytics_page_alter(&$page) { // a workaround until "_anonymizeIp" has been implemented/fixed. $script .= '_gaq.push(["_gat._anonymizeIp"]);'; } + + // Domain tracking type. + global $cookie_domain; + $domain_mode = variable_get('googleanalytics_domain_mode', 0); + + // Per RFC 2109, cookie domains must contain at least one dot other than the + // 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))) { + $script .= '_gaq.push(["_setDomainName", ' . drupal_json_encode($cookie_domain) . ']);'; + } + else if ($domain_mode == 2) { + $script .= '_gaq.push(["_setDomainName", "none"]);'; + $script .= '_gaq.push(["_setAllowLinker", true]);'; + } + if (!empty($segmentation)) { $script .= $segmentation; }