annotate sites/all/modules/google_analytics/googleanalytics.module @ 11:b0ee71395280

deleted .DS_Store files
author danieleb <danielebarchiesi@me.com>
date Mon, 28 Oct 2013 16:12:13 +0000
parents b74b41bb73f0
children 134d4b2e75f6
rev   line source
danielebarchiesi@2 1 <?php
danielebarchiesi@2 2
danielebarchiesi@2 3 /*
danielebarchiesi@2 4 * @file
danielebarchiesi@2 5 * Drupal Module: GoogleAnalytics
danielebarchiesi@2 6 * Adds the required Javascript to the bottom of all your Drupal pages
danielebarchiesi@2 7 * to allow tracking by the Google Analytics statistics package.
danielebarchiesi@2 8 *
danielebarchiesi@2 9 * @author: Alexander Hass <http://drupal.org/user/85918>
danielebarchiesi@2 10 */
danielebarchiesi@2 11
danielebarchiesi@2 12 define('GOOGLEANALYTICS_TRACKFILES_EXTENSIONS', '7z|aac|arc|arj|asf|asx|avi|bin|csv|doc|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mp(2|3|4|e?g)|mov(ie)?|msi|msp|pdf|phps|png|ppt|qtm?|ra(m|r)?|sea|sit|tar|tgz|torrent|txt|wav|wma|wmv|wpd|xls|xml|z|zip');
danielebarchiesi@2 13
danielebarchiesi@2 14 // Remove tracking from all administrative pages, see http://drupal.org/node/34970.
danielebarchiesi@2 15 define('GOOGLEANALYTICS_PAGES', "admin\nadmin/*\nbatch\nnode/add*\nnode/*/*\nuser/*/*");
danielebarchiesi@2 16
danielebarchiesi@2 17 /**
danielebarchiesi@2 18 * Implements hook_help().
danielebarchiesi@2 19 */
danielebarchiesi@2 20 function googleanalytics_help($path, $arg) {
danielebarchiesi@2 21 switch ($path) {
danielebarchiesi@2 22 case 'admin/config/system/googleanalytics':
danielebarchiesi@2 23 return t('<a href="@ga_url">Google Analytics</a> is a free (registration required) website traffic and marketing effectiveness service.', array('@ga_url' => 'http://www.google.com/analytics/'));
danielebarchiesi@2 24 }
danielebarchiesi@2 25 }
danielebarchiesi@2 26
danielebarchiesi@2 27 /**
danielebarchiesi@2 28 * Implements hook_theme().
danielebarchiesi@2 29 */
danielebarchiesi@2 30 function googleanalytics_theme() {
danielebarchiesi@2 31 return array(
danielebarchiesi@2 32 'googleanalytics_admin_custom_var_table' => array(
danielebarchiesi@2 33 'render element' => 'form',
danielebarchiesi@2 34 ),
danielebarchiesi@2 35 );
danielebarchiesi@2 36 }
danielebarchiesi@2 37
danielebarchiesi@2 38 /**
danielebarchiesi@2 39 * Implements hook_permission().
danielebarchiesi@2 40 */
danielebarchiesi@2 41 function googleanalytics_permission() {
danielebarchiesi@2 42 return array(
danielebarchiesi@2 43 'administer google analytics' => array(
danielebarchiesi@2 44 'title' => t('Administer Google Analytics'),
danielebarchiesi@2 45 'description' => t('Perform maintenance tasks for Google Analytics.'),
danielebarchiesi@2 46 ),
danielebarchiesi@2 47 'opt-in or out of tracking' => array(
danielebarchiesi@2 48 'title' => t('Opt-in or out of tracking'),
danielebarchiesi@2 49 'description' => t('Allow users to decide if tracking code will be added to pages or not.'),
danielebarchiesi@2 50 ),
danielebarchiesi@2 51 'use PHP for tracking visibility' => array(
danielebarchiesi@2 52 'title' => t('Use PHP for tracking visibility'),
danielebarchiesi@2 53 'description' => t('Enter PHP code in the field for tracking visibility settings.'),
danielebarchiesi@2 54 'restrict access' => TRUE,
danielebarchiesi@2 55 ),
danielebarchiesi@2 56 );
danielebarchiesi@2 57 }
danielebarchiesi@2 58
danielebarchiesi@2 59 /**
danielebarchiesi@2 60 * Implements hook_menu().
danielebarchiesi@2 61 */
danielebarchiesi@2 62 function googleanalytics_menu() {
danielebarchiesi@2 63 $items['admin/config/system/googleanalytics'] = array(
danielebarchiesi@2 64 'title' => 'Google Analytics',
danielebarchiesi@2 65 'description' => 'Configure tracking behavior to get insights into your website traffic and marketing effectiveness.',
danielebarchiesi@2 66 'page callback' => 'drupal_get_form',
danielebarchiesi@2 67 'page arguments' => array('googleanalytics_admin_settings_form'),
danielebarchiesi@2 68 'access arguments' => array('administer google analytics'),
danielebarchiesi@2 69 'type' => MENU_NORMAL_ITEM,
danielebarchiesi@2 70 'file' => 'googleanalytics.admin.inc',
danielebarchiesi@2 71 );
danielebarchiesi@2 72
danielebarchiesi@2 73 return $items;
danielebarchiesi@2 74 }
danielebarchiesi@2 75
danielebarchiesi@2 76 /**
danielebarchiesi@2 77 * Implements hook_page_alter() to insert JavaScript to the appropriate scope/region of the page.
danielebarchiesi@2 78 */
danielebarchiesi@2 79 function googleanalytics_page_alter(&$page) {
danielebarchiesi@2 80 global $user;
danielebarchiesi@2 81
danielebarchiesi@2 82 $id = variable_get('googleanalytics_account', '');
danielebarchiesi@2 83
danielebarchiesi@2 84 // Get page status code for visibility filtering.
danielebarchiesi@2 85 $status = drupal_get_http_header('Status');
danielebarchiesi@2 86 $trackable_status_codes = array(
danielebarchiesi@2 87 '403 Forbidden',
danielebarchiesi@2 88 '404 Not Found',
danielebarchiesi@2 89 );
danielebarchiesi@2 90
danielebarchiesi@2 91 // 1. Check if the GA account number has a value.
danielebarchiesi@2 92 // 2. Track page views based on visibility value.
danielebarchiesi@2 93 // 3. Check if we should track the currently active user's role.
danielebarchiesi@2 94 // 4. Ignore pages visibility filter for 404 or 403 status codes.
danielebarchiesi@2 95 if (!empty($id) && (_googleanalytics_visibility_pages() || in_array($status, $trackable_status_codes)) && _googleanalytics_visibility_user($user)) {
danielebarchiesi@2 96
danielebarchiesi@2 97 // We allow different scopes. Default to 'header' but allow user to override if they really need to.
danielebarchiesi@2 98 $scope = variable_get('googleanalytics_js_scope', 'header');
danielebarchiesi@2 99
danielebarchiesi@2 100 if (variable_get('googleanalytics_trackadsense', FALSE)) {
danielebarchiesi@2 101 // Custom tracking. Prepend before all other JavaScript.
danielebarchiesi@2 102 drupal_add_js('window.google_analytics_uacct = ' . drupal_json_encode($id) . ';', array('type' => 'inline', 'group' => JS_LIBRARY-1));
danielebarchiesi@2 103 }
danielebarchiesi@2 104
danielebarchiesi@2 105 // Add link tracking.
danielebarchiesi@2 106 $link_settings = array();
danielebarchiesi@2 107 if ($track_outbound = variable_get('googleanalytics_trackoutbound', 1)) {
danielebarchiesi@2 108 $link_settings['trackOutbound'] = $track_outbound;
danielebarchiesi@2 109 }
danielebarchiesi@2 110 if ($track_mailto = variable_get('googleanalytics_trackmailto', 1)) {
danielebarchiesi@2 111 $link_settings['trackMailto'] = $track_mailto;
danielebarchiesi@2 112 }
danielebarchiesi@2 113 if (($track_download = variable_get('googleanalytics_trackfiles', 1)) && ($trackfiles_extensions = variable_get('googleanalytics_trackfiles_extensions', GOOGLEANALYTICS_TRACKFILES_EXTENSIONS))) {
danielebarchiesi@2 114 $link_settings['trackDownload'] = $track_download;
danielebarchiesi@2 115 $link_settings['trackDownloadExtensions'] = $trackfiles_extensions;
danielebarchiesi@2 116 }
danielebarchiesi@2 117 if ($track_domain_mode = variable_get('googleanalytics_domain_mode', 0)) {
danielebarchiesi@2 118 $link_settings['trackDomainMode'] = $track_domain_mode;
danielebarchiesi@2 119 }
danielebarchiesi@2 120 if ($track_cross_domains = variable_get('googleanalytics_cross_domains', '')) {
danielebarchiesi@2 121 $link_settings['trackCrossDomains'] = preg_split('/(\r\n?|\n)/', $track_cross_domains);
danielebarchiesi@2 122 }
danielebarchiesi@2 123
danielebarchiesi@2 124 if (!empty($link_settings)) {
danielebarchiesi@2 125 drupal_add_js(array('googleanalytics' => $link_settings), 'setting');
danielebarchiesi@2 126 drupal_add_js(drupal_get_path('module', 'googleanalytics') . '/googleanalytics.js');
danielebarchiesi@2 127 }
danielebarchiesi@2 128
danielebarchiesi@2 129 // Add messages tracking.
danielebarchiesi@2 130 $message_events = '';
danielebarchiesi@2 131 if ($message_types = variable_get('googleanalytics_trackmessages', array())) {
danielebarchiesi@2 132 $message_types = array_values(array_filter($message_types));
danielebarchiesi@2 133 $status_heading = array(
danielebarchiesi@2 134 'status' => t('Status message'),
danielebarchiesi@2 135 'warning' => t('Warning message'),
danielebarchiesi@2 136 'error' => t('Error message'),
danielebarchiesi@2 137 );
danielebarchiesi@2 138
danielebarchiesi@2 139 foreach (drupal_get_messages(NULL, FALSE) as $type => $messages) {
danielebarchiesi@2 140 // Track only the selected message types.
danielebarchiesi@2 141 if (in_array($type, $message_types)) {
danielebarchiesi@2 142 foreach ($messages as $message) {
danielebarchiesi@2 143 $message_events .= '_gaq.push(["_trackEvent", ' . drupal_json_encode(t('Messages')) . ', ' . drupal_json_encode($status_heading[$type]) . ', ' . drupal_json_encode(strip_tags($message)) . ']);';
danielebarchiesi@2 144 }
danielebarchiesi@2 145 }
danielebarchiesi@2 146 }
danielebarchiesi@2 147 }
danielebarchiesi@2 148
danielebarchiesi@2 149 // Site search tracking support.
danielebarchiesi@2 150 $url_custom = '';
danielebarchiesi@2 151 if (module_exists('search') && variable_get('googleanalytics_site_search', FALSE) && arg(0) == 'search' && $keys = googleanalytics_search_get_keys()) {
danielebarchiesi@2 152 $url_custom = '(window.googleanalytics_search_results) ? ' . drupal_json_encode(url('search/' . arg(1), array('query' => array('search' => $keys)))) . ' : ' . drupal_json_encode(url('search/' . arg(1), array('query' => array('search' => 'no-results:' . $keys, 'cat' => 'no-results'))));
danielebarchiesi@2 153 }
danielebarchiesi@2 154
danielebarchiesi@2 155 // If this node is a translation of another node, pass the original
danielebarchiesi@2 156 // node instead.
danielebarchiesi@2 157 if (module_exists('translation') && variable_get('googleanalytics_translation_set', 0)) {
danielebarchiesi@2 158 // Check we have a node object, it supports translation, and its
danielebarchiesi@2 159 // translated node ID (tnid) doesn't match its own node ID.
danielebarchiesi@2 160 $node = menu_get_object();
danielebarchiesi@2 161 if ($node && translation_supported_type($node->type) && !empty($node->tnid) && ($node->tnid != $node->nid)) {
danielebarchiesi@2 162 $source_node = node_load($node->tnid);
danielebarchiesi@2 163 $languages = language_list();
danielebarchiesi@2 164 $url_custom = drupal_json_encode(url('node/' . $source_node->nid, array('language' => $languages[$source_node->language])));
danielebarchiesi@2 165 }
danielebarchiesi@2 166 }
danielebarchiesi@2 167
danielebarchiesi@2 168 // Track access denied (403) and file not found (404) pages.
danielebarchiesi@2 169 if ($status == '403 Forbidden') {
danielebarchiesi@2 170 // See http://www.google.com/support/analytics/bin/answer.py?answer=86927
danielebarchiesi@2 171 $url_custom = '"/403.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
danielebarchiesi@2 172 }
danielebarchiesi@2 173 elseif ($status == '404 Not Found') {
danielebarchiesi@2 174 $url_custom = '"/404.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
danielebarchiesi@2 175 }
danielebarchiesi@2 176
danielebarchiesi@2 177 // Add any custom code snippets if specified.
danielebarchiesi@2 178 $codesnippet_before = variable_get('googleanalytics_codesnippet_before', '');
danielebarchiesi@2 179 $codesnippet_after = variable_get('googleanalytics_codesnippet_after', '');
danielebarchiesi@2 180
danielebarchiesi@2 181 // Add custom variables.
danielebarchiesi@2 182 $googleanalytics_custom_vars = variable_get('googleanalytics_custom_var', array());
danielebarchiesi@2 183 $custom_var = '';
danielebarchiesi@2 184 for ($i = 1; $i < 6; $i++) {
danielebarchiesi@2 185 $custom_var_name = !empty($googleanalytics_custom_vars['slots'][$i]['name']) ? $googleanalytics_custom_vars['slots'][$i]['name'] : '';
danielebarchiesi@2 186 if (!empty($custom_var_name)) {
danielebarchiesi@2 187 $custom_var_value = !empty($googleanalytics_custom_vars['slots'][$i]['value']) ? $googleanalytics_custom_vars['slots'][$i]['value'] : '';
danielebarchiesi@2 188 $custom_var_scope = !empty($googleanalytics_custom_vars['slots'][$i]['scope']) ? $googleanalytics_custom_vars['slots'][$i]['scope'] : 3;
danielebarchiesi@2 189
danielebarchiesi@2 190 $types = array();
danielebarchiesi@2 191 $node = menu_get_object();
danielebarchiesi@2 192 if (is_object($node)) {
danielebarchiesi@2 193 $types += array('node' => $node);
danielebarchiesi@2 194 }
danielebarchiesi@2 195 $custom_var_name = token_replace($custom_var_name, $types, array('clear' => TRUE));
danielebarchiesi@2 196 $custom_var_value = token_replace($custom_var_value, $types, array('clear' => TRUE));
danielebarchiesi@2 197
danielebarchiesi@2 198 // Suppress empty custom names and/or variables.
danielebarchiesi@2 199 if (!drupal_strlen(trim($custom_var_name)) || !drupal_strlen(trim($custom_var_value))) {
danielebarchiesi@2 200 continue;
danielebarchiesi@2 201 }
danielebarchiesi@2 202
danielebarchiesi@2 203 // The length of the string used for the 'name' and the length of the
danielebarchiesi@2 204 // string used for the 'value' must not exceed 128 bytes after url encoding.
danielebarchiesi@2 205 $name_length = drupal_strlen(rawurlencode($custom_var_name));
danielebarchiesi@2 206 $tmp_value = rawurlencode($custom_var_value);
danielebarchiesi@2 207 $value_length = drupal_strlen($tmp_value);
danielebarchiesi@2 208 if ($name_length + $value_length > 128) {
danielebarchiesi@2 209 // Trim value and remove fragments of url encoding.
danielebarchiesi@2 210 $tmp_value = rtrim(substr($tmp_value, 0, 127 - $name_length), '%0..9A..F');
danielebarchiesi@2 211 $custom_var_value = urldecode($tmp_value);
danielebarchiesi@2 212 }
danielebarchiesi@2 213
danielebarchiesi@2 214 $custom_var_name = drupal_json_encode($custom_var_name);
danielebarchiesi@2 215 $custom_var_value = drupal_json_encode($custom_var_value);
danielebarchiesi@2 216 $custom_var .= "_gaq.push(['_setCustomVar', $i, $custom_var_name, $custom_var_value, $custom_var_scope]);";
danielebarchiesi@2 217 }
danielebarchiesi@2 218 }
danielebarchiesi@2 219
danielebarchiesi@2 220 // Build tracker code.
danielebarchiesi@2 221 $script = 'var _gaq = _gaq || [];';
danielebarchiesi@2 222 $script .= '_gaq.push(["_setAccount", ' . drupal_json_encode($id) . ']);';
danielebarchiesi@2 223 if (variable_get('googleanalytics_tracker_anonymizeip', 0)) {
danielebarchiesi@2 224 // FIXME: The Google API is currently broken and "_gat._anonymizeIp" is only
danielebarchiesi@2 225 // a workaround until "_anonymizeIp" has been implemented/fixed.
danielebarchiesi@2 226 $script .= '_gaq.push(["_gat._anonymizeIp"]);';
danielebarchiesi@2 227 }
danielebarchiesi@2 228
danielebarchiesi@2 229 // Domain tracking type.
danielebarchiesi@2 230 global $cookie_domain;
danielebarchiesi@2 231 $domain_mode = variable_get('googleanalytics_domain_mode', 0);
danielebarchiesi@2 232
danielebarchiesi@2 233 // Per RFC 2109, cookie domains must contain at least one dot other than the
danielebarchiesi@2 234 // first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
danielebarchiesi@2 235 if ($domain_mode == 1 && count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
danielebarchiesi@2 236 $script .= '_gaq.push(["_setDomainName", ' . drupal_json_encode($cookie_domain) . ']);';
danielebarchiesi@2 237 }
danielebarchiesi@2 238 elseif ($domain_mode == 2) {
danielebarchiesi@2 239 $script .= '_gaq.push(["_setDomainName", "none"]);';
danielebarchiesi@2 240 $script .= '_gaq.push(["_setAllowLinker", true]);';
danielebarchiesi@2 241 }
danielebarchiesi@2 242
danielebarchiesi@2 243 if (!empty($custom_var)) {
danielebarchiesi@2 244 $script .= $custom_var;
danielebarchiesi@2 245 }
danielebarchiesi@2 246 if (!empty($codesnippet_before)) {
danielebarchiesi@2 247 $script .= $codesnippet_before;
danielebarchiesi@2 248 }
danielebarchiesi@2 249 if (empty($url_custom)) {
danielebarchiesi@2 250 $script .= '_gaq.push(["_trackPageview"]);';
danielebarchiesi@2 251 }
danielebarchiesi@2 252 else {
danielebarchiesi@2 253 $script .= '_gaq.push(["_trackPageview", ' . $url_custom . ']);';
danielebarchiesi@2 254 }
danielebarchiesi@2 255 if (!empty($message_events)) {
danielebarchiesi@2 256 $script .= $message_events;
danielebarchiesi@2 257 }
danielebarchiesi@2 258 if (!empty($codesnippet_after)) {
danielebarchiesi@2 259 $script .= $codesnippet_after;
danielebarchiesi@2 260 }
danielebarchiesi@2 261
danielebarchiesi@2 262 $script .= '(function() {';
danielebarchiesi@2 263 $script .= 'var ga = document.createElement("script");';
danielebarchiesi@2 264 $script .= 'ga.type = "text/javascript";';
danielebarchiesi@2 265 $script .= 'ga.async = true;';
danielebarchiesi@2 266
danielebarchiesi@2 267 // Which version of the tracking library should be used?
danielebarchiesi@2 268 if ($trackdoubleclick = variable_get('googleanalytics_trackdoubleclick', FALSE)) {
danielebarchiesi@2 269 $library_tracker_url = 'stats.g.doubleclick.net/dc.js';
danielebarchiesi@2 270 $library_cache_url = 'http://' . $library_tracker_url;
danielebarchiesi@2 271 }
danielebarchiesi@2 272 else {
danielebarchiesi@2 273 $library_tracker_url = '.google-analytics.com/ga.js';
danielebarchiesi@2 274 $library_cache_url = 'http://www' . $library_tracker_url;
danielebarchiesi@2 275 }
danielebarchiesi@2 276
danielebarchiesi@2 277 // Should a local cached copy of ga.js be used?
danielebarchiesi@2 278 if (variable_get('googleanalytics_cache', 0) && $url = _googleanalytics_cache($library_cache_url)) {
danielebarchiesi@2 279 // A dummy query-string is added to filenames, to gain control over
danielebarchiesi@2 280 // browser-caching. The string changes on every update or full cache
danielebarchiesi@2 281 // flush, forcing browsers to load a new copy of the files, as the
danielebarchiesi@2 282 // URL changed.
danielebarchiesi@2 283 $query_string = '?' . variable_get('css_js_query_string', '0');
danielebarchiesi@2 284
danielebarchiesi@2 285 $script .= 'ga.src = "' . $url . $query_string . '";';
danielebarchiesi@2 286 }
danielebarchiesi@2 287 else {
danielebarchiesi@2 288 // Library paths do not follow the same naming convention.
danielebarchiesi@2 289 if ($trackdoubleclick) {
danielebarchiesi@2 290 $script .= 'ga.src = ("https:" == document.location.protocol ? "https://" : "http://") + "' . $library_tracker_url . '";';
danielebarchiesi@2 291 }
danielebarchiesi@2 292 else {
danielebarchiesi@2 293 $script .= 'ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + "' . $library_tracker_url . '";';
danielebarchiesi@2 294 }
danielebarchiesi@2 295 }
danielebarchiesi@2 296 $script .= 'var s = document.getElementsByTagName("script")[0];';
danielebarchiesi@2 297 $script .= 's.parentNode.insertBefore(ga, s);';
danielebarchiesi@2 298 $script .= '})();';
danielebarchiesi@2 299
danielebarchiesi@2 300 drupal_add_js($script, array('scope' => $scope, 'type' => 'inline'));
danielebarchiesi@2 301 }
danielebarchiesi@2 302 }
danielebarchiesi@2 303
danielebarchiesi@2 304 /**
danielebarchiesi@2 305 * Implements hook_field_extra_fields().
danielebarchiesi@2 306 */
danielebarchiesi@2 307 function googleanalytics_field_extra_fields() {
danielebarchiesi@2 308 $extra['user']['user']['form']['googleanalytics'] = array(
danielebarchiesi@2 309 'label' => t('Google Analytics configuration'),
danielebarchiesi@2 310 'description' => t('Google Analytics module form element.'),
danielebarchiesi@2 311 'weight' => 3,
danielebarchiesi@2 312 );
danielebarchiesi@2 313
danielebarchiesi@2 314 return $extra;
danielebarchiesi@2 315 }
danielebarchiesi@2 316
danielebarchiesi@2 317 /**
danielebarchiesi@2 318 * Implements hook_form_FORM_ID_alter().
danielebarchiesi@2 319 *
danielebarchiesi@2 320 * Allow users to decide if tracking code will be added to pages or not.
danielebarchiesi@2 321 */
danielebarchiesi@2 322 function googleanalytics_form_user_profile_form_alter(&$form, &$form_state) {
danielebarchiesi@2 323 $account = $form['#user'];
danielebarchiesi@2 324 $category = $form['#user_category'];
danielebarchiesi@2 325
danielebarchiesi@2 326 if ($category == 'account' && user_access('opt-in or out of tracking') && ($custom = variable_get('googleanalytics_custom', 0)) != 0 && _googleanalytics_visibility_roles($account)) {
danielebarchiesi@2 327 $form['googleanalytics'] = array(
danielebarchiesi@2 328 '#type' => 'fieldset',
danielebarchiesi@2 329 '#title' => t('Google Analytics configuration'),
danielebarchiesi@2 330 '#weight' => 3,
danielebarchiesi@2 331 '#collapsible' => TRUE,
danielebarchiesi@2 332 '#tree' => TRUE
danielebarchiesi@2 333 );
danielebarchiesi@2 334
danielebarchiesi@2 335 switch ($custom) {
danielebarchiesi@2 336 case 1:
danielebarchiesi@2 337 $description = t('Users are tracked by default, but you are able to opt out.');
danielebarchiesi@2 338 break;
danielebarchiesi@2 339
danielebarchiesi@2 340 case 2:
danielebarchiesi@2 341 $description = t('Users are <em>not</em> tracked by default, but you are able to opt in.');
danielebarchiesi@2 342 break;
danielebarchiesi@2 343 }
danielebarchiesi@2 344
danielebarchiesi@2 345 // Disable tracking for visitors who have opted out from tracking via DNT (Do-Not-Track) header.
danielebarchiesi@2 346 $disabled = FALSE;
danielebarchiesi@2 347 if (variable_get('googleanalytics_privacy_donottrack', 1) && !empty($_SERVER['HTTP_DNT'])) {
danielebarchiesi@2 348 $disabled = TRUE;
danielebarchiesi@2 349
danielebarchiesi@2 350 // Override settings value.
danielebarchiesi@2 351 $account->data['googleanalytics']['custom'] = FALSE;
danielebarchiesi@2 352
danielebarchiesi@2 353 $description .= '<span class="admin-disabled">';
danielebarchiesi@2 354 $description .= ' ' . t('You have opted out from tracking via browser privacy settings.');
danielebarchiesi@2 355 $description .= '</span>';
danielebarchiesi@2 356 }
danielebarchiesi@2 357
danielebarchiesi@2 358 $form['googleanalytics']['custom'] = array(
danielebarchiesi@2 359 '#type' => 'checkbox',
danielebarchiesi@2 360 '#title' => t('Enable user tracking'),
danielebarchiesi@2 361 '#description' => $description,
danielebarchiesi@2 362 '#default_value' => isset($account->data['googleanalytics']['custom']) ? $account->data['googleanalytics']['custom'] : ($custom == 1),
danielebarchiesi@2 363 '#disabled' => $disabled,
danielebarchiesi@2 364 );
danielebarchiesi@2 365
danielebarchiesi@2 366 return $form;
danielebarchiesi@2 367 }
danielebarchiesi@2 368 }
danielebarchiesi@2 369
danielebarchiesi@2 370 /**
danielebarchiesi@2 371 * Implements hook_user_presave().
danielebarchiesi@2 372 */
danielebarchiesi@2 373 function googleanalytics_user_presave(&$edit, $account, $category) {
danielebarchiesi@2 374 if (isset($edit['googleanalytics']['custom'])) {
danielebarchiesi@2 375 $edit['data']['googleanalytics']['custom'] = $edit['googleanalytics']['custom'];
danielebarchiesi@2 376 }
danielebarchiesi@2 377 }
danielebarchiesi@2 378
danielebarchiesi@2 379 /**
danielebarchiesi@2 380 * Implements hook_cron().
danielebarchiesi@2 381 */
danielebarchiesi@2 382 function googleanalytics_cron() {
danielebarchiesi@2 383 // Regenerate the tracking code file every day.
danielebarchiesi@2 384 if (REQUEST_TIME - variable_get('googleanalytics_last_cache', 0) >= 86400 && variable_get('googleanalytics_cache', 0)) {
danielebarchiesi@2 385 // Which version of the tracking library should be used?
danielebarchiesi@2 386 if (variable_get('googleanalytics_trackdoubleclick', FALSE)) {
danielebarchiesi@2 387 _googleanalytics_cache('http://stats.g.doubleclick.net/dc.js', TRUE);
danielebarchiesi@2 388 }
danielebarchiesi@2 389 else {
danielebarchiesi@2 390 _googleanalytics_cache('http://www.google-analytics.com/ga.js', TRUE);
danielebarchiesi@2 391 }
danielebarchiesi@2 392 variable_set('googleanalytics_last_cache', REQUEST_TIME);
danielebarchiesi@2 393 }
danielebarchiesi@2 394 }
danielebarchiesi@2 395
danielebarchiesi@2 396 /**
danielebarchiesi@2 397 * Implements hook_preprocess_search_results().
danielebarchiesi@2 398 *
danielebarchiesi@2 399 * Collects and adds the number of search results to the head.
danielebarchiesi@2 400 */
danielebarchiesi@2 401 function googleanalytics_preprocess_search_results(&$variables) {
danielebarchiesi@2 402 // There is no search result $variable available that hold the number of items
danielebarchiesi@2 403 // found. But the pager item mumber can tell the number of search results.
danielebarchiesi@2 404 global $pager_total_items;
danielebarchiesi@2 405
danielebarchiesi@2 406 drupal_add_js('window.googleanalytics_search_results = ' . intval($pager_total_items[0]) . ';', array('type' => 'inline', 'group' => JS_LIBRARY-1));
danielebarchiesi@2 407 }
danielebarchiesi@2 408
danielebarchiesi@2 409 /**
danielebarchiesi@2 410 * Helper function for grabbing search keys. Function is missing in D7.
danielebarchiesi@2 411 *
danielebarchiesi@2 412 * http://api.drupal.org/api/function/search_get_keys/6
danielebarchiesi@2 413 */
danielebarchiesi@2 414 function googleanalytics_search_get_keys() {
danielebarchiesi@2 415 static $return;
danielebarchiesi@2 416 if (!isset($return)) {
danielebarchiesi@2 417 // Extract keys as remainder of path
danielebarchiesi@2 418 // Note: support old GET format of searches for existing links.
danielebarchiesi@2 419 $path = explode('/', $_GET['q'], 3);
danielebarchiesi@2 420 $keys = empty($_REQUEST['keys']) ? '' : $_REQUEST['keys'];
danielebarchiesi@2 421 $return = count($path) == 3 ? $path[2] : $keys;
danielebarchiesi@2 422 }
danielebarchiesi@2 423 return $return;
danielebarchiesi@2 424 }
danielebarchiesi@2 425
danielebarchiesi@2 426 /**
danielebarchiesi@2 427 * Download/Synchronize/Cache tracking code file locally.
danielebarchiesi@2 428 *
danielebarchiesi@2 429 * @param $location
danielebarchiesi@2 430 * The full URL to the external javascript file.
danielebarchiesi@2 431 * @param $sync_cached_file
danielebarchiesi@2 432 * Synchronize tracking code and update if remote file have changed.
danielebarchiesi@2 433 * @return mixed
danielebarchiesi@2 434 * The path to the local javascript file on success, boolean FALSE on failure.
danielebarchiesi@2 435 */
danielebarchiesi@2 436 function _googleanalytics_cache($location, $sync_cached_file = FALSE) {
danielebarchiesi@2 437 $path = 'public://googleanalytics';
danielebarchiesi@2 438 $file_destination = $path . '/' . basename($location);
danielebarchiesi@2 439
danielebarchiesi@2 440 if (!file_exists($file_destination) || $sync_cached_file) {
danielebarchiesi@2 441 // Download the latest tracking code.
danielebarchiesi@2 442 $result = drupal_http_request($location);
danielebarchiesi@2 443
danielebarchiesi@2 444 if ($result->code == 200) {
danielebarchiesi@2 445 if (file_exists($file_destination)) {
danielebarchiesi@2 446 // Synchronize tracking code and and replace local file if outdated.
danielebarchiesi@2 447 $data_hash_local = drupal_hash_base64(file_get_contents($file_destination));
danielebarchiesi@2 448 $data_hash_remote = drupal_hash_base64($result->data);
danielebarchiesi@2 449 // Check that the files directory is writable.
danielebarchiesi@2 450 if ($data_hash_local != $data_hash_remote && file_prepare_directory($path)) {
danielebarchiesi@2 451 // Save updated tracking code file to disk.
danielebarchiesi@2 452 file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE);
danielebarchiesi@2 453 watchdog('googleanalytics', 'Locally cached tracking code file has been updated.', array(), WATCHDOG_INFO);
danielebarchiesi@2 454
danielebarchiesi@2 455 // Change query-strings on css/js files to enforce reload for all users.
danielebarchiesi@2 456 _drupal_flush_css_js();
danielebarchiesi@2 457 }
danielebarchiesi@2 458 }
danielebarchiesi@2 459 else {
danielebarchiesi@2 460 // Check that the files directory is writable.
danielebarchiesi@2 461 if (file_prepare_directory($path, FILE_CREATE_DIRECTORY)) {
danielebarchiesi@2 462 // There is no need to flush JS here as core refreshes JS caches
danielebarchiesi@2 463 // automatically, if new files are added.
danielebarchiesi@2 464 file_unmanaged_save_data($result->data, $file_destination, FILE_EXISTS_REPLACE);
danielebarchiesi@2 465 watchdog('googleanalytics', 'Locally cached tracking code file has been saved.', array(), WATCHDOG_INFO);
danielebarchiesi@2 466
danielebarchiesi@2 467 // Return the local JS file path.
danielebarchiesi@2 468 return file_create_url($file_destination);
danielebarchiesi@2 469 }
danielebarchiesi@2 470 }
danielebarchiesi@2 471 }
danielebarchiesi@2 472 }
danielebarchiesi@2 473 else {
danielebarchiesi@2 474 // Return the local JS file path.
danielebarchiesi@2 475 return file_create_url($file_destination);
danielebarchiesi@2 476 }
danielebarchiesi@2 477 }
danielebarchiesi@2 478
danielebarchiesi@2 479 /**
danielebarchiesi@2 480 * Delete cached files and directory.
danielebarchiesi@2 481 */
danielebarchiesi@2 482 function googleanalytics_clear_js_cache() {
danielebarchiesi@2 483 $path = 'public://googleanalytics';
danielebarchiesi@2 484 if (file_prepare_directory($path)) {
danielebarchiesi@2 485 file_scan_directory($path, '/.*/', array('callback' => 'file_unmanaged_delete'));
danielebarchiesi@2 486 drupal_rmdir($path);
danielebarchiesi@2 487
danielebarchiesi@2 488 // Change query-strings on css/js files to enforce reload for all users.
danielebarchiesi@2 489 _drupal_flush_css_js();
danielebarchiesi@2 490
danielebarchiesi@2 491 watchdog('googleanalytics', 'Local cache has been purged.', array(), WATCHDOG_INFO);
danielebarchiesi@2 492 }
danielebarchiesi@2 493 }
danielebarchiesi@2 494
danielebarchiesi@2 495 /**
danielebarchiesi@2 496 * Tracking visibility check for an user object.
danielebarchiesi@2 497 *
danielebarchiesi@2 498 * @param $account
danielebarchiesi@2 499 * A user object containing an array of roles to check.
danielebarchiesi@2 500 * @return boolean
danielebarchiesi@2 501 * A decision on if the current user is being tracked by Google Analytics.
danielebarchiesi@2 502 */
danielebarchiesi@2 503 function _googleanalytics_visibility_user($account) {
danielebarchiesi@2 504
danielebarchiesi@2 505 $enabled = FALSE;
danielebarchiesi@2 506
danielebarchiesi@2 507 // Is current user a member of a role that should be tracked?
danielebarchiesi@2 508 if (_googleanalytics_visibility_header($account) && _googleanalytics_visibility_roles($account)) {
danielebarchiesi@2 509
danielebarchiesi@2 510 // Use the user's block visibility setting, if necessary.
danielebarchiesi@2 511 if (($custom = variable_get('googleanalytics_custom', 0)) != 0) {
danielebarchiesi@2 512 if ($account->uid && isset($account->data['googleanalytics']['custom'])) {
danielebarchiesi@2 513 $enabled = $account->data['googleanalytics']['custom'];
danielebarchiesi@2 514 }
danielebarchiesi@2 515 else {
danielebarchiesi@2 516 $enabled = ($custom == 1);
danielebarchiesi@2 517 }
danielebarchiesi@2 518 }
danielebarchiesi@2 519 else {
danielebarchiesi@2 520 $enabled = TRUE;
danielebarchiesi@2 521 }
danielebarchiesi@2 522
danielebarchiesi@2 523 }
danielebarchiesi@2 524
danielebarchiesi@2 525 return $enabled;
danielebarchiesi@2 526 }
danielebarchiesi@2 527
danielebarchiesi@2 528 /**
danielebarchiesi@2 529 * Based on visibility setting this function returns TRUE if GA code should
danielebarchiesi@2 530 * be added for the current role and otherwise FALSE.
danielebarchiesi@2 531 */
danielebarchiesi@2 532 function _googleanalytics_visibility_roles($account) {
danielebarchiesi@2 533
danielebarchiesi@2 534 $visibility = variable_get('googleanalytics_visibility_roles', 0);
danielebarchiesi@2 535 $enabled = $visibility;
danielebarchiesi@2 536 $roles = variable_get('googleanalytics_roles', array());
danielebarchiesi@2 537
danielebarchiesi@2 538 if (array_sum($roles) > 0) {
danielebarchiesi@2 539 // One or more roles are selected.
danielebarchiesi@2 540 foreach (array_keys($account->roles) as $rid) {
danielebarchiesi@2 541 // Is the current user a member of one of these roles?
danielebarchiesi@2 542 if (isset($roles[$rid]) && $rid == $roles[$rid]) {
danielebarchiesi@2 543 // Current user is a member of a role that should be tracked/excluded from tracking.
danielebarchiesi@2 544 $enabled = !$visibility;
danielebarchiesi@2 545 break;
danielebarchiesi@2 546 }
danielebarchiesi@2 547 }
danielebarchiesi@2 548 }
danielebarchiesi@2 549 else {
danielebarchiesi@2 550 // No role is selected for tracking, therefore all roles should be tracked.
danielebarchiesi@2 551 $enabled = TRUE;
danielebarchiesi@2 552 }
danielebarchiesi@2 553
danielebarchiesi@2 554 return $enabled;
danielebarchiesi@2 555 }
danielebarchiesi@2 556
danielebarchiesi@2 557 /**
danielebarchiesi@2 558 * Based on visibility setting this function returns TRUE if GA code should
danielebarchiesi@2 559 * be added to the current page and otherwise FALSE.
danielebarchiesi@2 560 */
danielebarchiesi@2 561 function _googleanalytics_visibility_pages() {
danielebarchiesi@2 562 static $page_match;
danielebarchiesi@2 563
danielebarchiesi@2 564 // Cache visibility result if function is called more than once.
danielebarchiesi@2 565 if (!isset($page_match)) {
danielebarchiesi@2 566
danielebarchiesi@2 567 $visibility = variable_get('googleanalytics_visibility_pages', 0);
danielebarchiesi@2 568 $setting_pages = variable_get('googleanalytics_pages', GOOGLEANALYTICS_PAGES);
danielebarchiesi@2 569
danielebarchiesi@2 570 // Match path if necessary.
danielebarchiesi@2 571 if (!empty($setting_pages)) {
danielebarchiesi@2 572 // Convert path to lowercase. This allows comparison of the same path
danielebarchiesi@2 573 // with different case. Ex: /Page, /page, /PAGE.
danielebarchiesi@2 574 $pages = drupal_strtolower($setting_pages);
danielebarchiesi@2 575 if ($visibility < 2) {
danielebarchiesi@2 576 // Convert the Drupal path to lowercase
danielebarchiesi@2 577 $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
danielebarchiesi@2 578 // Compare the lowercase internal and lowercase path alias (if any).
danielebarchiesi@2 579 $page_match = drupal_match_path($path, $pages);
danielebarchiesi@2 580 if ($path != $_GET['q']) {
danielebarchiesi@2 581 $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
danielebarchiesi@2 582 }
danielebarchiesi@2 583 // When $visibility has a value of 0, the tracking code is displayed on
danielebarchiesi@2 584 // all pages except those listed in $pages. When set to 1, it
danielebarchiesi@2 585 // is displayed only on those pages listed in $pages.
danielebarchiesi@2 586 $page_match = !($visibility xor $page_match);
danielebarchiesi@2 587 }
danielebarchiesi@2 588 elseif (module_exists('php')) {
danielebarchiesi@2 589 $page_match = php_eval($setting_pages);
danielebarchiesi@2 590 }
danielebarchiesi@2 591 else {
danielebarchiesi@2 592 $page_match = FALSE;
danielebarchiesi@2 593 }
danielebarchiesi@2 594 }
danielebarchiesi@2 595 else {
danielebarchiesi@2 596 $page_match = TRUE;
danielebarchiesi@2 597 }
danielebarchiesi@2 598
danielebarchiesi@2 599 }
danielebarchiesi@2 600 return $page_match;
danielebarchiesi@2 601 }
danielebarchiesi@2 602
danielebarchiesi@2 603 /**
danielebarchiesi@2 604 * Based on headers send by clients this function returns TRUE if GA code should
danielebarchiesi@2 605 * be added to the current page and otherwise FALSE.
danielebarchiesi@2 606 */
danielebarchiesi@2 607 function _googleanalytics_visibility_header($account) {
danielebarchiesi@2 608
danielebarchiesi@2 609 if (($account->uid || variable_get('cache', 0) == 0) && variable_get('googleanalytics_privacy_donottrack', 1) && !empty($_SERVER['HTTP_DNT'])) {
danielebarchiesi@2 610 // Disable tracking if caching is disabled or a visitors is logged in and
danielebarchiesi@2 611 // have opted out from tracking via DNT (Do-Not-Track) header.
danielebarchiesi@2 612 return FALSE;
danielebarchiesi@2 613 }
danielebarchiesi@2 614
danielebarchiesi@2 615 return TRUE;
danielebarchiesi@2 616 }