| 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 |
12 | define('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 | |
| 14 | function 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 |
21 | function googleanalytics_perm() { |
| e92acf6e |
22 | return array('administer google analytics', 'use PHP for tracking visibility'); |
| 9a58ec60 |
23 | } |
| 24 | |
| 8369f34c |
25 | function 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 |
40 | function 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 | */ |
| 78 | function 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 | */ |
| 180 | function 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 | */ |
| 201 | function 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 |
226 | function _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 | */ |
| 250 | function _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 | */ |
| 279 | function _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 | } |