PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.14.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.14.2
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 / Admin / TrackingSettings.php
matomo / classes / WpMatomo / Admin Last commit date
TrackingSettings 4 years ago views 3 years ago AccessSettings.php 4 years ago Admin.php 4 years ago AdminSettings.php 4 years ago AdminSettingsInterface.php 6 years ago AdvancedSettings.php 4 years ago Chart.php 4 years ago CookieConsent.php 4 years ago Dashboard.php 4 years ago ExclusionSettings.php 4 years ago GeolocationSettings.php 4 years ago GetStarted.php 4 years ago ImportWpStatistics.php 4 years ago Info.php 4 years ago InvalidIpException.php 4 years ago Marketplace.php 4 years ago Menu.php 3 years ago PrivacySettings.php 4 years ago SafeModeMenu.php 4 years ago Summary.php 4 years ago SystemReport.php 3 years ago TrackingSettings.php 4 years ago
TrackingSettings.php
336 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\Admin;
11
12 use Exception;
13 use WpMatomo\Capabilities;
14 use WpMatomo\Settings;
15 use WpMatomo\Site;
16 use WpMatomo\Site\Sync\SyncConfig as SiteConfigSync;
17 use WpMatomo\TrackingCode\TrackingCodeGenerator;
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit; // if accessed directly
21 }
22 /**
23 * @todo set up the nonce verification
24 * phpcs:disable WordPress.Security.NonceVerification.Missing
25 */
26 class TrackingSettings implements AdminSettingsInterface {
27 const FORM_NAME = 'matomo';
28 const NONCE_NAME = 'matomo_settings';
29 const TRACK_MODE_DEFAULT = 'default';
30 const TRACK_MODE_DISABLED = 'disabled';
31 const TRACK_MODE_MANUALLY = 'manually';
32 const TRACK_MODE_TAGMANAGER = 'tagmanager';
33
34 /**
35 * @var Settings
36 */
37 private $settings;
38
39 /**
40 * @param Settings $settings
41 */
42 public function __construct( $settings ) {
43 $this->settings = $settings;
44 }
45
46 public function get_title() {
47 return esc_html__( 'Tracking', 'matomo' );
48 }
49
50 private function update_if_submitted() {
51 if ( $this->form_submitted() === true
52 && check_admin_referer( self::NONCE_NAME ) ) {
53 $this->apply_settings();
54
55 return true;
56 }
57
58 return false;
59 }
60
61 public function can_user_manage() {
62 return current_user_can( Capabilities::KEY_SUPERUSER );
63 }
64
65 private function apply_settings() {
66 $keys_to_keep = [
67 'track_mode',
68 'track_across',
69 'track_across_alias',
70 'track_crossdomain_linking',
71 'track_feed',
72 'track_feed_addcampaign',
73 'track_feed_campaign',
74 'track_heartbeat',
75 'track_user_id',
76 'track_datacfasync',
77 'tagmanger_container_ids',
78 'set_download_extensions',
79 'set_download_classes',
80 'set_link_classes',
81 'track_admin',
82 'limit_cookies_referral',
83 'limit_cookies_session',
84 'limit_cookies_visitor',
85 'limit_cookies',
86 'force_post',
87 'disable_cookies',
88 'cookie_consent',
89 'add_download_extensions',
90 'track_404',
91 'track_search',
92 'add_post_annotations',
93 'track_content',
94 'track_ecommerce',
95 'track_noscript',
96 'noscript_code',
97 'track_codeposition',
98 'tracking_code',
99 'force_protocol',
100 'track_js_endpoint',
101 'track_jserrors',
102 'track_api_endpoint',
103 Settings::SITE_CURRENCY,
104 ];
105
106 if ( matomo_has_tag_manager() ) {
107 $keys_to_keep[] = 'tagmanger_container_ids';
108 }
109
110 $values = [];
111
112 // default value in case no role/ post type is selected to make sure we unset it if no role /post type is selected
113 $values['add_post_annotations'] = [];
114 $values['tagmanger_container_ids'] = [];
115
116 $valid_currencies = $this->get_supported_currencies();
117
118 if ( ! empty( $_POST[ self::FORM_NAME ]['tracker_debug'] ) ) {
119 $site_config_sync = new SiteConfigSync( $this->settings );
120 switch ( $_POST[ self::FORM_NAME ]['tracker_debug'] ) {
121 case 'always':
122 $site_config_sync->set_config_value( 'Tracker', 'debug', 1 );
123 $site_config_sync->set_config_value( 'Tracker', 'debug_on_demand', 0 );
124 break;
125 case 'on_demand':
126 $site_config_sync->set_config_value( 'Tracker', 'debug', 0 );
127 $site_config_sync->set_config_value( 'Tracker', 'debug_on_demand', 1 );
128 break;
129 default:
130 $site_config_sync->set_config_value( 'Tracker', 'debug', 0 );
131 $site_config_sync->set_config_value( 'Tracker', 'debug_on_demand', 0 );
132 }
133 }
134
135 if ( empty( $_POST[ self::FORM_NAME ][ Settings::SITE_CURRENCY ] )
136 || ! array_key_exists( sanitize_text_field( wp_unslash( $_POST[ self::FORM_NAME ][ Settings::SITE_CURRENCY ] ) ), $valid_currencies ) ) {
137 $_POST[ self::FORM_NAME ][ Settings::SITE_CURRENCY ] = 'USD';
138 }
139
140 if ( ! empty( $_POST[ self::FORM_NAME ]['track_mode'] ) ) {
141 $track_mode = $this->get_track_mode();
142 if ( self::TRACK_MODE_TAGMANAGER === $track_mode ) {
143 // no noscript mode in this case
144 $_POST[ self::FORM_NAME ]['track_noscript'] = '';
145 $_POST[ self::FORM_NAME ]['noscript_code'] = '';
146 } else {
147 unset( $_POST['tagmanger_container_ids'] );
148 }
149 if ( $this->must_update_tracker() === true ) {
150 // We want to keep the tracking code when user switches between disabled and manually or disabled to disabled.
151 if ( ! empty( $_POST[ self::FORM_NAME ]['tracking_code'] ) ) {
152 // don't process, this is a script
153 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
154 $_POST[ self::FORM_NAME ]['tracking_code'] = stripslashes( $_POST[ self::FORM_NAME ]['tracking_code'] );
155 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
156 } else {
157 $_POST[ self::FORM_NAME ]['tracking_code'] = '';
158 }
159 if ( ! empty( $_POST[ self::FORM_NAME ]['noscript_code'] ) ) {
160 // don't process, this is a script
161 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
162 $_POST[ self::FORM_NAME ]['noscript_code'] = stripslashes( $_POST[ self::FORM_NAME ]['noscript_code'] );
163 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
164 } else {
165 $_POST[ self::FORM_NAME ]['noscript_code'] = '';
166 }
167 } else {
168 $_POST[ self::FORM_NAME ]['noscript_code'] = '';
169 $_POST[ self::FORM_NAME ]['tracking_code'] = '';
170 }
171 }
172 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
173 foreach ( $_POST[ self::FORM_NAME ] as $name => $value ) {
174 if ( in_array( $name, $keys_to_keep, true ) ) {
175 $values[ $name ] = $value;
176 }
177 }
178 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
179 $this->settings->apply_tracking_related_changes( $values );
180
181 return true;
182 }
183
184 private function get_track_mode() {
185 if ( ! empty( $_POST[ self::FORM_NAME ]['track_mode'] ) ) {
186 return sanitize_text_field( wp_unslash( $_POST[ self::FORM_NAME ]['track_mode'] ) );
187 }
188 return '';
189 }
190 /**
191 * Reauires form to be posted
192 *
193 * @return bool
194 */
195 private function must_update_tracker() {
196 $track_mode = $this->get_track_mode();
197 $previus_track_mode = $this->settings->get_global_option( 'track_mode' );
198 $must_update = false;
199 if ( self::TRACK_MODE_MANUALLY === $track_mode
200 || ( self::TRACK_MODE_DISABLED === $track_mode &&
201 in_array( $previus_track_mode, [ self::TRACK_MODE_DISABLED, self::TRACK_MODE_MANUALLY ], true ) ) ) {
202 // We want to keep the tracking code when user switches between disabled and manually or disabled to disabled.
203 $must_update = true;
204 }
205
206 return $must_update;
207 }
208
209 /**
210 * @return bool
211 */
212 private function form_submitted() {
213 return isset( $_POST ) && ! empty( $_POST[ self::FORM_NAME ] )
214 && is_admin()
215 && $this->can_user_manage();
216 }
217
218 /**
219 * @param string $field
220 *
221 * @return bool
222 */
223 private function has_valid_html_comments( $field ) {
224 $valid = true;
225 if ( $this->form_submitted() === true ) {
226 if ( $this->must_update_tracker() === true ) {
227 if ( ! empty( $_POST[ self::FORM_NAME ][ $field ] ) ) {
228 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
229 $valid = $this->validate_html_comments( $_POST[ self::FORM_NAME ][ $field ] );
230 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
231 }
232 }
233 }
234
235 return $valid;
236 }
237
238 /**
239 * @param string $html html content to validate
240 *
241 * @returns boolean
242 */
243 public function validate_html_comments( $html ) {
244 $opening = substr_count( $html, '<!--' );
245 $closing = substr_count( $html, '-->' );
246
247 return ( $opening === $closing );
248 }
249
250 public function show_settings() {
251 $was_updated = false;
252 $settings_errors = [];
253 if ( $this->has_valid_html_comments( 'tracking_code' ) !== true ) {
254 $settings_errors[] = __( 'Settings have not been saved. There is an issue with the HTML comments in the field "Tracking code". Make sure all opened comments (<!--) are closed (-->) correctly.', 'matomo' );
255 }
256 if ( $this->has_valid_html_comments( 'noscript_code' ) !== true ) {
257 $settings_errors[] = __( 'Settings have not been saved. There is an issue with the HTML comments in the field "Noscript code". Make sure all opened comments (<!--) are closed (-->) correctly.', 'matomo' );
258 }
259 if ( count( $settings_errors ) === 0 ) {
260 $was_updated = $this->update_if_submitted();
261 }
262
263 $settings = $this->settings;
264
265 $containers = $this->get_active_containers();
266
267 $track_modes = [
268 self::TRACK_MODE_DISABLED => esc_html__( 'Disabled', 'matomo' ),
269 self::TRACK_MODE_DEFAULT => esc_html__( 'Default tracking', 'matomo' ),
270 self::TRACK_MODE_MANUALLY => esc_html__( 'Enter manually', 'matomo' ),
271 ];
272
273 if ( ! empty( $containers ) ) {
274 $track_modes[ self::TRACK_MODE_TAGMANAGER ] = esc_html__( 'Tag Manager', 'matomo' );
275 }
276
277 $site = new Site();
278 $idsite = $site->get_current_matomo_site_id();
279
280 $matomo_currencies = $this->get_supported_currencies();
281
282 $cookie_consent_modes = $this->get_cookie_consent_modes();
283
284 $tracking_code_generator = new TrackingCodeGenerator( $this->settings );
285 $matomo_default_tracking_code = $tracking_code_generator->prepare_tracking_code( $idsite );
286
287 include dirname( __FILE__ ) . '/views/tracking.php';
288 }
289
290 /**
291 * @return string[]
292 */
293 private function get_cookie_consent_modes() {
294 $modes = [];
295 foreach ( CookieConsent::get_available_options() as $option => $description ) {
296 $modes[ $option ] = $description;
297 }
298
299 return $modes;
300 }
301
302 private function get_supported_currencies() {
303 $all = include dirname( MATOMO_ANALYTICS_FILE ) . '/app/core/Intl/Data/Resources/currencies.php';
304 $currencies = [];
305 foreach ( $all as $key => $single ) {
306 $currencies[ $key ] = $single[0] . ' ' . $single[1];
307 }
308
309 return $currencies;
310 }
311
312 public function get_active_containers() {
313 // we don't use Matomo API here to avoid needing to bootstrap Matomo which is slow and could break things
314 $containers = [];
315 if ( matomo_has_tag_manager() ) {
316 global $wpdb;
317 $db_settings = new \WpMatomo\Db\Settings();
318 $container_table = $db_settings->prefix_table_name( 'tagmanager_container' );
319 try {
320 // phpcs:disable WordPress.DB
321 $containers = $wpdb->get_results( sprintf( 'SELECT `idcontainer`, `name` FROM %s where `status` = "active"', $container_table ) );
322 // phpcs:enable WordPress.DB
323 } catch ( Exception $e ) {
324 // table may not exist yet etc
325 $containers = [];
326 }
327 }
328 $by_id = [];
329 foreach ( $containers as $container ) {
330 $by_id[ $container->idcontainer ] = $container->name;
331 }
332
333 return $by_id;
334 }
335 }
336