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