PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.0.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.0.2
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 5 years ago
TrackingCodeGenerator.php
366 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.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 $logLevel = is_admin() ? Logger::LEVEL_DEBUG : Logger::LEVEL_INFO;
215
216 $this->logger->log( 'Apply tracking code changes:', $logLevel );
217
218 $tracker_endpoint = $this->get_tracker_endpoint();
219 $js_endpoint = $this->get_js_endpoint();
220
221 $options = array();
222
223 if ( $this->settings->get_global_option( 'set_download_extensions' ) ) {
224 $options[] = "_paq.push(['setDownloadExtensions', " . wp_json_encode( $this->settings->get_global_option( 'set_download_extensions' ) ) . ']);';
225 }
226 if ( $this->settings->get_global_option( 'add_download_extensions' ) ) {
227 $options[] = "_paq.push(['addDownloadExtensions', " . wp_json_encode( $this->settings->get_global_option( 'add_download_extensions' ) ) . ']);';
228 }
229 if ( $this->settings->get_global_option( 'set_download_classes' ) ) {
230 $options[] = "_paq.push(['setDownloadClasses', " . wp_json_encode( $this->settings->get_global_option( 'set_download_classes' ) ) . ']);';
231 }
232 if ( $this->settings->get_global_option( 'set_link_classes' ) ) {
233 $options[] = "_paq.push(['setLinkClasses', " . wp_json_encode( $this->settings->get_global_option( 'set_link_classes' ) ) . ']);';
234 }
235 if ( $this->settings->get_global_option( 'disable_cookies' ) ) {
236 $options[] = "_paq.push(['disableCookies']);";
237 }
238 if ( $this->settings->get_global_option( 'track_crossdomain_linking' ) ) {
239 $options[] = "_paq.push(['enableCrossDomainLinking']);";
240 }
241 if ( $this->settings->get_global_option( 'track_jserrors' ) ) {
242 $options[] = "_paq.push(['enableJSErrorTracking']);";
243 }
244
245 $cookie_domain = $this->settings->get_tracking_cookie_domain();
246 if ( ! empty( $cookie_domain ) ) {
247 $options[] = '_paq.push(["setCookieDomain", ' . wp_json_encode( $cookie_domain ) . ']);';
248 }
249
250 $track_across_alias = $this->settings->get_global_option( 'track_across_alias' );
251
252 if ( $track_across_alias ) {
253 // todo detect more hosts such as when using WPML etc
254 $hosts = array( @parse_url( home_url(), PHP_URL_HOST ) );
255 $hosts = array_filter( $hosts );
256 $hosts = array_map(
257 function ( $host ) {
258 return '*.' . $host;
259 },
260 $hosts
261 );
262 if ( ! empty( $hosts ) ) {
263 $options[] = '_paq.push(["setDomains", ' . wp_json_encode( $hosts ) . ']);';
264 }
265 }
266 if ( $this->settings->get_global_option( 'force_post' ) ) {
267 $options[] = "_paq.push(['setRequestMethod', 'POST']);";
268 }
269 if ( $this->settings->get_global_option( 'limit_cookies' ) ) {
270 $options[] = "_paq.push(['setVisitorCookieTimeout', " . wp_json_encode( $this->settings->get_global_option( 'limit_cookies_visitor' ) ) . ']);';
271 $options[] = "_paq.push(['setSessionCookieTimeout', " . wp_json_encode( $this->settings->get_global_option( 'limit_cookies_session' ) ) . ']);';
272 $options[] = "_paq.push(['setReferralCookieTimeout', " . wp_json_encode( $this->settings->get_global_option( 'limit_cookies_referral' ) ) . ']);';
273 }
274 if ( $this->settings->get_global_option( 'track_content' ) === 'all' ) {
275 $options[] = "_paq.push(['trackAllContentImpressions']);";
276 } elseif ( $this->settings->get_global_option( 'track_content' ) === 'visible' ) {
277 $options[] = "_paq.push(['trackVisibleContentImpressions']);";
278 }
279 if ( (int) $this->settings->get_global_option( 'track_heartbeat' ) > 0 ) {
280 $options[] = "_paq.push(['enableHeartBeatTimer', " . intval( $this->settings->get_global_option( 'track_heartbeat' ) ) . ']);';
281 }
282
283 $data_cf_async = '';
284 if ( $this->settings->get_global_option( 'track_datacfasync' ) ) {
285 $data_cf_async = 'data-cfasync="false"';
286 }
287
288 $script = '<!-- Matomo -->';
289 $script .= '<script ' . $data_cf_async . ' type="text/javascript">';
290 $script .= "var _paq = window._paq = window._paq || [];\n";
291 $script .= implode( "\n", $options );
292 $script .= self::TRACKPAGEVIEW;
293 $script .= "_paq.push(['enableLinkTracking']);_paq.push(['alwaysUseSendBeacon']);";
294 $script .= "_paq.push(['setTrackerUrl', " . wp_json_encode( $tracker_endpoint ) . ']);';
295 $script .= "_paq.push(['setSiteId', '" . intval( $idsite ) . "']);";
296 $script .= "var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
297 g.type='text/javascript'; g.async=true; g.src=" . wp_json_encode( $js_endpoint ) . '; s.parentNode.insertBefore(g,s);';
298 $script .= '</script>';
299 $script .= '<!-- End Matomo Code -->';
300
301 $no_script = '<noscript><p><img referrerpolicy="no-referrer-when-downgrade" src="' . esc_url( $tracker_endpoint ) . '?idsite=' . intval( $idsite ) . '&amp;rec=1" style="border:0;" alt="" /></p></noscript>';
302
303 $script = apply_filters( 'matomo_tracking_code_script', $script, $idsite );
304 $script = apply_filters( 'matomo_tracking_code_noscript', $script, $idsite );
305
306 $this->logger->log( 'Finished tracking code: ' . $script, $logLevel );
307 $this->logger->log( 'Finished noscript code: ' . $no_script, $logLevel);
308
309 return array(
310 'script' => $script,
311 'noscript' => $no_script,
312 );
313 }
314
315 private function apply_404_changes( $tracking_code ) {
316 $this->logger->log( 'Apply 404 tracking changes. Blog ID: ' . get_current_blog_id() );
317
318 $code = "_paq.push(['setDocumentTitle', '404/URL = '+String(document.location.pathname+document.location.search).replace(/\//g,'%2f') + '/From = ' + String(document.referrer).replace(/\//g,'%2f')]);";
319 $tracking_code = str_replace( self::TRACKPAGEVIEW, $code . self::TRACKPAGEVIEW, $tracking_code );
320 $tracking_code = str_replace( self::MTM_INIT, $code . self::MTM_INIT, $tracking_code );
321
322 return $tracking_code;
323 }
324
325 private function apply_search_changes( $tracking_code ) {
326 $this->logger->log( 'Apply search tracking changes. Blog ID: ' . get_current_blog_id() );
327 $obj_search = new \WP_Query( 's=' . get_search_query() . '&showposts=-1' );
328 $int_result_count = $obj_search->post_count;
329
330 $code = "window._paq = window._paq || []; window._paq.push(['trackSiteSearch','" . get_search_query() . "', false, " . $int_result_count . "]);\n";
331 $tracking_code = str_replace( self::TRACKPAGEVIEW, $code . self::TRACKPAGEVIEW, $tracking_code );
332 $tracking_code = str_replace( self::MTM_INIT, $code . self::MTM_INIT, $tracking_code );
333
334 return $tracking_code;
335 }
336
337 private function apply_user_tracking( $tracking_code ) {
338 $user_id_to_track = null;
339 if ( \is_user_logged_in() ) {
340 // Get the User ID Admin option, and the current user's data
341 $uid_from = $this->settings->get_global_option( 'track_user_id' );
342 $current_user = wp_get_current_user(); // current user
343 // Get the user ID based on the admin setting
344 if ( 'uid' === $uid_from ) {
345 $user_id_to_track = $current_user->ID;
346 } elseif ( 'email' === $uid_from ) {
347 $user_id_to_track = $current_user->user_email;
348 } elseif ( 'username' === $uid_from ) {
349 $user_id_to_track = $current_user->user_login;
350 } elseif ( 'displayname' === $uid_from ) {
351 $user_id_to_track = $current_user->display_name;
352 }
353 }
354 $user_id_to_track = apply_filters( 'matomo_tracking_user_id', $user_id_to_track );
355 // Check we got a User ID to track, and track it
356 if ( isset( $user_id_to_track ) && ! empty( $user_id_to_track ) ) {
357 $code = "window._paq = window._paq || []; window._paq.push(['setUserId', '" . esc_js( $user_id_to_track ) . "']);\n";
358 $tracking_code = str_replace( self::TRACKPAGEVIEW, $code . self::TRACKPAGEVIEW, $tracking_code );
359 $tracking_code = str_replace( self::MTM_INIT, $code . self::MTM_INIT, $tracking_code );
360 }
361
362 return $tracking_code;
363 }
364
365 }
366