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