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. global $current_user; 
  233.  
  234. get_currentuserinfo(); 
  235.  
  236. $this->do_tracking = true; 
  237.  
  238. if ( 0 != $current_user->ID && isset( $this->options['ignore_users'] ) ) { 
  239. if ( ! empty( $current_user->roles ) && in_array( $current_user->roles[0], $this->options['ignore_users'] ) ) { 
  240. $this->do_tracking = false; 
  241.  
  242. /** 
  243. * Filter: 'yst_ga_track_super_admin' - Allows filtering if the Super admin should be tracked in a multi-site setup 
  244. * @api array $all_roles 
  245. */ 
  246. $track_super_admin = apply_filters( 'yst_ga_track_super_admin', true ); 
  247. if ( $track_super_admin === false && is_super_admin() ) { 
  248. $this->do_tracking = false; 
  249.  
  250. return $this->do_tracking; 
  251.  
  252. /** 
  253. * Return the target with a lot of parameters 
  254. * @param string $category 
  255. * @param array $matches 
  256. * @return array 
  257. */ 
  258. protected function get_target( $category, $matches ) { 
  259. $protocol = $matches[3]; 
  260. $original_url = $matches[4]; 
  261. $domain = $this->yoast_ga_get_domain( $matches[4] ); 
  262. $http_host = empty( $_SERVER['HTTP_HOST'] ) ? '' : $_SERVER['HTTP_HOST']; 
  263. $origin = $this->yoast_ga_get_domain( $http_host ); 
  264. $extension = substr( strrchr( $original_url, '.' ), 1 ); 
  265. $type = $this->get_target_type( $extension, $domain, $origin, $matches ); 
  266.  
  267. return array( 
  268. 'category' => $category,  
  269. 'type' => $type,  
  270. 'protocol' => $protocol,  
  271. 'domain' => $domain['domain'],  
  272. 'host' => $domain['host'],  
  273. 'origin_domain' => $origin['domain'],  
  274. 'origin_host' => $origin['host'],  
  275. 'extension' => $extension,  
  276. 'link_attributes' => trim( $matches[1] . ' ' . $matches[5] ),  
  277. 'link_text' => $matches[6],  
  278. 'original_url' => $original_url,  
  279. ); 
  280.  
  281. /** 
  282. * Getting the type for current target 
  283. * @param string $extension 
  284. * @param array $domain 
  285. * @param array $origin 
  286. * @param array $matches 
  287. * @return null|string 
  288. */ 
  289. protected function get_target_type( $extension, $domain, $origin, $matches ) { 
  290. $download_extensions = explode( ', ', str_replace( '.', '', $this->options['extensions_of_files'] ) ); 
  291. $download_extensions = array_map( 'trim', $download_extensions ); 
  292. $protocol = $matches[3]; 
  293. $original_url = $matches[4]; 
  294.  
  295. // Break out immediately if the link is not an http or https link. 
  296. $type = null; 
  297. if ( $protocol !== 'http' && $protocol !== 'https' && $protocol !== 'mailto' ) { 
  298. $type = null; 
  299. else { 
  300. if ( ( $protocol == 'mailto' ) ) { 
  301. $type = 'email'; 
  302. elseif ( in_array( $extension, $download_extensions ) ) { 
  303. $type = 'download'; 
  304. else { 
  305. $type = $this->parse_outbound_type( $domain, $origin, $original_url ); 
  306.  
  307. return $type; 
  308.  
  309. /** 
  310. * Parse the type for outbound links 
  311. * @param array $domain 
  312. * @param array $origin 
  313. * @param string $original_url 
  314. * @return string 
  315. */ 
  316. protected function parse_outbound_type( $domain, $origin, $original_url ) { 
  317. $type = null; 
  318.  
  319. if ( $domain['domain'] == $origin['domain'] ) { 
  320. $out_links = explode( ', ', $this->options['track_internal_as_outbound'] ); 
  321. $out_links = array_unique( array_map( 'trim', $out_links ) ); 
  322.  
  323. if ( ! empty( $original_url ) && ! empty( $domain['domain'] ) && count( $out_links ) >= 1 ) { 
  324. foreach ( $out_links as $out ) { 
  325. if ( ! empty( $out ) && strpos( $original_url, $domain['domain'] . $out ) !== false ) { 
  326. $type = 'internal-as-outbound'; 
  327.  
  328. if ( ! isset( $type ) ) { 
  329. $type = 'internal'; 
  330. elseif ( $domain['domain'] != $origin['domain'] ) { 
  331. $type = 'outbound'; 
  332.  
  333. return $type; 
  334.  
  335. /** 
  336. * Trims the track_internal_as_label option to prevent commas and whitespaces 
  337. * @return string 
  338. */ 
  339. protected function sanitize_internal_label() { 
  340. if ( ! is_null( $this->options['track_internal_as_label'] ) && ! empty( $this->options['track_internal_as_label'] ) ) { 
  341. $label = $this->options['track_internal_as_label']; 
  342. $label = trim( $label, ', ' ); 
  343. $label = trim( $label ); 
  344.  
  345. // Be sure label isn't empty, if so, set value with in 
  346. if ( empty( $label ) ) { 
  347. $label = 'int'; 
  348.  
  349. return $label; 
  350.  
  351. /** 
  352. * When a usergroup is disabled, show a message in the source to notify the user they are in a disabled user group. 
  353. */ 
  354. protected function disabled_usergroup() { 
  355. /** translators %1$s is the product name 'Google Analytics by Yoast'. %2$s displays the plugin version the website uses and a link to the plugin on Yoast.com */ 
  356. echo '<!-- ' . sprintf( __( 'This site uses the %1$s plugin version %2$s', 'google-analytics-for-wordpress' ), 'Google Analytics by Yoast', GAWP_VERSION . ' - https://yoast.com/wordpress/plugins/google-analytics/' ) . ' -->'; 
  357.  
  358. if ( current_user_can( 'manage_options' ) ) { 
  359. 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' ) . ' -->'; 
  360. else { 
  361. echo '<!-- ' . __( 'Normally you will find the Google Analytics tracking code here, but the webmaster disabled your user group.', 'google-analytics-for-wordpress' ) . ' -->'; 
  362.  
  363. // Do not make this translatable, as this is the product name. 
  364. echo '<!-- / Google Analytics by Yoast -->'; 
  365.  
  366. /** 
  367. * When the debug mode is enabled, display a message in the source. 
  368. * @return bool 
  369. */ 
  370. protected function debug_mode() { 
  371. if ( $this->options['debug_mode'] === 1 ) { 
  372. /** translators %1$s is the product name 'Google Analytics by Yoast'. %2$s displays the plugin version the website uses and a link to the plugin on Yoast.com */ 
  373. echo '<!-- ' . sprintf( __( 'This site uses the %1$s plugin version %2$s', 'google-analytics-for-wordpress' ), 'Google Analytics by Yoast', GAWP_VERSION . ' - https://yoast.com/wordpress/plugins/google-analytics/' ) . ' -->'; 
  374.  
  375. if ( current_user_can( 'manage_options' ) ) { 
  376. 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' ) . ' -->'; 
  377. else { 
  378. echo '<!-- ' . __( 'Normally you will find the Google Analytics tracking code here, but the webmaster has enabled the Debug Mode.', 'google-analytics-for-wordpress' ) . ' -->'; 
  379.  
  380. // Do not make this translatable, as this is the product name. 
  381. echo '<!-- / Google Analytics by Yoast -->'; 
  382.  
  383. return true; 
  384. return false; 
  385.