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 / Settings.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
Settings.php
555 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 * Code Based on
9 * @author Andr&eacute; Br&auml;kling
10 * https://github.com/braekling/matomo
11 *
12 */
13
14 namespace WpMatomo;
15
16 use Piwik\CliMulti\Process;
17 use Piwik\Tracker\Cache;
18 use WpMatomo\Admin\CookieConsent;
19 use WpMatomo\Admin\TrackingSettings;
20
21 if ( ! defined( 'ABSPATH' ) ) {
22 exit; // if accessed directly
23 }
24
25 class Settings {
26 const OPTION_PREFIX = 'matomo-';
27 const GLOBAL_OPTION_PREFIX = 'matomo_global-';
28 const OPTION = 'matomo-option';
29 const OPTION_GLOBAL = 'matomo-global-option';
30 const OPTION_KEY_CAPS_ACCESS = 'caps_access';
31 const OPTION_KEY_STEALTH = 'caps_tracking';
32 const OPTION_LAST_TRACKING_SETTINGS_CHANGE = 'last_tracking_settings_update';
33 const OPTION_LAST_TRACKING_CODE_UPDATE = 'last_tracking_code_update';
34 const SHOW_GET_STARTED_PAGE = 'show_get_started_page';
35 const DELETE_ALL_DATA_ON_UNINSTALL = 'delete_all_data_uninstall';
36 const SITE_CURRENCY = 'site_currency';
37 const NETWORK_CONFIG_OPTIONS = 'config_options';
38 const DISABLE_ASYNC_ARCHIVING_OPTION_NAME = 'matomo_disable_async_archiving';
39 const USE_SESSION_VISITOR_ID_OPTION_NAME = 'use_session_visitor_id';
40 const SERVER_SIDE_TRACKING_DELAY_SECS = 'server_side_tracking_delay_secs';
41 const GLOBAL_USER_AGENT_EXCLUSIONS = 'global_user_agent_exclusions';
42 const TRACK_AI_BOTS = 'track_ai_bots';
43 const TRACK_AI_BOTS_USING_ESI = 'track_ai_bots_using_esi';
44
45 // NOTE: this is not a setting value, but is stored with setting values to avoid
46 // adding an extra get_option call to every WordPress backoffice request.
47 const INSTANCE_COMPONENTS_INSTALLED = 'instance-components-installed';
48
49 public static $is_doing_action_tracking_related = false;
50 /**
51 * @internal tests only
52 * @var bool
53 */
54 public $force_disable_addhandler = false;
55
56 /**
57 * Tests only
58 *
59 * @ignore
60 * @var bool
61 */
62 private $assume_is_network_enabled_in_tests = false;
63
64 /**
65 * Register default configuration set
66 *
67 * (public for tests)
68 *
69 * @var array
70 */
71 public $default_global_settings = [
72 // Plugin settings
73 'last_settings_update' => 0,
74 self::OPTION_LAST_TRACKING_SETTINGS_CHANGE => 0,
75 self::OPTION_KEY_STEALTH => [],
76 self::OPTION_KEY_CAPS_ACCESS => [],
77 self::NETWORK_CONFIG_OPTIONS => [],
78 self::DELETE_ALL_DATA_ON_UNINSTALL => true,
79 self::SITE_CURRENCY => 'USD',
80 // User settings: Stats configuration
81 // User settings: Tracking configuration
82 'track_mode' => 'disabled',
83 'track_js_endpoint' => 'default',
84 'track_api_endpoint' => 'default',
85 'track_codeposition' => 'footer',
86 'track_noscript' => false,
87 'track_content' => 'disabled',
88 'track_ecommerce' => true,
89 'track_search' => false,
90 'track_404' => false,
91 self::TRACK_AI_BOTS => false,
92 self::TRACK_AI_BOTS_USING_ESI => false,
93 'tagmanger_container_ids' => [],
94 'add_post_annotations' => [],
95 'add_customvars_box' => false,
96 'js_manually' => '',
97 'noscript_manually' => '',
98 'add_download_extensions' => '',
99 'set_download_extensions' => '',
100 'set_link_classes' => '',
101 'set_download_classes' => '',
102 'core_version' => '',
103 'version_history' => [],
104 'mail_history' => [],
105 'disable_cookies' => false,
106 'cookie_consent' => CookieConsent::REQUIRE_NONE,
107 'force_post' => false,
108 'limit_cookies' => false,
109 'limit_cookies_visitor' => 34186669, // Matomo default 13 months
110 'limit_cookies_session' => 1800, // Matomo default 30 minutes
111 'limit_cookies_referral' => 15778463, // Matomo default 6 months
112 'track_admin' => false,
113 'track_across' => false,
114 'track_across_alias' => false,
115 'track_crossdomain_linking' => false,
116 'track_feed' => false,
117 'track_feed_addcampaign' => false,
118 'track_feed_campaign' => 'feed',
119 'track_heartbeat' => 0,
120 'track_user_id' => 'disabled',
121 'track_datacfasync' => false,
122 'track_jserrors' => false,
123 'force_protocol' => 'disabled',
124 'maxmind_license_key' => '',
125 self::SHOW_GET_STARTED_PAGE => 1,
126 self::DISABLE_ASYNC_ARCHIVING_OPTION_NAME => false,
127 self::GLOBAL_USER_AGENT_EXCLUSIONS => null,
128 ];
129
130 /**
131 * Settings stored per blog
132 *
133 * @var array
134 */
135 private $default_blog_settings = [
136 'noscript_code' => '',
137 'tracking_code' => '',
138 self::OPTION_LAST_TRACKING_CODE_UPDATE => 0,
139 self::USE_SESSION_VISITOR_ID_OPTION_NAME => false,
140 self::SERVER_SIDE_TRACKING_DELAY_SECS => 180,
141 ];
142
143 private $global_settings = [];
144 private $blog_settings = [];
145
146 private $settings_changed = [];
147
148 /**
149 * @var Logger
150 */
151 private $logger;
152
153 /**
154 * Constructor class to prepare settings manager
155 *
156 */
157 public function __construct() {
158 $this->logger = new Logger();
159
160 $this->init_settings();
161 }
162
163 public function init_settings() {
164 $this->settings_changed = [];
165 $this->global_settings = [];
166 $this->blog_settings = [];
167
168 if ( $this->is_network_enabled() ) {
169 $global_settings = get_site_option( self::OPTION_GLOBAL, [] );
170 } else {
171 $global_settings = get_option( self::OPTION_GLOBAL, [] );
172 }
173
174 if ( ! empty( $global_settings ) && is_array( $global_settings ) ) {
175 $this->global_settings = $global_settings;
176 }
177
178 $settings = get_option( self::OPTION, [] );
179
180 if ( ! empty( $settings ) && is_array( $settings ) ) {
181 $this->blog_settings = $settings;
182 }
183 }
184
185 public function get_customised_global_settings() {
186 $custom_settings = [];
187
188 foreach ( $this->global_settings as $key => $val ) {
189 if ( isset( $this->default_global_settings[ $key ] )
190 // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
191 && $this->default_global_settings[ $key ] != $val ) {
192 $custom_settings[ $key ] = $val;
193 }
194 }
195
196 return $custom_settings;
197 }
198
199 public function uninstall() {
200 Uninstaller::uninstall_options( self::OPTION_PREFIX );
201 Uninstaller::uninstall_options( self::GLOBAL_OPTION_PREFIX );
202 Uninstaller::uninstall_site_meta( self::GLOBAL_OPTION_PREFIX );
203 $this->init_settings();
204 }
205
206 public function is_multisite() {
207 return function_exists( 'is_multisite' ) && is_multisite();
208 }
209
210 /**
211 * @api
212 */
213 public function is_network_enabled() {
214 if ( $this->assume_is_network_enabled_in_tests ) {
215 return true;
216 }
217
218 if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
219 require_once ABSPATH . 'wp-admin/includes/plugin.php';
220 }
221
222 return is_plugin_active_for_network( 'matomo/matomo.php' );
223 }
224
225 /**
226 * Save all settings as WordPress options
227 */
228 public function save() {
229 if ( empty( $this->settings_changed ) ) {
230 $this->logger->log( 'No settings changed yet' );
231
232 return;
233 }
234
235 $this->logger->log( 'Save settings' );
236
237 if ( $this->is_network_enabled() ) {
238 update_site_option( self::OPTION_GLOBAL, $this->global_settings );
239 } else {
240 update_option( self::OPTION_GLOBAL, $this->global_settings );
241 }
242
243 update_option( self::OPTION, $this->blog_settings );
244
245 $keys_changed = array_values( array_unique( $this->settings_changed ) );
246 $this->settings_changed = [];
247
248 foreach ( $keys_changed as $key_changed ) {
249 if ( self::GLOBAL_USER_AGENT_EXCLUSIONS === $key_changed ) {
250 Bootstrap::do_bootstrap();
251 Cache::clearCacheGeneral();
252 }
253
254 do_action( 'matomo_setting_change_' . $key_changed );
255 }
256 }
257
258 /**
259 * Get a global option's value
260 *
261 * @param string $key
262 * option key
263 *
264 * @return string|array option value
265 * @api
266 */
267 public function get_global_option( $key ) {
268 if ( isset( $this->global_settings[ $key ] ) ) {
269 return $this->global_settings[ $key ];
270 }
271
272 if ( isset( $this->default_global_settings[ $key ] ) ) {
273 return $this->default_global_settings[ $key ];
274 }
275 }
276
277 /**
278 * Get an option's value related to a specific blog
279 *
280 * @param string $key option key
281 *
282 * @return string|array
283 * @api
284 */
285 public function get_option( $key ) {
286 if ( isset( $this->blog_settings[ $key ] ) ) {
287 return $this->blog_settings[ $key ];
288 }
289
290 if ( isset( $this->default_blog_settings[ $key ] ) ) {
291 return $this->default_blog_settings[ $key ];
292 }
293 }
294
295 private function convert_type( $value, $type ) {
296 if ( 'array' === $type && empty( $value ) ) {
297 $value = []; // prevent eg converting '' to array('')
298 } else {
299 settype( $value, $type );
300 }
301
302 return $value;
303 }
304
305 /**
306 * Set a global option's value
307 *
308 * @param string $key option key
309 * @param string|array $value new option value
310 */
311 public function set_global_option( $key, $value ) {
312 if ( isset( $this->default_global_settings[ $key ] ) ) {
313 $type = gettype( $this->default_global_settings[ $key ] );
314 $value = $this->convert_type( $value, $type );
315 }
316
317 if ( ! isset( $this->global_settings[ $key ] )
318 || $this->global_settings[ $key ] !== $value ) {
319 $this->settings_changed[] = $key;
320 $this->logger->log( 'Changed global option ' . $key . ': ' . ( is_array( $value ) ? wp_json_encode( $value ) : $value ) );
321
322 $this->global_settings[ $key ] = $value;
323 }
324 }
325
326 /**
327 * Set an option's value related to a specific blog
328 *
329 * @param string $key option key
330 * @param string $value new option value
331 */
332 public function set_option( $key, $value ) {
333 if ( isset( $this->default_blog_settings[ $key ] ) ) {
334 $type = gettype( $this->default_blog_settings[ $key ] );
335 $value = $this->convert_type( $value, $type );
336 }
337
338 if ( ! isset( $this->blog_settings[ $key ] )
339 || $this->blog_settings[ $key ] !== $value ) {
340 $this->settings_changed[] = $key;
341 $this->logger->log( 'Changed option ' . $key . ': ' . $value );
342 $this->blog_settings[ $key ] = $value;
343 }
344 }
345
346 /**
347 * @param array $values
348 *
349 * @api
350 */
351 public function apply_tracking_related_changes( $values ) {
352 $this->set_global_option( self::OPTION_LAST_TRACKING_SETTINGS_CHANGE, time() );
353
354 $this->apply_changes( $values );
355
356 if ( ! self::$is_doing_action_tracking_related ) {
357 // prevent recurison if any plugin was listening to this event and calling this method again
358 self::$is_doing_action_tracking_related = true;
359 do_action( 'matomo_tracking_settings_changed', $this, $values );
360 self::$is_doing_action_tracking_related = false;
361 }
362 }
363
364 public function should_disable_addhandler() {
365 if ( $this->force_disable_addhandler ) {
366 return true;
367 }
368
369 return defined( 'MATOMO_DISABLE_ADDHANDLER' ) && MATOMO_DISABLE_ADDHANDLER;
370 }
371
372 /**
373 * Apply new configuration
374 *
375 * @param array $settings
376 * new configuration set
377 *
378 * @api
379 */
380 public function apply_changes( $settings ) {
381 $this->logger->log( 'Apply changed settings:' );
382 foreach ( $this->default_global_settings as $key => $val ) {
383 if ( isset( $settings[ $key ] ) ) {
384 $this->set_global_option( $key, $settings[ $key ] );
385 }
386 }
387 foreach ( $this->default_blog_settings as $key => $val ) {
388 if ( isset( $settings[ $key ] ) ) {
389 $this->set_option( $key, $settings[ $key ] );
390 }
391 }
392 $this->set_global_option( 'last_settings_update', time() );
393
394 if ( $this->should_save_tracking_code_across_sites() ) {
395 // special case for when the same tracking code needs to be used across all instances
396 $this->set_global_option( 'js_manually', $this->get_option( 'tracking_code' ) );
397 $this->set_global_option( 'noscript_manually', $this->get_option( 'noscript_code' ) );
398 }
399
400 $this->save();
401 }
402
403 private function should_save_tracking_code_across_sites() {
404 return $this->is_network_enabled()
405 && $this->get_global_option( 'track_mode' ) === TrackingSettings::TRACK_MODE_MANUALLY;
406 }
407
408 public function get_js_tracking_code() {
409 if ( $this->should_save_tracking_code_across_sites() ) {
410 return $this->get_global_option( 'js_manually' );
411 }
412
413 return $this->get_option( 'tracking_code' );
414 }
415
416 public function get_noscript_tracking_code() {
417 if ( $this->should_save_tracking_code_across_sites() ) {
418 return $this->get_global_option( 'noscript_manually' );
419 }
420
421 return $this->get_option( 'noscript_code' );
422 }
423
424 public function is_cross_domain_linking_enabled() {
425 return $this->get_global_option( 'track_crossdomain_linking' );
426 }
427
428 public function should_delete_all_data_on_uninstall() {
429 if ( defined( 'MATOMO_REMOVE_ALL_DATA' ) ) {
430 return (bool) MATOMO_REMOVE_ALL_DATA;
431 }
432
433 return (bool) $this->get_global_option( self::DELETE_ALL_DATA_ON_UNINSTALL );
434 }
435
436 /**
437 * Check if feed tracking is enabled
438 *
439 * @return boolean Is feed tracking enabled?
440 */
441 public function is_track_feed() {
442 return $this->get_global_option( 'track_feed' );
443 }
444
445 /**
446 * Check if admin tracking is enabled
447 *
448 * @return boolean Is admin tracking enabled?
449 */
450 public function is_admin_tracking_enabled() {
451 return $this->get_global_option( 'track_admin' ) && is_admin();
452 }
453
454 public function is_current_tracking_code() {
455 $last_tracking_code_update = $this->get_option( self::OPTION_LAST_TRACKING_CODE_UPDATE );
456 $last_tracking_settings_update = $this->get_global_option( self::OPTION_LAST_TRACKING_SETTINGS_CHANGE );
457
458 return $last_tracking_code_update && $last_tracking_code_update > $last_tracking_settings_update;
459 }
460
461 /**
462 * Check if feed permalinks get a campaign parameter
463 *
464 * @return boolean Add campaign parameter to feed permalinks?
465 */
466 public function is_add_feed_campaign() {
467 return $this->get_global_option( 'track_feed_addcampaign' );
468 }
469
470 public function is_tracking_enabled() {
471 return $this->get_global_option( 'track_mode' ) !== 'disabled';
472 }
473
474 /**
475 * Check if noscript code insertion is enabled
476 *
477 * @return boolean Insert noscript code?
478 */
479 public function is_add_no_script_code() {
480 return $this->get_global_option( 'track_noscript' );
481 }
482
483 public function get_tracking_code_position() {
484 return $this->get_global_option( 'track_codeposition' );
485 }
486
487 public function track_404_enabled() {
488 return $this->get_global_option( 'track_404' );
489 }
490
491 public function track_user_id_enabled() {
492 return $this->get_global_option( 'track_user_id' ) !== 'disabled';
493 }
494
495 public function track_search_enabled() {
496 return ( is_search() && $this->get_global_option( 'track_search' ) );
497 }
498
499 public function set_assume_is_network_enabled_in_tests( $network_enabled = true ) {
500 $this->assume_is_network_enabled_in_tests = $network_enabled;
501 }
502
503 public function is_async_archiving_supported() {
504 return Process::isSupported() && ( ! defined( 'MATOMO_SUPPORT_ASYNC_ARCHIVING' ) || MATOMO_SUPPORT_ASYNC_ARCHIVING );
505 }
506
507 public function is_async_archiving_disabled_by_option() {
508 return (bool) $this->get_global_option( self::DISABLE_ASYNC_ARCHIVING_OPTION_NAME );
509 }
510
511 public function is_ai_bot_tracking_enabled() {
512 return (bool) $this->get_global_option( self::TRACK_AI_BOTS );
513 }
514
515 public function is_tracking_ai_bots_via_esi_includes() {
516 return (bool) $this->get_global_option( self::TRACK_AI_BOTS_USING_ESI );
517 }
518
519 public function get_matomo_major_version() {
520 $core_version = $this->get_global_option( 'core_version' );
521 $core_version = isset( $core_version ) ? $core_version : '';
522
523 $parts = explode( '.', $core_version );
524 if ( empty( $parts ) ) {
525 return 0;
526 }
527
528 return (int) $parts[0];
529 }
530
531 public function set_global_user_agent_exclusions( $user_agents ) {
532 $this->set_global_option( self::GLOBAL_USER_AGENT_EXCLUSIONS, $user_agents );
533 }
534
535 public function get_global_user_agent_exclusions() {
536 $user_agents = $this->get_global_option( self::GLOBAL_USER_AGENT_EXCLUSIONS );
537 if ( ! is_array( $user_agents ) ) {
538 // only bootstrap if we can't access the SitesManager API.
539 // if we always bootstrap, it is possible to try initializing the FrontController before Matomo
540 // installation completes, which will fail.
541 if ( ! class_exists( \Piwik\Plugins\SitesManager\API::class ) ) {
542 Bootstrap::do_bootstrap();
543 }
544
545 $user_agents = \Piwik\Plugins\SitesManager\API::getInstance()->getExcludedUserAgentsGlobal();
546 $user_agents = explode( ',', $user_agents );
547 }
548 return $user_agents;
549 }
550
551 public function is_track_via_esi_enabled() {
552 return ( (bool) $this->get_global_option( 'track_ai_bots_using_esi' ) ) === true;
553 }
554 }
555