Explain users what the legacy system (urchin.js) and new (ga.js) is.
[project/google_analytics.git] / googleanalytics.module
CommitLineData
8369f34c 1<?php
2// $Id$
117c4d98 3
8369f34c 4/*
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':
17 return t('Google Analytics is a free statistics package based on the excellent Urchin system.');
18 }
19}
20
9a58ec60 21function googleanalytics_perm() {
e92acf6e 22 return array('administer google analytics', 'use PHP for tracking visibility');
9a58ec60 23}
24
8369f34c 25function googleanalytics_menu() {
26
27 $items['admin/settings/googleanalytics'] = array(
28 'title' => 'Google Analytics',
649b04ab 29 'description' => 'Configure the settings used to generate your Google Analytics tracking code.',
8369f34c 30 'page callback' => 'drupal_get_form',
485516b7 31 'page arguments' => array('googleanalytics_admin_settings_form'),
9a58ec60 32 'access arguments' => array('administer google analytics'),
8369f34c 33 'file' => 'googleanalytics.admin.inc',
34 'type' => MENU_NORMAL_ITEM,
35 );
36
37 return $items;
38}
39
d37139ea 40function googleanalytics_init() {
020b6c1c 41 global $user;
d37139ea 42
020b6c1c 43 $id = variable_get('googleanalytics_account', '');
802831f0 44
9fd52543 45 // 1. Check if the GA account number has a value.
46 // 2. Track page views based on visibility value.
47 // 3. Check if we should track the currently active user's role.
48 if (!empty($id) && _googleanalytics_visibility() && _googleanalytics_track($user)) {
020b6c1c 49 // Use the old version of Google Analytics?
50 $legacy_version = variable_get('googleanalytics_legacy_version', FALSE);
51 $scope = variable_get('googleanalytics_js_scope', 'footer');
52
020b6c1c 53 // Should a local cached copy of urchin.js or ga.js be used?
54 $js_file = ($legacy_version) ? 'urchin.js' : 'ga.js';
a911fe63 55 $url = 'http://www.google-analytics.com/'. $js_file;
020b6c1c 56
57 if (variable_get('googleanalytics_cache', 0) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC) && $source = _googleanalytics_cache($url)) {
58 drupal_add_js($source, 'module', $scope);
59 }
60 else {
a911fe63 61 $script = 'var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");';
62 $script .= 'document.write(unescape("%3Cscript src=\'" + gaJsHost + "google-analytics.com/'. $js_file .'\' type=\'text/javascript\'%3E%3C/script%3E"));';
020b6c1c 63 drupal_add_js($script, 'inline', $scope);
64 }
65
66 // Add download tracking.
67 $path = drupal_get_path('module', 'googleanalytics');
92429a1c 68 if (variable_get('googleanalytics_trackfiles', TRUE) && $trackfiles_extensions = variable_get('googleanalytics_trackfiles_extensions', GA_TRACKFILES_EXTENSIONS)) {
cf1f0ddf 69 drupal_add_js(array('googleanalytics' => array('trackDownload' => $trackfiles_extensions, 'LegacyVersion' => $legacy_version)), 'setting', 'header');
020b6c1c 70 drupal_add_js($path .'/downloadtracker.js', 'module', $scope);
71 }
d37139ea 72 }
d37139ea 73}
74
8369f34c 75/**
d37139ea 76 * Implementation of hook_footer() to insert Javascript at the end of the page.
8369f34c 77 */
78function googleanalytics_footer($main = 0) {
79 global $user;
80
81 $id = variable_get('googleanalytics_account', '');
82
9fd52543 83 if (!empty($id) && _googleanalytics_visibility() && _googleanalytics_track($user)) {
8369f34c 84
117c4d98 85 // Use the old version of Google Analytics?
d37139ea 86 $legacy_version = variable_get('googleanalytics_legacy_version', FALSE);
117c4d98 87
d37139ea 88 // Add User profile segmentation values.
8369f34c 89 if (is_array($profile_fields = variable_get('googleanalytics_segmentation', '')) && ($user->uid > 0)) {
90
91 $p = module_invoke('profile', 'load_profile', $user);
92
93 $fields = array();
94 foreach ($profile_fields as $field => $title) {
95 $value = $user->$field;
96
97 if (is_array($value)) {
98 $value = implode(',', $value);
99 }
100
46fcde43 101 $fields[$field] = $value;
8369f34c 102 }
103
23f7a9c5 104 // Only show segmentation variable if there are specified fields.
8369f34c 105 $segmentation = '';
106 if (count($fields) > 0) {
117c4d98 107 if ($legacy_version) {
46fcde43 108 $segmentation = '__utmSetVar('. drupal_to_js(implode(':', $fields)) .');';
117c4d98 109 }
110 else {
46fcde43 111 $segmentation = 'pageTracker._setVar('. drupal_to_js(implode(':', $fields)) .');';
117c4d98 112 }
8369f34c 113 }
114 }
115
1af88f22 116 // Site search tracking support.
117 $url_custom = '';
a7495234 118 if (module_exists('search') && variable_get('googleanalytics_site_search', FALSE) && arg(0) == 'search') {
1af88f22 119 $keys = search_get_keys();
01a25886 120 $url_custom = drupal_to_js(url('search/'. arg(1), array('query' => 'search='. trim($keys))));
1af88f22 121 }
122
7122d4fc 123 // Track access denied (403) and file not found (404) pages.
01a25886 124 if (function_exists('drupal_get_headers')) {
125 $headers = drupal_get_headers();
31139f87 126 if (strstr($headers, 'HTTP/1.1 403 Forbidden')) {
01a25886 127 if ($legacy_version) {
128 // See http://www.google.com/support/analytics/bin/answer.py?answer=86928
31139f87 129 $url_custom = '"/403.html?page=" + _udl.pathname + _udl.search';
01a25886 130 }
131 else {
132 // See http://www.google.com/support/analytics/bin/answer.py?answer=86927
31139f87 133 $url_custom = '"/403.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
134 }
135 }
136 elseif (strstr($headers, 'HTTP/1.1 404 Not Found')) {
137 if ($legacy_version) {
138 $url_custom = '"/404.html?page=" + _udl.pathname + _udl.search';
139 }
140 else {
01a25886 141 $url_custom = '"/404.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer';
142 }
143 }
1af88f22 144 }
145
36504c61 146 // Add any custom code snippets if specified.
147 $codesnippet = variable_get('googleanalytics_codesnippet', '');
148
117c4d98 149 // Should the legacy code be used?
802831f0 150 $script = '';
117c4d98 151 if ($legacy_version) {
46fcde43 152 $script .= '_uacct = '. drupal_to_js($id) .';';
c69ed8ef 153 if (!empty($segmentation)) {
0b7be7dc 154 $script .= $segmentation;
c69ed8ef 155 }
156 if (!empty($codesnippet)) {
0b7be7dc 157 $script .= $codesnippet;
c69ed8ef 158 }
1af88f22 159 $script .= 'urchinTracker('. $url_custom .');';
117c4d98 160 }
161 else {
46fcde43 162 $script .= 'var pageTracker = _gat._getTracker('. drupal_to_js($id) .');';
c69ed8ef 163 $script .= 'pageTracker._initData();';
d4ebf275 164 if (!empty($segmentation)) {
165 $script .= $segmentation;
166 }
23f7a9c5 167 if (!empty($codesnippet)) {
168 $script .= $codesnippet;
169 }
1af88f22 170 $script .= 'pageTracker._trackPageview('. $url_custom .');';
117c4d98 171 }
8369f34c 172
802831f0 173 drupal_add_js($script, 'inline', 'footer');
8369f34c 174 }
175}
176
177/**
178 * Implementation of hook_requirements().
179 */
180function googleanalytics_requirements($phase) {
181 $requirements = array();
182
183 if ($phase == 'runtime') {
184 // Raise warning if Google user account has not been set yet.
485516b7 185 if (!preg_match('/^UA-\d{4,}-\d+$/', variable_get('googleanalytics_account', 'UA-'))) {
8369f34c 186 $requirements['googleanalytics'] = array(
187 'title' => t('Google Analytics module'),
188 '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'))),
189 'severity' => REQUIREMENT_ERROR,
190 'value' => t('Not configured'),
191 );
192 }
193 }
194
195 return $requirements;
196}
197
198/**
199 * Implementation of hook_cron().
200 */
201function googleanalytics_cron() {
69b3ea65 202 // Regenerate the google analytics urchin.js or ga.js every day.
203 if (time() - variable_get('googleanalytics_last_cache', 0) >= 86400) {
117c4d98 204 // Legacy google analytics version.
8369f34c 205 file_delete(file_directory_path() .'/googleanalytics/urchin.js');
117c4d98 206
207 // New google analytics version.
208 file_delete(file_directory_path() .'/googleanalytics/ga.js');
802831f0 209
210 // Clear aggregated JS files.
211 if (variable_get('preprocess_js', 0)) {
212 drupal_clear_js_cache();
213 }
214
69b3ea65 215 variable_set('googleanalytics_last_cache', time());
8369f34c 216 }
217}
218
219/**
220 * Download and cache the urchin.js file locally.
221 * @param $location
222 * The full URL to the external javascript file.
223 * @return mixed
224 * The path to the local javascript file on success, boolean FALSE on failure.
225 */
6b8c40e4 226function _googleanalytics_cache($location) {
8369f34c 227 $directory = file_directory_path() .'/googleanalytics';
228 $file_destination = $directory .'/'. basename($location);
229 if (!file_exists($file_destination)) {
230 $result = drupal_http_request($location);
231 if ($result->code == 200) {
232 // Check that the files directory is writable
233 if (file_check_directory($directory, FILE_CREATE_DIRECTORY)) {
234 return file_save_data($result->data, $directory .'/'. basename($location), FILE_EXISTS_REPLACE);
235 }
236 }
237 }
238 else {
239 return $file_destination;
240 }
241}
117c4d98 242
243/**
244 *
245 * @param $account
d37139ea 246 * A user object containing an array of roles to check.
117c4d98 247 * @return boolean
d37139ea 248 * A decision on if the current user is being tracked by GAnalytics.
117c4d98 249 */
250function _googleanalytics_track($account) {
084a10a3 251 // By default we don't track users.
252 $track = FALSE;
117c4d98 253
254 foreach (array_keys($account->roles) as $role) {
084a10a3 255 // Add the tracking code if user is member of one role that should be tracked.
256 if (variable_get('googleanalytics_track_'. $role, FALSE)) {
257 $track = TRUE;
117c4d98 258 }
259 }
260
084a10a3 261 // Handle behavior for administrative user 1.
262 if ($account->uid == 1 && variable_get('googleanalytics_track__user1', FALSE)) {
263 // Enable tracking of user 1 if tracking for "authenticated user" is disabled.
264 $track = TRUE;
265 }
266 elseif ($account->uid == 1 && !variable_get('googleanalytics_track__user1', FALSE)) {
267 // User 1 is a member of "authenticated user". Disable user tracking
d37139ea 268 // if user 1 shouldn't be tracked, but "authenticated user" should.
117c4d98 269 $track = FALSE;
270 }
271
272 return $track;
273}
9fd52543 274
275/**
276 * Based on visibility setting this function returns TRUE if GA code should
277 * be added to the current page and otherwise FALSE.
278 */
279function _googleanalytics_visibility() {
280 static $page_match;
281
282 // Cache visibility setting in hook_init for hook_footer.
283 if (!isset($page_match)) {
284
285 $visibility = variable_get('googleanalytics_visibility', 0);
286 $pages = variable_get('googleanalytics_pages', '');
287
288 // Match path if necessary.
289 if (!empty($pages)) {
290 if ($visibility < 2) {
291 $path = drupal_get_path_alias($_GET['q']);
292 // Compare with the internal and path alias (if any).
293 $page_match = drupal_match_path($path, $pages);
294 if ($path != $_GET['q']) {
295 $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
296 }
297 // When $visibility has a value of 0, the block is displayed on
298 // all pages except those listed in $pages. When set to 1, it
299 // is displayed only on those pages listed in $pages.
300 $page_match = !($visibility xor $page_match);
301 }
302 else {
303 $page_match = drupal_eval($pages);
304 }
305 }
306 else {
307 $page_match = TRUE;
308 }
309
310 }
311 return $page_match;
312}