Completed
Push — update/remove-disconnect-link ( 4b6a2c )
by
unknown
73:18 queued 63:47
created

Jetpack_Google_Analytics::_get_url()   C

Complexity

Conditions 9
Paths 36

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 14
nc 36
nop 1
dl 0
loc 22
rs 6.412
c 0
b 0
f 0
1
<?php
2
/*
3
		Copyright 2006  Aaron D. Campbell  (email : [email protected])
4
5
    This program is free software; you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by
7
    the Free Software Foundation; either version 2 of the License, or
8
    (at your option) any later version.
9
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
15
    You should have received a copy of the GNU General Public License
16
    along with this program; if not, write to the Free Software
17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
*/
19
20
/**
21
 * Jetpack_Google_Analytics is the class that handles ALL of the plugin functionality.
22
 * It helps us avoid name collisions
23
 * http://codex.wordpress.org/Writing_a_Plugin#Avoiding_Function_Name_Collisions
24
 */
25
class Jetpack_Google_Analytics {
26
27
	/**
28
	 * @var Jetpack_Google_Analytics - Static property to hold our singleton instance
29
	 */
30
	static $instance = false;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $instance.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
31
32
	/**
33
	 * This is our constructor, which is private to force the use of get_instance()
34
	 *
35
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
36
	 */
37
	private function __construct() {
38
		add_action( 'get_footer', array( $this, 'insert_code' ) );
39
	}
40
41
	/**
42
	 * Function to instantiate our class and make it a singleton
43
	 */
44
	public static function get_instance() {
45
		if ( ! self::$instance ) {
46
			self::$instance = new self;
47
		}
48
49
		return self::$instance;
50
	}
51
52
	/**
53
	 * Used to generate a tracking URL
54
	 *
55
	 * @param array $track - Must have ['data'] and ['code'].
56
	 * @return string - Tracking URL
57
	 */
58
	private function _get_url( $track ) {
59
		$site_url = ( is_ssl() ? 'https://':'http://' ) . sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ); // Input var okay.
60
		foreach ( $track as $k => $value ) {
61
			if ( strpos( strtolower( $value ), strtolower( $site_url ) ) === 0 ) {
62
				$track[ $k ] = substr( $track[ $k ], strlen( $site_url ) );
63
			}
64
			if ( 'data' === $k ) {
65
				$track[ $k ] = preg_replace( '/^https?:\/\/|^\/+/i', '', $track[ $k ] );
66
			}
67
68
			// This way we don't lose search data.
69
			if ( 'data' === $k && 'search' === $track['code'] ) {
70
				$track[ $k ] = rawurlencode( $track[ $k ] );
71
			} else {
72
				$track[ $k ] = preg_replace( '/[^a-z0-9\.\/\+\?=-]+/i', '_', $track[ $k ] );
73
			}
74
75
			$track[ $k ] = trim( $track[ $k ], '_' );
76
		}
77
		$char = ( strpos( $track['data'], '?' ) === false ) ? '?' : '&amp;';
78
		return str_replace( "'", "\'", "/{$track['code']}/{$track['data']}{$char}referer=" . rawurlencode( isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '' ) ); // Input var okay.
79
	}
80
81
	/**
82
	 * Maybe output or return, depending on the context
83
	 */
84
	private function _output_or_return( $val, $maybe ) {
85
		if ( $maybe ) {
86
			echo $val . "\r\n";
87
		} else {
88
			return $val;
89
		}
90
	}
91
92
	/**
93
	 * This injects the Google Analytics code into the footer of the page.
94
	 *
95
	 * @param bool[optional] $output - defaults to true, false returns but does NOT echo the code.
96
	 */
97
	public function insert_code( $output = true ) {
98
		// If $output is not a boolean false, set it to true (default).
99
		$output = ( false !== $output);
100
101
		$tracking_id = $this->_get_tracking_code();
102
		if ( empty( $tracking_id ) ) {
103
			return $this->_output_or_return( '<!-- Your Google Analytics Plugin is missing the tracking ID -->', $output );
104
		}
105
106
		// If we're in the admin_area, return without inserting code.
107
		if ( is_admin() ) {
108
			return $this->_output_or_return( '<!-- Your Google Analytics Plugin is set to ignore Admin area -->', $output );
109
		}
110
111
		$custom_vars = array(
112
			"_gaq.push(['_setAccount', '{$tracking_id}']);",
113
		);
114
115
		$track = array();
116
		if ( is_404() ) {
117
			// This is a 404 and we are supposed to track them.
118
			$custom_vars[] = "_gaq.push( [ '_trackEvent', '404', document.location.href, document.referrer ] );";
119
		} elseif ( is_search() ) {
120
			// Set track for searches, if it's a search, and we are supposed to.
121
			$track['data'] = sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ); // Input var okay.
122
			$track['code'] = 'search';
123
		}
124
125
		if ( ! empty( $track ) ) {
126
			$track['url'] = $this->_get_url( $track );
127
			// adjust the code that we output, account for both types of tracking.
128
			$track['url'] = esc_js( str_replace( '&', '&amp;', $track['url'] ) );
129
			$custom_vars[] = "_gaq.push(['_trackPageview','{$track['url']}']);";
130
		} else {
131
			$custom_vars[] = "_gaq.push(['_trackPageview']);";
132
		}
133
134
		$async_code = "<script type='text/javascript'>
135
							var _gaq = _gaq || [];
136
							%custom_vars%
137
138
							(function() {
139
								var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
140
								ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
141
								var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
142
							})();
143
						</script>";
144
145
		$custom_vars_string = implode( "\r\n", $custom_vars );
146
		$async_code = str_replace( '%custom_vars%', $custom_vars_string, $async_code );
147
148
		return $this->_output_or_return( $async_code, $output );
149
	}
150
151
	/**
152
	 * Used to get the tracking code option
153
	 *
154
	 * @return tracking code option value.
155
	 */
156
	private function _get_tracking_code() {
157
		$o = get_option( 'jetpack_wga' );
158
159
		if ( isset( $o['code'] ) && preg_match( '#UA-[\d-]+#', $o['code'], $matches ) ) {
160
				return $o['code'];
161
		}
162
163
		return '';
164
	}
165
}
166
167
global $jetpack_google_analytics;
168
$jetpack_google_analytics = Jetpack_Google_Analytics::get_instance();
169