class-tracking-analytics.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <?php
  2. /**
  3. * Tracking analytics.js class.
  4. *
  5. * @since 6.0.0
  6. *
  7. * @package MonsterInsights
  8. * @author Chris Christoff
  9. */
  10. // Exit if accessed directly
  11. if ( ! defined( 'ABSPATH' ) ) {
  12. exit;
  13. }
  14. class MonsterInsights_Tracking_Analytics extends MonsterInsights_Tracking_Abstract {
  15. /**
  16. * Holds the name of the tracking type.
  17. *
  18. * @since 6.0.0
  19. * @access public
  20. *
  21. * @var string $name Name of the tracking type.
  22. */
  23. public $name = 'analytics';
  24. /**
  25. * Version of the tracking class.
  26. *
  27. * @since 6.0.0
  28. * @access public
  29. *
  30. * @var string $version Version of the tracking class.
  31. */
  32. public $version = '1.0.0';
  33. /**
  34. * Primary class constructor.
  35. *
  36. * @since 6.0.0
  37. * @access public
  38. */
  39. public function __construct() {
  40. }
  41. /**
  42. * Get frontend tracking options.
  43. *
  44. * This function is used to return an array of parameters
  45. * for the frontend_output() function to output. These are
  46. * generally dimensions and turned on GA features.
  47. *
  48. * @since 6.0.0
  49. * @access public
  50. *
  51. * @return array Array of the options to use.
  52. */
  53. public function frontend_tracking_options( ) {
  54. global $wp_query;
  55. $options = array();
  56. $ua_code = monsterinsights_get_ua_to_output();
  57. if ( empty( $ua_code ) ) {
  58. return $options;
  59. }
  60. $track_user = monsterinsights_track_user();
  61. if ( ! $track_user ) {
  62. $options['create'] = "'create', '" . esc_js( $ua_code ) . "', '" . esc_js( 'auto' ) . "'";
  63. $options['forceSSL'] = "'set', 'forceSSL', true";
  64. $options['send'] = "'send','pageview'";
  65. return $options;
  66. }
  67. $domain = esc_attr( monsterinsights_get_option( 'subdomain_tracking', 'auto' ) );
  68. $allow_linker = monsterinsights_get_option( 'add_allow_linker', false );
  69. $allow_anchor = monsterinsights_get_option( 'allow_anchor', false );
  70. $create = array();
  71. if ( $allow_anchor ) {
  72. $create['allowAnchor'] = true;
  73. }
  74. if ( $allow_linker ) {
  75. $create['allowLinker'] = true;
  76. }
  77. if ( class_exists( 'MonsterInsights_AMP' ) ) {
  78. $create['useAmpClientId'] = true;
  79. }
  80. $create = apply_filters( 'monsterinsights_frontend_tracking_options_analytics_create', $create );
  81. if ( $create && ! empty( $create ) && is_array( $create ) ) {
  82. $create = json_encode( $create );
  83. $create = str_replace( '"', "'", $create );
  84. $options['create'] = "'create', '" . esc_js( $ua_code ). "', '" . esc_js( $domain ) . "', " . $create;
  85. } else {
  86. $options['create'] = "'create', '" . esc_js( $ua_code ) . "', '" . esc_js( $domain ) . "'";
  87. }
  88. $options['forceSSL'] = "'set', 'forceSSL', true";
  89. if ( monsterinsights_get_option( 'custom_code', false ) ) {
  90. // Add custom code to the view
  91. $options['custom_code'] = array(
  92. 'type' => 'custom_code',
  93. 'value' => stripslashes( monsterinsights_get_option( 'custom_code', '' ) ),
  94. );
  95. }
  96. // Anonymous data
  97. if ( monsterinsights_get_option( 'anonymize_ips', false ) ) {
  98. $options['anonymize_ips'] = "'set', 'anonymizeIp', true";
  99. }
  100. $options = apply_filters( 'monsterinsights_frontend_tracking_options_analytics_before_scripts', $options );
  101. // add demographics
  102. if ( monsterinsights_get_option( 'demographics', false ) ) {
  103. $options['demographics'] = "'require', 'displayfeatures'";
  104. }
  105. // Check for Enhanced link attribution
  106. if ( monsterinsights_get_option( 'enhanced_link_attribution', false ) ) {
  107. $options['enhanced_link_attribution'] = "'require', 'linkid', 'linkid.js'";
  108. }
  109. $options = apply_filters( 'monsterinsights_frontend_tracking_options_analytics_before_pageview', $options );
  110. $options = apply_filters( 'monsterinsights_frontend_tracking_options_before_pageview', $options, $this->name, $this->version );
  111. if ( is_404() ) {
  112. if ( monsterinsights_get_option( 'hash_tracking', false ) ) {
  113. $options['send'] = "'send','pageview','/404.html?page=' + document.location.pathname + document.location.search + location.hash + '&from=' + document.referrer";
  114. } else {
  115. $options['send'] = "'send','pageview','/404.html?page=' + document.location.pathname + document.location.search + '&from=' + document.referrer";
  116. }
  117. } else if ( $wp_query->is_search ) {
  118. $pushstr = "'send','pageview','/?s=";
  119. if ( (int) $wp_query->found_posts === 0 ) {
  120. $options['send'] = $pushstr . 'no-results:' . rawurlencode( $wp_query->query_vars['s'] ) . "&cat=no-results'";
  121. } else if ( (int) $wp_query->found_posts === 1 ) {
  122. $options['send'] = $pushstr . rawurlencode( $wp_query->query_vars['s'] ) . "&cat=1-result'";
  123. } else if ( $wp_query->found_posts > 1 && $wp_query->found_posts < 6 ) {
  124. $options['send'] = $pushstr . rawurlencode( $wp_query->query_vars['s'] ) . "&cat=2-5-results'";
  125. } else {
  126. $options['send'] = $pushstr . rawurlencode( $wp_query->query_vars['s'] ) . "&cat=plus-5-results'";
  127. }
  128. } else if ( monsterinsights_get_option( 'hash_tracking', false ) ) {
  129. $options['send'] = "'send','pageview', location.pathname + location.search + location.hash";
  130. } else {
  131. $options['send'] = "'send','pageview'";
  132. }
  133. $options = apply_filters( 'monsterinsights_frontend_tracking_options_analytics_end', $options );
  134. return $options;
  135. }
  136. /**
  137. * Get frontend output.
  138. *
  139. * This function is used to return the Javascript
  140. * to output in the head of the page for the given
  141. * tracking method.
  142. *
  143. * @since 6.0.0
  144. * @access public
  145. *
  146. * @return string Javascript to output.
  147. */
  148. public function frontend_output( ) {
  149. $options = $this->frontend_tracking_options();
  150. $is_debug_mode = monsterinsights_is_debug_mode();
  151. $src = apply_filters( 'monsterinsights_frontend_output_analytics_src', '//www.google-analytics.com/analytics.js' );
  152. if ( current_user_can( 'manage_options' ) && $is_debug_mode ) {
  153. $src = apply_filters( 'monsterinsights_frontend_output_analytics_src', '//www.google-analytics.com/analytics_debug.js' );
  154. }
  155. $compat = monsterinsights_get_option( 'gatracker_compatibility_mode', false );
  156. $compat = $compat ? 'window.ga = __gaTracker;' : '';
  157. $track_user = monsterinsights_track_user();
  158. $ua = monsterinsights_get_ua();
  159. $output = '';
  160. $reason = '';
  161. $attributes = apply_filters( 'monsterinsights_tracking_analytics_script_attributes', array( 'type' => "text/javascript", 'data-cfasync' => 'false' ) );
  162. $attr_string = '';
  163. if ( ! empty( $attributes ) ) {
  164. foreach( $attributes as $attr_name => $attr_value ) {
  165. if ( ! empty( $attr_name ) ) {
  166. $attr_string .= ' ' . sanitize_key( $attr_name ) . '="' . esc_attr( $attr_value ) . '"';
  167. } else {
  168. $attr_string .= ' ' . sanitize_key( $attr_value );
  169. }
  170. }
  171. }
  172. ob_start();
  173. ?>
  174. <!-- This site uses the Google Analytics by MonsterInsights plugin v<?php echo MONSTERINSIGHTS_VERSION; ?> - Using Analytics tracking - https://www.monsterinsights.com/ -->
  175. <?php if ( ! $track_user ) {
  176. if ( empty( $ua ) ) {
  177. $reason = __( 'Note: MonsterInsights is not currently configured on this site. The site owner needs to authenticate with Google Analytics in the MonsterInsights settings panel.', 'google-analytics-for-wordpress' );
  178. $output .= '<!-- ' . esc_html( $reason ) . ' -->' . PHP_EOL;
  179. } else if ( current_user_can( 'monsterinsights_save_settings' ) ) {
  180. $reason = __( 'Note: MonsterInsights does not track you as a logged in site administrator to prevent site owners from accidentally skewing their own Google Analytics data.'. PHP_EOL . 'If you are testing Google Analytics code, please do so either logged out or in the private browsing/incognito mode of your web browser.', 'google-analytics-for-wordpress' );
  181. $output .= '<!-- ' . esc_html( $reason ) . ' -->' . PHP_EOL;
  182. } else {
  183. $reason = __( 'Note: The site owner has disabled Google Analytics tracking for your user role.', 'google-analytics-for-wordpress' );
  184. $output .= '<!-- ' . esc_html( $reason ) . ' -->' . PHP_EOL;
  185. }
  186. echo $output;
  187. } ?>
  188. <?php if ( $ua ) { ?>
  189. <script<?php echo $attr_string;?>>
  190. var mi_version = '<?php echo MONSTERINSIGHTS_VERSION; ?>';
  191. var mi_track_user = <?php echo ( $track_user ? 'true' : 'false' ); ?>;
  192. var mi_no_track_reason = <?php echo ( $reason ? "'" . esc_js( $reason) . "'": "''" ); ?>;
  193. <?php do_action( 'monsterinsights_tracking_analytics_frontend_output_after_mi_track_user' ); ?>
  194. <?php if ( $this->should_do_optout() ) { ?>
  195. var disableStr = 'ga-disable-<?php echo monsterinsights_get_ua(); ?>';
  196. /* Function to detect opted out users */
  197. function __gaTrackerIsOptedOut() {
  198. return document.cookie.indexOf(disableStr + '=true') > -1;
  199. }
  200. /* Disable tracking if the opt-out cookie exists. */
  201. if ( __gaTrackerIsOptedOut() ) {
  202. window[disableStr] = true;
  203. }
  204. /* Opt-out function */
  205. function __gaTrackerOptout() {
  206. document.cookie = disableStr + '=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
  207. window[disableStr] = true;
  208. }
  209. <?php } ?>
  210. if ( mi_track_user ) {
  211. (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  212. (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  213. m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  214. })(window,document,'script','<?php echo $src; ?>','__gaTracker');
  215. <?php
  216. if ( current_user_can( 'manage_options' ) && $is_debug_mode ) {
  217. echo 'window.ga_debug = {trace: true};';
  218. }
  219. echo $compat;
  220. if ( count( $options ) >= 1 ) {
  221. foreach ( $options as $item ) {
  222. if ( ! is_array( $item ) ) {
  223. echo ' __gaTracker(' . $item . ");\n";
  224. } else if ( ! empty ( $item['value'] ) ) {
  225. echo ' ' . $item['value'] . "\n";
  226. }
  227. }
  228. }
  229. ?>
  230. } else {
  231. <?php if ( $this->should_do_optout() ) { ?>
  232. console.log( "<?php echo esc_js( $reason );?>" );
  233. (function() {
  234. /* https://developers.google.com/analytics/devguides/collection/analyticsjs/ */
  235. var noopfn = function() {
  236. return null;
  237. };
  238. var noopnullfn = function() {
  239. return null;
  240. };
  241. var Tracker = function() {
  242. return null;
  243. };
  244. var p = Tracker.prototype;
  245. p.get = noopfn;
  246. p.set = noopfn;
  247. p.send = noopfn;
  248. var __gaTracker = function() {
  249. var len = arguments.length;
  250. if ( len === 0 ) {
  251. return;
  252. }
  253. var f = arguments[len-1];
  254. if ( typeof f !== 'object' || f === null || typeof f.hitCallback !== 'function' ) {
  255. console.log( '<?php echo esc_js( __("Not running function", "google-analytics-for-wordpress" ) );?> __gaTracker(' + arguments[0] + " ....) <?php echo esc_js( __( "because you are not being tracked.", 'google-analytics-for-wordpress' ) );?> " + mi_no_track_reason );
  256. return;
  257. }
  258. try {
  259. f.hitCallback();
  260. } catch (ex) {
  261. }
  262. };
  263. __gaTracker.create = function() {
  264. return new Tracker();
  265. };
  266. __gaTracker.getByName = noopnullfn;
  267. __gaTracker.getAll = function() {
  268. return [];
  269. };
  270. __gaTracker.remove = noopfn;
  271. window['__gaTracker'] = __gaTracker;
  272. <?php echo $compat; ?>
  273. })();
  274. <?php } ?>
  275. }
  276. </script>
  277. <?php } else { ?>
  278. <!-- No UA code set -->
  279. <?php } ?>
  280. <!-- / Google Analytics by MonsterInsights -->
  281. <?php
  282. $output = ob_get_contents();
  283. ob_end_clean();
  284. return $output;
  285. }
  286. public function should_do_optout() {
  287. return ! ( defined( 'MI_NO_TRACKING_OPTOUT' ) && MI_NO_TRACKING_OPTOUT );
  288. }
  289. }