PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.0.5
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.0.5
5.13.0 5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / classes / WpMatomo / TrackingCode / TrackingCodeGenerator.php
matomo / classes / WpMatomo / TrackingCode Last commit date
TrackingCodeGenerator.php 6 years ago
TrackingCodeGenerator.php
361 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 * @package matomo
8 */
9
10 namespace WpMatomo\TrackingCode;
11
12 use WpMatomo\Admin\TrackingSettings;
13 use WpMatomo\Logger;
14 use WpMatomo\Paths;
15 use WpMatomo\Settings;
16 use WpMatomo\Site;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit; // if accessed directly
20 }
21
22 class TrackingCodeGenerator {
23
24 const TRACKPAGEVIEW = "_paq.push(['trackPageView']);";
25 const MTM_INIT = 'var _mtm = _mtm || [];';
26
27 /**
28 * @var Settings
29 */
30 private $settings;
31
32 /**
33 * @var Logger
34 */
35 private $logger;
36
37 /**
38 * @param Settings $settings
39 */
40 public function __construct( $settings ) {
41 $this->settings = $settings;
42 $this->logger = new Logger();
43 }
44
45 public function register_hooks() {
46 add_action( 'matomo_site_synced', array( $this, 'update_tracking_code' ), $prio = 10, $args = 0 );
47 add_action( 'matomo_tracking_settings_changed', array( $this, 'update_tracking_code' ), $prio = 10, $args = 0 );
48 }
49
50 public function update_tracking_code() {
51 if ( $this->settings->is_current_tracking_code()
52 && $this->settings->get_option( 'tracking_code' ) ) {
53 return false;
54 }
55
56 $track_mode = $this->settings->get_global_option( 'track_mode' );
57
58 if ( ! $this->settings->is_tracking_enabled()
59 || $track_mode == TrackingSettings::TRACK_MODE_MANUALLY ) {
60 return false;
61 }
62
63 $blod_id = get_current_blog_id();
64 $idsite = Site::get_matomo_site_id( $blod_id );
65
66 if ( ! $idsite ) {
67 $this->logger->log( 'Not found related idSite for blog ' . get_current_blog_id() );
68
69 return false;
70 }
71
72 if ( TrackingSettings::TRACK_MODE_DEFAULT === $track_mode ) {
73 $result = $this->prepare_tracking_code( $idsite );
74
75 if ( ! $this->settings->get_global_option( 'track_noscript' ) ) {
76 $result['noscript'] = '';
77 }
78 } elseif ( TrackingSettings::TRACK_MODE_TAGMANAGER === $track_mode && matomo_has_tag_manager() ) {
79 $result = $this->prepare_tagmanger_code( $this->settings, $this->logger );
80 } else {
81 $result = array(
82 'script' => '<!-- Matomo: no supported track_mode selected -->',
83 'noscript' => '',
84 );
85 }
86
87 if ( ! empty( $result['script'] ) ) {
88 $this->settings->set_option( 'tracking_code', $result['script'] );
89 $this->settings->set_option( 'noscript_code', $result['noscript'] );
90 }
91
92 $this->settings->set_option( Settings::OPTION_LAST_TRACKING_CODE_UPDATE, time() );
93 $this->settings->save();
94
95 return $result;
96 }
97
98 public function get_noscript_code() {
99 $this->update_tracking_code();
100
101 return $this->settings->get_noscript_tracking_code();
102 }
103
104 public function get_tracking_code() {
105 $this->update_tracking_code();
106
107 $tracking_code = $this->settings->get_js_tracking_code();
108
109 if ( $this->settings->track_user_id_enabled() ) {
110 $tracking_code = $this->apply_user_tracking( $tracking_code );
111 }
112 if ( $this->settings->track_404_enabled() && is_404() ) {
113 $tracking_code = $this->apply_404_changes( $tracking_code );
114 }
115 if ( $this->settings->track_search_enabled() ) {
116 $tracking_code = $this->apply_search_changes( $tracking_code );
117 }
118
119 return $tracking_code;
120 }
121
122 /**
123 * @param Settings $settings
124 * @param Logger $logger
125 *
126 * @return array
127 */
128 private function prepare_tagmanger_code( $settings, $logger ) {
129 $logger->log( 'Apply tag manager code changes:' );
130
131 $container_ids = $settings->get_global_option( 'tagmanger_container_ids' );
132
133 $code = '<!-- Matomo Tag Manager -->';
134
135 if ( ! empty( $container_ids ) && is_array( $container_ids ) ) {
136 $paths = new Paths();
137 $upload_url = $paths->get_upload_base_url();
138
139 foreach ( $container_ids as $container_id => $enabled ) {
140 if ( $enabled
141 && ctype_alnum( $container_id )
142 && strlen( $container_id ) <= 16 ) {
143 $container_url = $upload_url . '/container_' . urlencode( $container_id ) . '.js';
144
145 $data_cf_async = '';
146 if ( $settings->get_global_option( 'track_datacfasync' ) ) {
147 $data_cf_async = 'data-cfasync="false"';
148 }
149
150 if ( $settings->get_global_option( 'force_protocol' ) == 'https' ) {
151 $container_url = preg_replace( '(^http://)', 'https://', $container_url );
152 }
153
154 $code .= '
155 <script type="text/javascript" ' . $data_cf_async . '>
156 ' . self::MTM_INIT . '
157 _mtm.push({\'mtm.startTime\': (new Date().getTime()), \'event\': \'mtm.Start\'});
158 var d=document, g=d.createElement(\'script\'), s=d.getElementsByTagName(\'script\')[0];
159 g.type=\'text/javascript\'; g.async=true; g.defer=true; g.src="' . $container_url . '"; s.parentNode.insertBefore(g,s);
160 </script>';
161 }
162 }
163 }
164
165 $code .= '<!-- End Matomo Tag Manager -->';
166
167 return array(
168 'script' => $code,
169 'noscript' => '',
170 );
171 }
172
173 public function get_tracker_endpoint() {
174 $paths = new Paths();
175
176 if ( $this->settings->get_global_option( 'track_api_endpoint' ) === 'restapi' ) {
177 $tracker_endpoint = $paths->get_tracker_api_rest_api_endpoint();
178 } else {
179 $tracker_endpoint = $paths->get_tracker_api_url_in_matomo_dir();
180 }
181
182 if ( $this->settings->get_global_option( 'force_protocol' ) === 'https' ) {
183 $tracker_endpoint = preg_replace( '(^http://)', 'https://', $tracker_endpoint );
184 } else {
185 $tracker_endpoint = preg_replace( '(^https?://)', '//', $tracker_endpoint );
186 }
187
188 return $tracker_endpoint;
189 }
190
191 public function get_js_endpoint() {
192 $paths = new Paths();
193 if ( $this->settings->get_global_option( 'track_js_endpoint' ) === 'restapi' ) {
194 $js_endpoint = $paths->get_js_tracker_rest_api_endpoint();
195 } else {
196 $js_endpoint = $paths->get_js_tracker_url_in_matomo_dir();
197 }
198
199 if ( $this->settings->get_global_option( 'force_protocol' ) === 'https' ) {
200 $js_endpoint = preg_replace( '(^http://)', 'https://', $js_endpoint );
201 } else {
202 $js_endpoint = preg_replace( '(^https?://)', '//', $js_endpoint );
203 }
204
205 return $js_endpoint;
206 }
207
208 /**
209 * @param $idsite
210 *
211 * @return array
212 */
213 public function prepare_tracking_code( $idsite ) {
214 $this->logger->log( 'Apply tracking code changes:' );
215
216 $tracker_endpoint = $this->get_tracker_endpoint();
217 $js_endpoint = $this->get_js_endpoint();
218
219 $options = array();
220
221 if ( $this->settings->get_global_option( 'set_download_extensions' ) ) {
222 $options[] = "_paq.push(['setDownloadExtensions', " . wp_json_encode( $this->settings->get_global_option( 'set_download_extensions' ) ) . ']);';
223 }
224 if ( $this->settings->get_global_option( 'add_download_extensions' ) ) {
225 $options[] = "_paq.push(['addDownloadExtensions', " . wp_json_encode( $this->settings->get_global_option( 'add_download_extensions' ) ) . ']);';
226 }
227 if ( $this->settings->get_global_option( 'set_download_classes' ) ) {
228 $options[] = "_paq.push(['setDownloadClasses', " . wp_json_encode( $this->settings->get_global_option( 'set_download_classes' ) ) . ']);';
229 }
230 if ( $this->settings->get_global_option( 'set_link_classes' ) ) {
231 $options[] = "_paq.push(['setLinkClasses', " . wp_json_encode( $this->settings->get_global_option( 'set_link_classes' ) ) . ']);';
232 }
233 if ( $this->settings->get_global_option( 'disable_cookies' ) ) {
234 $options[] = "_paq.push(['disableCookies']);";
235 }
236 if ( $this->settings->get_global_option( 'track_crossdomain_linking' ) ) {
237 $options[] = "_paq.push(['enableCrossDomainLinking']);";
238 }
239
240 $cookie_domain = $this->settings->get_tracking_cookie_domain();
241 if ( ! empty( $cookie_domain ) ) {
242 $options[] = '_paq.push(["setCookieDomain", ' . wp_json_encode( $cookie_domain ) . ']);';
243 }
244
245 $track_across_alias = $this->settings->get_global_option( 'track_across_alias' );
246
247 if ( $track_across_alias ) {
248 // todo detect more hosts such as when using WPML etc
249 $hosts = array( @parse_url( home_url(), PHP_URL_HOST ) );
250 $hosts = array_filter( $hosts );
251 $hosts = array_map(
252 function ( $host ) {
253 return '*.' . $host;
254 },
255 $hosts
256 );
257 if ( ! empty( $hosts ) ) {
258 $options[] = '_paq.push(["setDomains", ' . wp_json_encode( $hosts ) . ']);';
259 }
260 }
261 if ( $this->settings->get_global_option( 'force_post' ) ) {
262 $options[] = "_paq.push(['setRequestMethod', 'POST']);";
263 }
264 if ( $this->settings->get_global_option( 'limit_cookies' ) ) {
265 $options[] = "_paq.push(['setVisitorCookieTimeout', " . wp_json_encode( $this->settings->get_global_option( 'limit_cookies_visitor' ) ) . ']);';
266 $options[] = "_paq.push(['setSessionCookieTimeout', " . wp_json_encode( $this->settings->get_global_option( 'limit_cookies_session' ) ) . ']);';
267 $options[] = "_paq.push(['setReferralCookieTimeout', " . wp_json_encode( $this->settings->get_global_option( 'limit_cookies_referral' ) ) . ']);';
268 }
269 if ( $this->settings->get_global_option( 'track_content' ) === 'all' ) {
270 $options[] = "_paq.push(['trackAllContentImpressions']);";
271 } elseif ( $this->settings->get_global_option( 'track_content' ) === 'visible' ) {
272 $options[] = "_paq.push(['trackVisibleContentImpressions']);";
273 }
274 if ( (int) $this->settings->get_global_option( 'track_heartbeat' ) > 0 ) {
275 $options[] = "_paq.push(['enableHeartBeatTimer', " . intval( $this->settings->get_global_option( 'track_heartbeat' ) ) . ']);';
276 }
277
278 $data_cf_async = '';
279 if ( $this->settings->get_global_option( 'track_datacfasync' ) ) {
280 $data_cf_async = 'data-cfasync="false"';
281 }
282
283 $script = '<!-- Matomo -->';
284 $script .= '<script ' . $data_cf_async . ' type="text/javascript">';
285 $script .= "var _paq = window._paq || [];\n";
286 $script .= implode( "\n", $options );
287 $script .= self::TRACKPAGEVIEW;
288 $script .= "_paq.push(['enableLinkTracking']);";
289 $script .= "_paq.push(['setTrackerUrl', " . wp_json_encode( $tracker_endpoint ) . ']);';
290 $script .= "_paq.push(['setSiteId', '" . intval( $idsite ) . "']);";
291 $script .= "var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
292 g.type='text/javascript'; g.async=true; g.defer=true; g.src=" . wp_json_encode( $js_endpoint ) . '; s.parentNode.insertBefore(g,s);';
293 $script .= '</script>';
294 $script .= '<!-- End Matomo Code -->';
295
296 $no_script = '<noscript><p><img src="' . esc_url( $tracker_endpoint ) . '?idsite=' . intval( $idsite ) . '&amp;rec=1" style="border:0;" alt="" /></p></noscript>';
297
298 $script = apply_filters( 'matomo_tracking_code_script', $script, $idsite );
299 $script = apply_filters( 'matomo_tracking_code_noscript', $script, $idsite );
300
301 $this->logger->log( 'Finished tracking code: ' . $script );
302 $this->logger->log( 'Finished noscript code: ' . $no_script );
303
304 return array(
305 'script' => $script,
306 'noscript' => $no_script,
307 );
308 }
309
310 private function apply_404_changes( $tracking_code ) {
311 $this->logger->log( 'Apply 404 tracking changes. Blog ID: ' . get_current_blog_id() );
312
313 $code = "_paq.push(['setDocumentTitle', '404/URL = '+String(document.location.pathname+document.location.search).replace(/\//g,'%2f') + '/From = ' + String(document.referrer).replace(/\//g,'%2f')]);";
314 $tracking_code = str_replace( self::TRACKPAGEVIEW, $code . self::TRACKPAGEVIEW, $tracking_code );
315 $tracking_code = str_replace( self::MTM_INIT, $code . self::MTM_INIT, $tracking_code );
316
317 return $tracking_code;
318 }
319
320 private function apply_search_changes( $tracking_code ) {
321 $this->logger->log( 'Apply search tracking changes. Blog ID: ' . get_current_blog_id() );
322 $obj_search = new \WP_Query( 's=' . get_search_query() . '&showposts=-1' );
323 $int_result_count = $obj_search->post_count;
324
325 $code = "window._paq = window._paq || []; window._paq.push(['trackSiteSearch','" . get_search_query() . "', false, " . $int_result_count . "]);\n";
326 $tracking_code = str_replace( self::TRACKPAGEVIEW, $code . self::TRACKPAGEVIEW, $tracking_code );
327 $tracking_code = str_replace( self::MTM_INIT, $code . self::MTM_INIT, $tracking_code );
328
329 return $tracking_code;
330 }
331
332 private function apply_user_tracking( $tracking_code ) {
333 $user_id_to_track = null;
334 if ( \is_user_logged_in() ) {
335 // Get the User ID Admin option, and the current user's data
336 $uid_from = $this->settings->get_global_option( 'track_user_id' );
337 $current_user = wp_get_current_user(); // current user
338 // Get the user ID based on the admin setting
339 if ( 'uid' === $uid_from ) {
340 $user_id_to_track = $current_user->ID;
341 } elseif ( 'email' === $uid_from ) {
342 $user_id_to_track = $current_user->user_email;
343 } elseif ( 'username' === $uid_from ) {
344 $user_id_to_track = $current_user->user_login;
345 } elseif ( 'displayname' === $uid_from ) {
346 $user_id_to_track = $current_user->display_name;
347 }
348 }
349 $user_id_to_track = apply_filters( 'matomo_tracking_user_id', $user_id_to_track );
350 // Check we got a User ID to track, and track it
351 if ( isset( $user_id_to_track ) && ! empty( $user_id_to_track ) ) {
352 $code = "window._paq = window._paq || []; window._paq.push(['setUserId', '" . esc_js( $user_id_to_track ) . "']);\n";
353 $tracking_code = str_replace( self::TRACKPAGEVIEW, $code . self::TRACKPAGEVIEW, $tracking_code );
354 $tracking_code = str_replace( self::MTM_INIT, $code . self::MTM_INIT, $tracking_code );
355 }
356
357 return $tracking_code;
358 }
359
360 }
361