Yoast_GA_Tracking

The basic frontend tracking class for the GA plugin, extendable for the children.

Defined (1)

The class is defined in the following location(s).

/frontend/abstract-class-tracking.php  
  1. abstract class Yoast_GA_Tracking { 
  2.  
  3. /** 
  4. * Regular expression for Ga.js and universal tracking to detect links 
  5. * @var string 
  6. */ 
  7. protected $link_regex = '/<a([^>]*)\shref=([\'\"])([a-zA-Z]+):(?:\/) {2}?(.*)\2([^>]*)>(.*)<\/a>/isU'; 
  8.  
  9. /** 
  10. * Storage for the currently set options 
  11. * @var mixed|void 
  12. */ 
  13. public $options; 
  14.  
  15. /** 
  16. * @var boolean $do_tracking Should the tracking code be added 
  17. */ 
  18. protected $do_tracking = null; 
  19.  
  20. /** 
  21. * Function to output the GA Tracking code in the wp_head() 
  22. * @param bool $return_array 
  23. * @return mixed 
  24. */ 
  25. abstract public function tracking( $return_array = false ); 
  26.  
  27. /** 
  28. * Output tracking link 
  29. * @param string $label 
  30. * @param array $matches 
  31. * @return mixed 
  32. */ 
  33. abstract protected function output_parse_link( $label, $matches ); 
  34.  
  35. /** 
  36. * Class constructor 
  37. */ 
  38. public function __construct() { 
  39. $options_class = $this->get_options_class(); 
  40. $this->options = $options_class->options; 
  41.  
  42. add_action( 'wp_head', array( $this, 'tracking' ), 8 ); 
  43.  
  44. if ( $this->options['track_outbound'] == 1 ) { 
  45. $this->track_outbound_filters(); 
  46.  
  47. /** 
  48. * Get the options class 
  49. * @return object|Yoast_GA_Options 
  50. */ 
  51. protected function get_options_class() { 
  52. return Yoast_GA_Options::instance(); 
  53.  
  54. /** 
  55. * Delegates `get_tracking_code` to the options class 
  56. * @return null 
  57. */ 
  58. public function get_tracking_code() { 
  59. return $this->get_options_class()->get_tracking_code(); 
  60.  
  61. /** 
  62. * Get 1 or 0 if we need to do enhanced link attribution 
  63. * @return mixed 
  64. */ 
  65. public function get_enhanced_link_attribution() { 
  66. return $this->options['enhanced_link_attribution']; 
  67.  
  68. /** 
  69. * Parse article link 
  70. * @param array $matches 
  71. * @return mixed 
  72. */ 
  73. public function parse_article_link( $matches ) { 
  74. return $this->output_parse_link( 'outbound-article', $matches ); 
  75.  
  76. /** 
  77. * Parse comment link 
  78. * @param array $matches 
  79. * @return mixed 
  80. */ 
  81. public function parse_comment_link( $matches ) { 
  82. return $this->output_parse_link( 'outbound-comment', $matches ); 
  83.  
  84. /** 
  85. * Parse widget link 
  86. * @param array $matches 
  87. * @return mixed 
  88. */ 
  89. public function parse_widget_link( $matches ) { 
  90. return $this->output_parse_link( 'outbound-widget', $matches ); 
  91.  
  92. /** 
  93. * Parse menu link 
  94. * @param array $matches 
  95. * @return mixed 
  96. */ 
  97. public function parse_nav_menu( $matches ) { 
  98. return $this->output_parse_link( 'outbound-menu', $matches ); 
  99.  
  100. /** 
  101. * Parse the_content or the_excerpt for links 
  102. * @param string $text 
  103. * @return mixed 
  104. */ 
  105. public function the_content( $text ) { 
  106. if ( false === $this->do_tracking() ) { 
  107. return $text; 
  108.  
  109. if ( ! is_feed() ) { 
  110. $text = preg_replace_callback( $this->link_regex, array( $this, 'parse_article_link' ), $text ); 
  111.  
  112. return $text; 
  113.  
  114. /** 
  115. * Parse the widget content for links 
  116. * @param string $text 
  117. * @return mixed 
  118. */ 
  119. public function widget_content( $text ) { 
  120. if ( ! $this->do_tracking() ) { 
  121. return $text; 
  122. $text = preg_replace_callback( $this->link_regex, array( $this, 'parse_widget_link' ), $text ); 
  123.  
  124. return $text; 
  125.  
  126. /** 
  127. * Parse the nav menu for links 
  128. * @param string $text 
  129. * @return mixed 
  130. */ 
  131. public function nav_menu( $text ) { 
  132. if ( ! $this->do_tracking() ) { 
  133. return $text; 
  134.  
  135. if ( ! is_feed() ) { 
  136. $text = preg_replace_callback( $this->link_regex, array( $this, 'parse_nav_menu' ), $text ); 
  137.  
  138. return $text; 
  139.  
  140. /** 
  141. * Parse comment text for links 
  142. * @param string $text 
  143. * @return mixed 
  144. */ 
  145. public function comment_text( $text ) { 
  146. if ( ! $this->do_tracking() ) { 
  147. return $text; 
  148.  
  149. if ( ! is_feed() ) { 
  150. $text = preg_replace_callback( $this->link_regex, array( $this, 'parse_comment_link' ), $text ); 
  151.  
  152. return $text; 
  153.  
  154. /** 
  155. * Parse the domain 
  156. * @param string $uri 
  157. * @return array|bool 
  158. */ 
  159. public function yoast_ga_get_domain( $uri ) { 
  160. $hostPattern = '/^(https?:\/\/)?([^\/]+)/i'; 
  161. $domainPatternUS = '/[^\.\/]+\.[^\.\/]+$/'; 
  162. $domainPatternUK = '/[^\.\/]+\.[^\.\/]+\.[^\.\/]+$/'; 
  163.  
  164. $matching = preg_match( $hostPattern, $uri, $matches ); 
  165. if ( $matching ) { 
  166. $host = $matches[2]; 
  167. if ( preg_match( '/.*\..*\..*\..*$/', $host ) ) { 
  168. preg_match( $domainPatternUK, $host, $matches ); 
  169. else { 
  170. preg_match( $domainPatternUS, $host, $matches ); 
  171.  
  172. if ( isset( $matches[0] ) ) { 
  173. return array( 'domain' => $matches[0], 'host' => $host ); 
  174.  
  175. return false; 
  176.  
  177. /** 
  178. * Merge the existing onclick with a new one and append it 
  179. * @param string $link_attribute 
  180. * @param string $onclick 
  181. * @return string 
  182. */ 
  183. public function output_add_onclick( $link_attribute, $onclick ) { 
  184. if ( preg_match( '/onclick=[\'\"](.*?;)[\'\"]/i', $link_attribute, $matches ) > 0 ) { 
  185. $js_snippet_single = 'onclick=\'' . $matches[1] . ' ' . $onclick . '\''; 
  186. $js_snippet_double = 'onclick="' . $matches[1] . ' ' . $onclick . '"'; 
  187.  
  188. $link_attribute = str_replace( 'onclick="' . $matches[1] . '"', $js_snippet_double, $link_attribute ); 
  189. $link_attribute = str_replace( "onclick='" . $matches[1] . "'", $js_snippet_single, $link_attribute ); 
  190.  
  191. return $link_attribute; 
  192. else { 
  193. if ( ! is_null( $onclick ) ) { 
  194. return 'onclick="' . $onclick . '" ' . $link_attribute; 
  195. else { 
  196. return $link_attribute; 
  197.  
  198. /** 
  199. * Generate the full URL 
  200. * @param string $link 
  201. * @return string 
  202. */ 
  203. public function make_full_url( $link ) { 
  204. switch ( $link['type'] ) { 
  205. case 'download': 
  206. case 'internal': 
  207. case 'internal-as-outbound': 
  208. case 'outbound': 
  209. return $link['protocol'] . '://' . $link['original_url']; 
  210. break; 
  211. case 'email': 
  212. return 'mailto:' . $link['original_url']; 
  213. break; 
  214.  
  215. /** 
  216. * Setting the filters for tracking outbound links 
  217. */ 
  218. protected function track_outbound_filters() { 
  219. add_filter( 'the_content', array( $this, 'the_content' ), 99 ); 
  220. add_filter( 'widget_text', array( $this, 'widget_content' ), 99 ); 
  221. add_filter( 'wp_list_bookmarks', array( $this, 'widget_content' ), 99 ); 
  222. add_filter( 'wp_nav_menu', array( $this, 'widget_content' ), 99 ); 
  223. add_filter( 'the_excerpt', array( $this, 'the_content' ), 99 ); 
  224. add_filter( 'comment_text', array( $this, 'comment_text' ), 99 ); 
  225.  
  226. /** 
  227. * Check if we need to show an actual tracking code 
  228. * @return bool 
  229. */ 
  230. public function do_tracking() { 
  231. if ( $this->do_tracking === null ) { 
  232. $user = wp_get_current_user(); 
  233. $this->do_tracking = true; 
  234.  
  235. if ( 0 != $user->ID && isset( $this->options['ignore_users'] ) ) { 
  236. if ( ! empty( $user->roles ) && in_array( $user->roles[0], $this->options['ignore_users'] ) ) { 
  237. $this->do_tracking = false; 
  238.  
  239. /** 
  240. * Filter: 'yst_ga_track_super_admin' - Allows filtering if the Super admin should be tracked in a multi-site setup 
  241. * @api array $all_roles 
  242. */ 
  243. $track_super_admin = apply_filters( 'yst_ga_track_super_admin', true ); 
  244. if ( $track_super_admin === false && is_super_admin() ) { 
  245. $this->do_tracking = false; 
  246.  
  247. return $this->do_tracking; 
  248.  
  249. /** 
  250. * Return the target with a lot of parameters 
  251. * @param string $category 
  252. * @param array $matches 
  253. * @return array 
  254. */ 
  255. protected function get_target( $category, $matches ) { 
  256. $protocol = $matches[3]; 
  257. $original_url = $matches[4]; 
  258. $domain = $this->yoast_ga_get_domain( $matches[4] ); 
  259. $http_host = empty( $_SERVER['HTTP_HOST'] ) ? '' : $_SERVER['HTTP_HOST']; 
  260. $origin = $this->yoast_ga_get_domain( $http_host ); 
  261. $extension = substr( strrchr( $original_url, '.' ), 1 ); 
  262. $type = $this->get_target_type( $extension, $domain, $origin, $matches ); 
  263.  
  264. return array( 
  265. 'category' => $category,  
  266. 'type' => $type,  
  267. 'protocol' => $protocol,  
  268. 'domain' => $domain['domain'],  
  269. 'host' => $domain['host'],  
  270. 'origin_domain' => $origin['domain'],  
  271. 'origin_host' => $origin['host'],  
  272. 'extension' => $extension,  
  273. 'link_attributes' => trim( $matches[1] . ' ' . $matches[5] ),  
  274. 'link_text' => $matches[6],  
  275. 'original_url' => $original_url,  
  276. ); 
  277.  
  278. /** 
  279. * Getting the type for current target 
  280. * @param string $extension 
  281. * @param array $domain 
  282. * @param array $origin 
  283. * @param array $matches 
  284. * @return null|string 
  285. */ 
  286. protected function get_target_type( $extension, $domain, $origin, $matches ) { 
  287. $download_extensions = explode( ', ', str_replace( '.', '', $this->options['extensions_of_files'] ) ); 
  288. $download_extensions = array_map( 'trim', $download_extensions ); 
  289. $protocol = $matches[3]; 
  290. $original_url = $matches[4]; 
  291.  
  292. // Break out immediately if the link is not an http or https link. 
  293. $type = null; 
  294. if ( $protocol !== 'http' && $protocol !== 'https' && $protocol !== 'mailto' ) { 
  295. $type = null; 
  296. else { 
  297. if ( ( $protocol == 'mailto' ) ) { 
  298. $type = 'email'; 
  299. elseif ( in_array( $extension, $download_extensions ) ) { 
  300. $type = 'download'; 
  301. else { 
  302. $type = $this->parse_outbound_type( $domain, $origin, $original_url ); 
  303.  
  304. return $type; 
  305.  
  306. /** 
  307. * Parse the type for outbound links 
  308. * @param array $domain 
  309. * @param array $origin 
  310. * @param string $original_url 
  311. * @return string 
  312. */ 
  313. protected function parse_outbound_type( $domain, $origin, $original_url ) { 
  314. $type = null; 
  315.  
  316. if ( $domain['domain'] == $origin['domain'] ) { 
  317. $out_links = explode( ', ', $this->options['track_internal_as_outbound'] ); 
  318. $out_links = array_unique( array_map( 'trim', $out_links ) ); 
  319.  
  320. if ( ! empty( $original_url ) && ! empty( $domain['domain'] ) && count( $out_links ) >= 1 ) { 
  321. foreach ( $out_links as $out ) { 
  322. if ( ! empty( $out ) && strpos( $original_url, $domain['domain'] . $out ) !== false ) { 
  323. $type = 'internal-as-outbound'; 
  324.  
  325. if ( ! isset( $type ) ) { 
  326. $type = 'internal'; 
  327. elseif ( $domain['domain'] != $origin['domain'] ) { 
  328. $type = 'outbound'; 
  329.  
  330. return $type; 
  331.  
  332. /** 
  333. * Trims the track_internal_as_label option to prevent commas and whitespaces 
  334. * @return string 
  335. */ 
  336. protected function sanitize_internal_label() { 
  337. if ( ! is_null( $this->options['track_internal_as_label'] ) && ! empty( $this->options['track_internal_as_label'] ) ) { 
  338. $label = $this->options['track_internal_as_label']; 
  339. $label = trim( $label, ', ' ); 
  340. $label = trim( $label ); 
  341.  
  342. // Be sure label isn't empty, if so, set value with in 
  343. if ( empty( $label ) ) { 
  344. $label = 'int'; 
  345.  
  346. return $label; 
  347.  
  348. /** 
  349. * When a usergroup is disabled, show a message in the source to notify the user they are in a disabled user group. 
  350. */ 
  351. protected function disabled_usergroup() { 
  352. /** translators %1$s is the product name 'Google Analytics by MonsterInsights'. %2$s displays the plugin version the website uses and a link to the plugin on MonsterInsights.com */ 
  353. echo '<!-- ' . sprintf( __( 'This site uses the %1$s plugin version %2$s', 'google-analytics-for-wordpress' ), 'Google Analytics by MonsterInsights', GAWP_VERSION . ' - https://www.monsterinsights.com/' ) . ' -->'; 
  354.  
  355. if ( current_user_can( 'manage_options' ) ) { 
  356. echo '<!-- ' . __( '@Webmaster, normally you will find the Google Analytics tracking code here, but you are in the disabled user groups. To change this, navigate to Analytics -> Settings (Ignore usergroups)', 'google-analytics-for-wordpress' ) . ' -->'; 
  357. else { 
  358. echo '<!-- ' . __( 'Normally you will find the Google Analytics tracking code here, but the webmaster disabled your user group.', 'google-analytics-for-wordpress' ) . ' -->'; 
  359.  
  360. // Do not make this translatable, as this is the product name. 
  361. echo '<!-- / Google Analytics by MonsterInsights -->'; 
  362.  
  363. /** 
  364. * When the debug mode is enabled, display a message in the source. 
  365. * @return bool 
  366. */ 
  367. protected function debug_mode() { 
  368. if ( $this->options['debug_mode'] === 1 ) { 
  369. /** translators %1$s is the product name 'Google Analytics by MonsterInsights'. %2$s displays the plugin version the website uses and a link to the plugin on MonsterInsights.com */ 
  370. echo '<!-- ' . sprintf( __( 'This site uses the %1$s plugin version %2$s', 'google-analytics-for-wordpress' ), 'Google Analytics by MonsterInsights', GAWP_VERSION . ' - https://www.monsterinsights.com/' ) . ' -->'; 
  371.  
  372. if ( current_user_can( 'manage_options' ) ) { 
  373. echo '<!-- ' . __( '@Webmaster, normally you will find the Google Analytics tracking code here, but the Debug Mode is enabled. To change this, navigate to Analytics -> Settings -> (Tab) Debug Mode and disable Debug Mode to enable tracking of your site.', 'google-analytics-for-wordpress' ) . ' -->'; 
  374. else { 
  375. echo '<!-- ' . __( 'Normally you will find the Google Analytics tracking code here, but the webmaster has enabled the Debug Mode.', 'google-analytics-for-wordpress' ) . ' -->'; 
  376.  
  377. // Do not make this translatable, as this is the product name. 
  378. echo '<!-- / Google Analytics by MonsterInsights -->'; 
  379.  
  380. return true; 
  381. return false; 
  382.