'gtag.js', ]; } /** * Implements hook_help(). */ function google_analytics_help($route_name, RouteMatchInterface $route_match) { switch ($route_name) { case 'help.page.google_analytics': $output = '

' . t('About') . '

'; $output .= '

' . t('Google Analytics adds a web statistics tracking system to your website. This system incorporates numerous statistical features. For an extensive listing of these features see the Google Analytics project site. Beyond that, additional information can be found at the Drupal - Google Analytics documentation.', [':documentation' => 'https://www.drupal.org/node/37694', ':project' => 'https://www.drupal.org/project/google_analytics']) . '

'; $output .= '

' . t('Uses') . '

'; $output .= '
' . t('Configuring Google Analytics') . '
'; $output .= '
' . t('All settings for this module can be found on the Google Analytics settings page. When entering the Google Analytics account number here, it will automatically add the required JavaScript to every page generated. The General Settings section on this page provides additional instruction about setting up tracking thru the Google account.', [':ga_settings' => Url::fromRoute('google_analytics.admin_settings_form')->toString()]) . '
'; $output .= '
' . t('Additional features') . '
'; $output .= '
' . t('The Google Analytics module offers a bit more than basic tracking. Page Tracking for instance allows you to provide a list of pages to track, or a list of pages not to track. Role and Link tracking features are also available. For a comprehensive discussion on the setup and use of its many feature see the Drupal - Google Analytics documentation.', [':documentation' => 'https://www.drupal.org/node/37694']) . '
'; return $output; case 'google_analytics.admin_settings_form': return t('Google Analytics is a free (registration required) website traffic and marketing effectiveness service.', [':ga_url' => 'https://marketingplatform.google.com/about/analytics/']); } } /** * Implements hook_page_attachments(). * * Insert JavaScript to the appropriate scope/region of the page. */ function google_analytics_page_attachments(array &$page) { $account = \Drupal::currentUser(); $config = \Drupal::config('google_analytics.settings'); $request = \Drupal::request(); /** @var \Drupal\google_analytics\Helpers\VisiblityTracker $visibilityTracker */ $visibilityTracker = \Drupal::service('google_analytics.visibility'); /** @var \Drupal\google_analytics\Helpers\GoogleAnalyticsAccounts $ga_accounts */ $ga_accounts = \Drupal::service('google_analytics.accounts'); // Add module cache tags. $page['#cache']['tags'] = Cache::mergeTags(isset($page['#cache']['tags']) ? $page['#cache']['tags'] : [], $config->getCacheTags()); // Get page http status code for visibility filtering. $status = NULL; if ($exception = $request->attributes->get('exception')) { $status = $exception->getStatusCode(); } $trackable_status_codes = [ // "Forbidden" status code. '403', // "Not Found" status code. '404', ]; // 1. Check if the GA account number has a valid value. // 2. Track page views based on visibility value. // 3. Check if we should track the currently active user's role. // 4. Ignore pages visibility filter for 404 or 403 status codes. if ($ga_accounts->getDefaultMeasurementId() && ($visibilityTracker->getVisibilityPages() || in_array($status, $trackable_status_codes)) && $visibilityTracker->getUserVisibilty($account)) { $default_id = $ga_accounts->getDefaultMeasurementId(); // Init variables. $debug = $config->get('debug'); $url_custom = ''; // Instantiate our event. $javascript = new GaJavascriptObject($default_id); // Add link tracking. $link_settings = ['account' => (string) $default_id]; if ($track_outbound = $config->get('track.outbound')) { $link_settings['trackOutbound'] = $track_outbound; } if ($track_mailto = $config->get('track.mailto')) { $link_settings['trackMailto'] = $track_mailto; } if ($track_tel = $config->get('track.tel')) { $link_settings['trackTel'] = $track_tel; } if (($track_download = $config->get('track.files')) && ($trackfiles_extensions = $config->get('track.files_extensions'))) { $link_settings['trackDownload'] = $track_download; $link_settings['trackDownloadExtensions'] = $trackfiles_extensions; } if ((\Drupal::moduleHandler()->moduleExists('colorbox')) && $track_colorbox = $config->get('track.colorbox')) { $link_settings['trackColorbox'] = $track_colorbox; } if ($track_domain_mode = $config->get('domain_mode')) { $link_settings['trackDomainMode'] = $track_domain_mode; } if ($track_cross_domains = $config->get('cross_domains')) { $link_settings['trackCrossDomains'] = preg_split('/(\r\n?|\n)/', $track_cross_domains); } if ($track_url_fragments = $config->get('track.urlfragments')) { $link_settings['trackUrlFragments'] = $track_url_fragments; } $page['#attached']['drupalSettings']['google_analytics'] = $link_settings; // Add debugging code. if ($debug) { $page['#attached']['library'][] = 'google_analytics/google_analytics.debug'; // phpcs:disable // Add the JS test in development to the page. // $page['#attached']['library'][] = 'google_analytics/google_analytics.test'; // phpcs:enable } else { $page['#attached']['library'][] = 'google_analytics/google_analytics'; } if ($config->get('track.adsense')) { // Custom tracking. Prepend before all other JavaScript. // @TODO: https://support.google.com/adsense/answer/98142 // sounds like it could be appended to $script. $script = $javascript->getAdsenseScript(); } // Build tracker code. $script = 'window.dataLayer = window.dataLayer || [];'; $script .= 'function gtag(){dataLayer.push(arguments)};'; $script .= 'gtag("js", new Date());'; $script .= 'gtag("set", "developer_id.dMDhkMT", true);'; // Add any custom code snippets if specified. $codesnippet_before = $config->get('codesnippet.before'); $codesnippet_after = $config->get('codesnippet.after'); // Create a tracker. if (!empty($codesnippet_before)) { $script .= $codesnippet_before; } // Create a config for each account. foreach($ga_accounts->getAccounts() as $account) { $ga_config = new GoogleAnalyticsConfigEvent($javascript, $account); // Get the event_dispatcher service and dispatch the event. $event_dispatcher = \Drupal::service('event_dispatcher'); $event_dispatcher->dispatch($ga_config, GoogleAnalyticsEvents::ADD_CONFIG); // Json::encode() cannot convert custom URLs properly. $config_array = $ga_config->getConfig(); $path = ''; $path_type = ''; if (isset($config_array['page'])) { $path_type = substr($config_array['page_placeholder'], strlen('PLACEHOLDER_')); $path = $config_array['page']; $config_array[$path_type] = $config_array['page_placeholder']; unset($config_array['page']); unset($config_array['page_placeholder']); } $arguments_json = Json::encode($config_array); $arguments_json = str_replace('"PLACEHOLDER_'.$path_type.'"', $path, $arguments_json); $script .= 'gtag("config", ' . Json::encode((string)$account) . ', ' . $arguments_json . ');'; } $ga_events = new GoogleAnalyticsEventsEvent($javascript); // Get the event_dispatcher service and dispatch the event. $event_dispatcher = \Drupal::service('event_dispatcher'); $event_dispatcher->dispatch($ga_events, GoogleAnalyticsEvents::ADD_EVENT); if (!empty($ga_events->getEvents())) { foreach ($ga_events->getEvents() as $event) { $event_name = array_key_first($event); $event_parameters = $event[$event_name]; $script .= 'gtag("event", ' . Json::encode($event_name) . ', ' . Json::encode($event_parameters) . ');'; } } if (!empty($codesnippet_after)) { $script .= $codesnippet_after; } // Prepend tracking library directly before script code. $javascript_service = \Drupal::service('google_analytics.javascript_cache'); $page['#attached']['html_head'][] = [ [ '#tag' => 'script', '#attributes' => [ 'async' => TRUE, 'src' => $javascript_service->fetchGoogleAnalyticsJavascript($default_id), ], ], 'google_analytics_tracking_file', ]; $page['#attached']['html_head'][] = [ [ '#tag' => 'script', '#value' => new GoogleAnalyticsJavaScriptSnippet($script), ], 'google_analytics_tracking_script', ]; } } /** * Implements hook_entity_extra_field_info(). */ function google_analytics_entity_extra_field_info() { $extra['user']['user']['form']['google_analytics'] = [ 'label' => t('Google Analytics settings'), 'description' => t('Google Analytics module form element.'), 'weight' => 3, ]; return $extra; } /** * Implements hook_form_FORM_ID_alter(). */ function google_analytics_form_user_form_alter(&$form, FormStateInterface $form_state) { $config = \Drupal::config('google_analytics.settings'); /** @var Drupal\user\ProfileForm $profileForm */ $profileForm = $form_state->getFormObject(); /** @var Drupal\user\Entity\User $account */ $account = $profileForm->getEntity(); /** @var \Drupal\google_analytics\Helpers\VisiblityTracker $visibilityTracker */ $visibilityTracker = \Drupal::service('google_analytics.visibility'); if ($account->hasPermission('opt-in or out of google analytics tracking') && ($visibility_user_account_mode = $config->get('visibility.user_account_mode')) != 0 && $visibilityTracker->getVisibilityRoles($account)) { $account_data_google_analytics = \Drupal::service('user.data')->get('google_analytics', $account->id()); $form['google_analytics'] = [ '#type' => 'details', '#title' => t('Google Analytics settings'), '#weight' => 3, '#open' => TRUE, ]; $description = ''; switch ($visibility_user_account_mode) { case 1: $description = t('Users are tracked by default, but you are able to opt out.'); break; case 2: $description = t('Users are not tracked by default, but you are able to opt in.'); break; } $form['google_analytics']['user_account_users'] = [ '#type' => 'checkbox', '#title' => t('Enable user tracking'), '#description' => $description, '#default_value' => isset($account_data_google_analytics['user_account_users']) ? $account_data_google_analytics['user_account_users'] : ($visibility_user_account_mode == 1), ]; // hook_user_update() is missing in D8, add custom submit handler. $form['actions']['submit']['#submit'][] = 'google_analytics_user_profile_form_submit'; } } /** * Submit callback for user profile form to save the Google Analytics setting. */ function google_analytics_user_profile_form_submit($form, FormStateInterface $form_state) { /** @var Drupal\user\ProfileForm $profileForm */ $profileForm = $form_state->getFormObject(); /** @var Drupal\user\Entity\User $account */ $account = $profileForm->getEntity(); if ($account->id() && $form_state->hasValue('user_account_users')) { \Drupal::service('user.data')->set('google_analytics', $account->id(), 'user_account_users', (int) $form_state->getValue('user_account_users')); } } /** * Implements hook_cron(). */ function google_analytics_cron() { $config = \Drupal::config('google_analytics.settings'); $request_time = \Drupal::time()->getRequestTime(); $javascript_service = \Drupal::service('google_analytics.javascript_cache'); $ga_accounts = \Drupal::service('google_analytics.accounts'); // Return prematurely if no default measurement ID was found. if (empty($ga_accounts->getDefaultMeasurementId())) { return; } // Regenerate the tracking code file every day. if ($request_time - \Drupal::state()->get('google_analytics.last_cache') >= 86400 && $config->get('cache')) { $javascript_service->fetchGoogleAnalyticsJavascript($ga_accounts->getDefaultMeasurementId(), TRUE); \Drupal::state()->set('google_analytics.last_cache', $request_time); } } /** * Implements hook_preprocess_item_list__search_results(). * * Collects and adds the number of search results to the head. */ function google_analytics_preprocess_item_list__search_results(&$variables) { $config = \Drupal::config('google_analytics.settings'); // Only run on search results list. if ($config->get('track.site_search')) { // Get the pager manager to give us the number of items returned. /** @var \Drupal\Core\Pager\PagerManagerInterface $pager_manager */ $pager_manager = \Drupal::service('pager.manager'); $items = 0; if ($pager_manager->getPager()) { $items = $pager_manager->getPager()->getTotalItems(); } $variables['#attached']['html_head'][] = [ [ '#tag' => 'script', '#value' => 'window.google_analytics_search_results = ' . $items . ';', '#weight' => JS_LIBRARY - 1, ], 'google_analytics_search_script', ]; } }