Removing translation directories
[project/google_analytics.git] / googleanalytics.module
CommitLineData
8369f34c 1<?php
117c4d98 2
8369f34c 3/*
02b557e6 4 * @file
8369f34c 5 * Drupal Module: GoogleAnalytics
6 * Adds the required Javascript to the bottom of all your Drupal pages
7 * to allow tracking by the Google Analytics statistics package.
8 *
9 * @author: Mike Carter <www.ixis.co.uk/contact>
10 */
11
92429a1c 12define('GA_TRACKFILES_EXTENSIONS', '7z|aac|avi|csv|doc|exe|flv|gif|gz|jpe?g|js|mp(3|4|e?g)|mov|pdf|phps|png|ppt|rar|sit|tar|torrent|txt|wma|wmv|xls|xml|zip');
8369f34c 13
14function googleanalytics_help($path, $arg) {
15 switch ($path) {
16 case 'admin/settings/googleanalytics':
38214733 17 return t('<a href="@ga_url">Google Analytics</a> is a free statistics package based on the excellent Urchin system. This module provides services to better integrate Drupal with Google Analytics.', array('@ga_url' => 'http://www.google.com/analytics/'));
8369f34c 18 }
19}
20
9a58ec60 21function googleanalytics_perm() {
26e73fce 22 return array('administer google analytics', 'opt-in or out of tracking', 'use PHP for tracking visibility');
9a58ec60 23}
24
8369f34c 25function googleanalytics_menu() {
8369f34c 26 $items['admin/settings/googleanalytics'] = array(
27 'title' => 'Google Analytics',
649b04ab 28 'description' => 'Configure the settings used to generate your Google Analytics tracking code.',
8369f34c 29 'page callback' => 'drupal_get_form',
485516b7 30 'page arguments' => array('googleanalytics_admin_settings_form'),
9a58ec60 31 'access arguments' => array('administer google analytics'),
8369f34c 32 'file' => 'googleanalytics.admin.inc',
33 'type' => MENU_NORMAL_ITEM,
34 );
35
36 return $items;
37}
38
d37139ea 39function googleanalytics_init() {
020b6c1c 40 global $user;
d37139ea 41
020b6c1c 42 $id = variable_get('googleanalytics_account', '');
802831f0 43
9fd52543 44 // 1. Check if the GA account number has a value.
45 // 2. Track page views based on visibility value.
46 // 3. Check if we should track the currently active user's role.
681fdfe9 47 if (!empty($id) && _googleanalytics_visibility_pages() && _googleanalytics_visibility_user($user)) {
020b6c1c 48 // Use the old version of Google Analytics?
49 $legacy_version = variable_get('googleanalytics_legacy_version', FALSE);
50 $scope = variable_get('googleanalytics_js_scope', 'footer');
51
020b6c1c 52 // Should a local cached copy of urchin.js or ga.js be used?
53 $js_file = ($legacy_version) ? 'urchin.js' : 'ga.js';
a911fe63 54 $url = 'http://www.google-analytics.com/'. $js_file;
020b6c1c 55
56 if (variable_get('googleanalytics_cache', 0) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC) && $source = _googleanalytics_cache($url)) {
57 drupal_add_js($source, 'module', $scope);
58 }
59 else {
a911fe63 60 $script = 'var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");';
61 $script .= 'document.write(unescape("%3Cscript src=\'" + gaJsHost + "google-analytics.com/'. $js_file .'\' type=\'text/javascript\'%3E%3C/script%3E"));';
020b6c1c 62 drupal_add_js($script, 'inline', $scope);
63 }
64
da8422a7 65 // Add link tracking.
66 $link_settings = array();
1dffdb18 67 if ($track_outgoing = variable_get('googleanalytics_trackoutgoing', 1)) {
68 $link_settings['trackOutgoing'] = $track_outgoing;
da8422a7 69 }
1dffdb18 70 if ($track_mailto = variable_get('googleanalytics_trackmailto', 1)) {
71 $link_settings['trackMailto'] = $track_mailto;
da8422a7 72 }
1dffdb18 73 if (($track_download = variable_get('googleanalytics_trackfiles', 1)) && ($trackfiles_extensions = variable_get('googleanalytics_trackfiles_extensions', GA_TRACKFILES_EXTENSIONS))) {
74 $link_settings['trackDownload'] = $track_download;
da8422a7 75 $link_settings['trackDownloadExtensions'] = $trackfiles_extensions;
76 }
77 if (!empty($link_settings)) {
78 // TODO: Why is this legacy_version added as data type string and not integer to settings?
79 $link_settings['LegacyVersion'] = $legacy_version ? 1 : 0;
80 drupal_add_js(array('googleanalytics' => $link_settings), 'setting', 'header');
81 drupal_add_js(drupal_get_path('module', 'googleanalytics') .'/googleanalytics.js', 'module', $scope);
020b6c1c 82 }
5bcd0dac 83
84 // Custom tracking.
85 if (variable_get('googleanalytics_trackadsense', FALSE)) {
86 drupal_add_js('window.google_analytics_uacct = ' . drupal_to_js($id) . ';', 'inline', 'header');
87 }
d37139ea 88 }
d37139ea 89}
90
8369f34c 91/**
d37139ea 92 * Implementation of hook_footer() to insert Javascript at the end of the page.
8369f34c 93 */
94function googleanalytics_footer($main = 0) {
95 global $user;
96
97 $id = variable_get('googleanalytics_account', '');
98
681fdfe9 99 if (!empty($id) && _googleanalytics_visibility_pages() && _googleanalytics_visibility_user($user)) {
8369f34c 100
117c4d98 101 // Use the old version of Google Analytics?
d37139ea 102 $legacy_version = variable_get('googleanalytics_legacy_version', FALSE);
117c4d98 103
d37139ea 104 // Add User profile segmentation values.
8369f34c 105 if (is_array($profile_fields = variable_get('googleanalytics_segmentation', '')) && ($user->uid > 0)) {
106
107 $p = module_invoke('profile', 'load_profile', $user);
108
109 $fields = array();
110 foreach ($profile_fields as $field => $title) {
111 $value = $user->$field;
112
113 if (is_array($value)) {
114 $value = implode(',', $value);
115 }
116
46fcde43 117 $fields[$field] = $value;
8369f34c 118 }
119
23f7a9c5 120 // Only show segmentation variable if there are specified fields.
8369f34c 121 $segmentation = '';
122 if (count($fields) > 0) {
117c4d98 123 if ($legacy_version) {
46fcde43 124 $segmentation = '__utmSetVar('. drupal_to_js(implode(':', $fields)) .');';
117c4d98 125 }
126 else {
46fcde43 127 $segmentation = 'pageTracker._setVar('. drupal_to_js(implode(':', $fields)) .');';
117c4d98 128 }
8369f34c 129 }
130 }
131
1af88f22 132 // Site search tracking support.
133 $url_custom = '';
a6ef32a8 134 if (module_exists('search') && variable_get('googleanalytics_site_search', FALSE) && arg(0) == 'search' && $keys = search_get_keys()) {
135 $url_custom = drupal_to_js(url('search/'. arg(1), array('query' => 'search='. $keys)));
1af88f22 136 }
137
dcc96839 138 // If this node is a translation of another node, pass the original
139 // node instead.
140 if (module_exists('translation') && variable_get('googleanalytics_translation_set', 0)) {
141 // Check we have a node object, it supports translation, and its
142 // translated node ID (tnid) doesn't match its own node ID.
143 $node = menu_get_object();
144 if ($node && translation_supported_type($node->type) && isset($node->tnid) && ($node->tnid != $node->nid)) {
145 $source_node = node_load($node->tnid);
146 $languages = language_list();
c5af1718 147 $url_custom = drupal_to_js(url('node/'. $source_node->nid, array('language' => $languages[$source_node->language])));
dcc96839 148 }
149 }
150
7122d4fc 151 // Track access denied (403) and file not found (404) pages.
01a25886 152 if (function_exists('drupal_get_headers')) {
153 $headers = drupal_get_headers();
31139f87 154 if (strstr($headers, 'HTTP/1.1 403 Forbidden')) {
01a25886 155 if ($legacy_version) {
156 // See http://www.google.com/support/analytics/bin/answer.py?answer=86928
31139f87 157 $url_custom = '"/403.html?page=" + _udl.pathname + _udl.search';
01a25886 158 }
159 else {
160 // See http://www.google.com/support/analytics/bin/answer.py?answer=86927
31139f87 161 $url_custom = '"/403.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
162 }
163 }
164 elseif (strstr($headers, 'HTTP/1.1 404 Not Found')) {
165 if ($legacy_version) {
166 $url_custom = '"/404.html?page=" + _udl.pathname + _udl.search';
167 }
168 else {
01a25886 169 $url_custom = '"/404.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
170 }
171 }
1af88f22 172 }
173
36504c61 174 // Add any custom code snippets if specified.
bb1b0643 175 $codesnippet_before = variable_get('googleanalytics_codesnippet_before', '');
176 $codesnippet_after = variable_get('googleanalytics_codesnippet_after', '');
1dffdb18 177
117c4d98 178 // Should the legacy code be used?
83e514c4 179 $script = 'try{';
117c4d98 180 if ($legacy_version) {
46fcde43 181 $script .= '_uacct = '. drupal_to_js($id) .';';
c69ed8ef 182 if (!empty($segmentation)) {
0b7be7dc 183 $script .= $segmentation;
c69ed8ef 184 }
bb1b0643 185 if (!empty($codesnippet_before)) {
186 $script .= $codesnippet_before;
c69ed8ef 187 }
1af88f22 188 $script .= 'urchinTracker('. $url_custom .');';
bb1b0643 189 if (!empty($codesnippet_after)) {
190 $script .= $codesnippet_after;
191 }
117c4d98 192 }
193 else {
46fcde43 194 $script .= 'var pageTracker = _gat._getTracker('. drupal_to_js($id) .');';
d4ebf275 195 if (!empty($segmentation)) {
196 $script .= $segmentation;
197 }
bb1b0643 198 if (!empty($codesnippet_before)) {
199 $script .= $codesnippet_before;
23f7a9c5 200 }
1af88f22 201 $script .= 'pageTracker._trackPageview('. $url_custom .');';
bb1b0643 202 if (!empty($codesnippet_after)) {
203 $script .= $codesnippet_after;
204 }
117c4d98 205 }
83e514c4 206 $script .= '} catch(err) {}';
8369f34c 207
802831f0 208 drupal_add_js($script, 'inline', 'footer');
8369f34c 209 }
210}
211
212/**
681fdfe9 213 * Implementation of hook_user().
214 *
215 * Allow users to decide if tracking code will be added to pages or not.
216 */
217function googleanalytics_user($type, $edit, &$account, $category = NULL) {
218 switch ($type) {
219 case 'form':
26e73fce 220 if ($category == 'account' && user_access('opt-in or out of tracking') && ($custom = variable_get('googleanalytics_custom', 0)) != 0 && _googleanalytics_visibility_roles($account)) {
681fdfe9 221 $form['googleanalytics'] = array(
222 '#type' => 'fieldset',
223 '#title' => t('Google Analytics configuration'),
224 '#weight' => 3,
225 '#collapsible' => TRUE,
226 '#tree' => TRUE
227 );
850c058d 228
229 switch ($custom) {
230 case 1:
231 $title = t('Disable user tracking');
232 $description = t('Users are tracked by default, but you are able to opt out.');
233 break;
234
235 case 2:
236 $title = t('Enable user tracking');
237 $description = t('Users are <em>not</em> tracked by default, but you are able to opt in.');
238 break;
239 }
240
681fdfe9 241 $form['googleanalytics']['custom'] = array(
242 '#type' => 'checkbox',
850c058d 243 '#title' => $title,
244 '#description' => $description,
681fdfe9 245 '#default_value' => isset($account->googleanalytics['custom']) ? $account->googleanalytics['custom'] : ($custom == 1)
246 );
247
248 return $form;
249 }
250 break;
251
252 }
253}
254
255/**
8369f34c 256 * Implementation of hook_requirements().
257 */
258function googleanalytics_requirements($phase) {
259 $requirements = array();
260
261 if ($phase == 'runtime') {
262 // Raise warning if Google user account has not been set yet.
485516b7 263 if (!preg_match('/^UA-\d{4,}-\d+$/', variable_get('googleanalytics_account', 'UA-'))) {
8369f34c 264 $requirements['googleanalytics'] = array(
265 'title' => t('Google Analytics module'),
266 'description' => t('Google Analytics module has not been configured yet. Please configure its settings from the <a href="@url">Google Analytics settings page</a>.', array('@url' => url('admin/settings/googleanalytics'))),
267 'severity' => REQUIREMENT_ERROR,
268 'value' => t('Not configured'),
269 );
270 }
271 }
272
273 return $requirements;
274}
275
276/**
277 * Implementation of hook_cron().
278 */
279function googleanalytics_cron() {
69b3ea65 280 // Regenerate the google analytics urchin.js or ga.js every day.
281 if (time() - variable_get('googleanalytics_last_cache', 0) >= 86400) {
117c4d98 282 // Legacy google analytics version.
8369f34c 283 file_delete(file_directory_path() .'/googleanalytics/urchin.js');
117c4d98 284
285 // New google analytics version.
286 file_delete(file_directory_path() .'/googleanalytics/ga.js');
802831f0 287
288 // Clear aggregated JS files.
289 if (variable_get('preprocess_js', 0)) {
290 drupal_clear_js_cache();
291 }
292
69b3ea65 293 variable_set('googleanalytics_last_cache', time());
8369f34c 294 }
295}
296
297/**
298 * Download and cache the urchin.js file locally.
299 * @param $location
300 * The full URL to the external javascript file.
301 * @return mixed
302 * The path to the local javascript file on success, boolean FALSE on failure.
303 */
6b8c40e4 304function _googleanalytics_cache($location) {
8369f34c 305 $directory = file_directory_path() .'/googleanalytics';
306 $file_destination = $directory .'/'. basename($location);
307 if (!file_exists($file_destination)) {
308 $result = drupal_http_request($location);
309 if ($result->code == 200) {
310 // Check that the files directory is writable
311 if (file_check_directory($directory, FILE_CREATE_DIRECTORY)) {
312 return file_save_data($result->data, $directory .'/'. basename($location), FILE_EXISTS_REPLACE);
313 }
314 }
315 }
316 else {
317 return $file_destination;
318 }
319}
117c4d98 320
321/**
681fdfe9 322 * Tracking visibility check for an user object.
117c4d98 323 *
324 * @param $account
d37139ea 325 * A user object containing an array of roles to check.
117c4d98 326 * @return boolean
681fdfe9 327 * A decision on if the current user is being tracked by Google Analytics.
117c4d98 328 */
681fdfe9 329function _googleanalytics_visibility_user($account) {
330
331 $enabled = FALSE;
332
333 // Is current user a member of a role that should be tracked?
334 if (_googleanalytics_visibility_roles($account)) {
335
336 // Use the user's block visibility setting, if necessary.
337 if (($custom = variable_get('googleanalytics_custom', 0)) != 0) {
338 if ($account->uid && isset($account->googleanalytics['custom'])) {
339 $enabled = $account->googleanalytics['custom'];
340 }
341 else {
342 $enabled = ($custom == 1);
343 }
344 }
345 else {
346 $enabled = TRUE;
117c4d98 347 }
681fdfe9 348
117c4d98 349 }
350
681fdfe9 351 return $enabled;
352}
353
354/**
355 * Based on visibility setting this function returns TRUE if GA code should
356 * be added for the current role and otherwise FALSE.
357 */
358function _googleanalytics_visibility_roles($account) {
359
360 $enabled = FALSE;
361 $roles = variable_get('googleanalytics_roles', array());
362
363 if (array_sum($roles) > 0) {
364 // One or more roles are selected for tracking.
365 foreach (array_keys($account->roles) as $rid) {
366 // Is the current user a member of one role enabled for tracking?
367 if (isset($roles[$rid]) && $rid == $roles[$rid]) {
368 // Current user is a member of a role that should be tracked.
369 $enabled = TRUE;
370 break;
371 }
372 }
084a10a3 373 }
681fdfe9 374 else {
1dffdb18 375 // No role is selected for tracking, therefor all roles should be tracked.
681fdfe9 376 $enabled = TRUE;
117c4d98 377 }
378
681fdfe9 379 return $enabled;
117c4d98 380}
9fd52543 381
382/**
383 * Based on visibility setting this function returns TRUE if GA code should
384 * be added to the current page and otherwise FALSE.
385 */
4761ed2b 386function _googleanalytics_visibility_pages() {
9fd52543 387 static $page_match;
388
389 // Cache visibility setting in hook_init for hook_footer.
390 if (!isset($page_match)) {
391
392 $visibility = variable_get('googleanalytics_visibility', 0);
393 $pages = variable_get('googleanalytics_pages', '');
394
395 // Match path if necessary.
396 if (!empty($pages)) {
397 if ($visibility < 2) {
398 $path = drupal_get_path_alias($_GET['q']);
399 // Compare with the internal and path alias (if any).
400 $page_match = drupal_match_path($path, $pages);
401 if ($path != $_GET['q']) {
402 $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
403 }
404 // When $visibility has a value of 0, the block is displayed on
405 // all pages except those listed in $pages. When set to 1, it
406 // is displayed only on those pages listed in $pages.
407 $page_match = !($visibility xor $page_match);
408 }
409 else {
410 $page_match = drupal_eval($pages);
411 }
412 }
413 else {
414 $page_match = TRUE;
415 }
416
417 }
418 return $page_match;
419}