PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.10.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.10.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.php
matomo / classes / WpMatomo Last commit date
Admin 1 month ago Commands 2 years ago Db 1 year ago Ecommerce 1 month ago Report 2 months ago Site 2 months ago TrackingCode 4 months ago Updater 4 years ago User 2 months ago Workarounds 2 years ago WpStatistics 5 months ago views 1 month ago AIBotTracking.php 4 months ago API.php 2 months ago Access.php 4 years ago AjaxTracker.php 4 months ago Annotations.php 2 months ago Bootstrap.php 10 months ago Capabilities.php 2 months ago Compatibility.php 2 months ago Email.php 2 years ago ErrorNotice.php 1 month ago Feature.php 2 months ago Installer.php 1 month ago Logger.php 1 year ago OptOut.php 1 month ago Paths.php 5 months ago PluginActionLinks.php 2 months ago PluginAdminOverrides.php 2 months ago PluginInit.php 2 months ago PrivacyBadge.php 4 years ago RedirectOnActivation.php 2 months ago Referral.php 2 months ago Roles.php 2 months ago ScheduledTasks.php 2 months ago Settings.php 4 months ago Site.php 3 years ago TrackingCode.php 2 months ago Uninstaller.php 5 months ago Updater.php 10 months ago User.php 4 years ago
TrackingCode.php
228 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;
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit; // if accessed directly
14 }
15
16 use WpMatomo\TrackingCode\GeneratorOptions;
17 use WpMatomo\TrackingCode\TrackingCodeGenerator;
18 use WpMatomo\Settings;
19
20 class TrackingCode extends Feature {
21
22 /**
23 * @var Settings
24 */
25 private $settings;
26
27 /**
28 * @var Logger
29 */
30 private $logger;
31
32 /**
33 * @var TrackingCodeGenerator
34 */
35 private $generator;
36
37 /**
38 * @param Settings $settings
39 */
40 public function __construct( $settings ) {
41 $this->settings = $settings;
42 $this->logger = new Logger();
43 $this->generator = new TrackingCodeGenerator( $this->settings, new GeneratorOptions( $this->settings ) );
44 $this->generator->register_hooks();
45 }
46
47 public function register_hooks() {
48 if ( $this->settings->is_tracking_enabled() ) {
49 if ( $this->settings->is_track_feed() ) {
50 add_filter( 'the_excerpt_rss', [ $this, 'add_feed_tracking' ] );
51 add_filter( 'the_content', [ $this, 'add_feed_tracking' ] );
52 }
53 if ( $this->settings->is_add_feed_campaign() ) {
54 add_filter( 'post_link', [ $this, 'add_feed_campaign' ] );
55 }
56 if ( $this->settings->is_cross_domain_linking_enabled() ) {
57 add_filter( 'wp_redirect', [ $this, 'forward_cross_domain_visitor_id' ] );
58 }
59
60 $is_admin = is_admin() || ! empty( $GLOBALS['MATOMO_LOADED_DIRECTLY'] );
61
62 if ( ! $is_admin || $this->settings->is_admin_tracking_enabled() ) {
63 $prefix = 'wp';
64 if ( $is_admin ) {
65 $prefix = 'admin';
66 }
67
68 $position = $prefix . '_head';
69 if ( $this->settings->get_tracking_code_position() === 'footer' ) {
70 $position = $prefix . '_footer';
71 }
72
73 add_action( $position, [ $this, 'add_javascript_code' ] );
74
75 if ( $this->settings->is_add_no_script_code() ) {
76 add_action( $prefix . '_footer', [ $this, 'add_noscript_code' ] );
77 }
78 }
79 }
80 }
81
82 /**
83 * Check if user should not be tracked
84 *
85 * @return boolean Do not track user?
86 */
87 public function is_hidden_user() {
88 if ( is_multisite() && is_super_admin() ) {
89 // by pass the hook in the WP_User::has_cap method which bypass the capabilities management
90 $stealth = $this->settings->get_global_option( Settings::OPTION_KEY_STEALTH );
91 return ( ! empty( $stealth['administrator'] ) );
92 }
93 return current_user_can( Capabilities::KEY_STEALTH );
94 }
95
96 /**
97 * Echo javascript tracking code
98 */
99 public function add_javascript_code() {
100 if ( $this->is_hidden_user() ) {
101 $this->logger->log( 'Do not add tracking code to site (user should not be tracked) Blog ID: ' . get_current_blog_id(), Logger::LEVEL_DEBUG );
102
103 return;
104 }
105
106 $tracking_code = $this->generator->get_tracking_code();
107
108 $this->logger->log( 'Add tracking code. Blog ID: ' . get_current_blog_id(), Logger::LEVEL_DEBUG );
109
110 if ( $this->settings->is_network_enabled()
111 && 'manually' === $this->settings->get_global_option( 'track_mode' ) ) {
112 $site = new Site();
113 $site_id = $site->get_current_matomo_site_id();
114 if ( $site_id ) {
115 $tracking_code = str_replace( '{MATOMO_API_ENDPOINT}', wp_json_encode( $this->generator->get_tracker_endpoint() ), $tracking_code );
116 $tracking_code = str_replace( '{MATOMO_JS_ENDPOINT}', wp_json_encode( $this->generator->get_js_endpoint() ), $tracking_code );
117 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
118 echo str_replace( '{MATOMO_IDSITE}', $site_id, $tracking_code );
119 } else {
120 echo '<!-- Site not yet synced with Matomo, tracking code will be added later -->';
121 }
122 } else {
123 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
124 echo $tracking_code;
125 }
126 }
127
128 /**
129 * Echo noscript tracking code
130 */
131 public function add_noscript_code() {
132 if ( $this->is_hidden_user() ) {
133 $this->logger->log( 'Do not add noscript code to site (user should not be tracked) Blog ID: ' . get_current_blog_id(), Logger::LEVEL_DEBUG );
134
135 return;
136 }
137
138 $code = $this->generator->get_noscript_code();
139
140 if ( ! empty( $code ) ) {
141 $this->logger->log( 'Add noscript code. Blog ID: ' . get_current_blog_id(), Logger::LEVEL_DEBUG );
142 $contains_noscript_tag = stripos( $code, '<noscript' ) !== false;
143 if ( ! $contains_noscript_tag ) {
144 echo '<noscript>';
145 }
146 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
147 echo $code;
148 if ( ! $contains_noscript_tag ) {
149 echo '</noscript>';
150 }
151 echo "\n";
152 } else {
153 $this->logger->log( 'No noscript code present. Blog ID: ' . get_current_blog_id(), Logger::LEVEL_DEBUG );
154 }
155 }
156
157 /**
158 * Add a campaign parameter to feed permalink
159 *
160 * @param string $permalink
161 * permalink
162 *
163 * @return string permalink extended by campaign parameter
164 */
165 public function add_feed_campaign( $permalink ) {
166 global $post;
167 if ( is_feed() && ! empty( $post ) ) {
168 $this->logger->log( 'Add campaign to feed permalink.' );
169 $sep = ( strpos( $permalink, '?' ) === false ? '?' : '&' );
170 $permalink .= $sep . 'pk_campaign=' . rawurlencode( $this->settings->get_global_option( 'track_feed_campaign' ) ) . '&pk_kwd=' . rawurlencode( $post->post_name );
171 }
172
173 return $permalink;
174 }
175
176 /**
177 * Add tracking pixels to feed content
178 *
179 * @param string $content
180 * post content
181 *
182 * @return string post content extended by tracking pixel
183 */
184 public function add_feed_tracking( $content ) {
185 global $post;
186 if ( is_feed() ) {
187 $this->logger->log( 'Add tracking image to feed entry.' );
188 $site = new Site();
189 $site_id = $site->get_current_matomo_site_id();
190 if ( ! $site_id ) {
191 return false;
192 }
193 $title = the_title( null, null, false );
194 $posturl = get_permalink( $post->ID );
195 $urlref = get_bloginfo( 'rss2_url' );
196
197 $tracker_endpoint = $this->generator->get_tracker_endpoint();
198
199 $tracking_image = $tracker_endpoint . '?idsite=' . $site_id . '&amp;rec=1&amp;url=' . rawurlencode( $posturl ) . '&amp;action_name=' . rawurlencode( $title ) . '&amp;urlref=' . rawurlencode( $urlref );
200 $content .= '<img src="' . $tracking_image . '" style="border:0;width:0;height:0" width="0" height="0" alt="" />';
201 }
202
203 return $content;
204 }
205
206 /**
207 * Forwards the cross domain parameter pk_vid if the URL parameter is set and a user is about to be redirected.
208 * When another website links to WooCommerce with a pk_vid parameter, and WooCommerce redirects the user to another
209 * URL, the pk_vid parameter would get lost and the visitorId would later not be applied by the tracking code
210 * due to the lost pk_vid URL parameter. If the URL parameter is set, we make sure to forward this parameter.
211 *
212 * @param string $location
213 *
214 * @return string location extended by pk_vid URL parameter if the URL parameter is set
215 */
216 public function forward_cross_domain_visitor_id( $location ) {
217 if ( ! empty( $_GET['pk_vid'] ) ) {
218 $pk_vid = sanitize_text_field( wp_unslash( $_GET['pk_vid'] ) );
219 if ( preg_match( '/^[a-zA-Z0-9]{24,60}$/', $pk_vid ) ) {
220 // currently, the pk_vid parameter is 32 characters long, but it may vary over time.
221 $location = add_query_arg( 'pk_vid', $pk_vid, $location );
222 }
223 }
224
225 return $location;
226 }
227 }
228