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