PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.11.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.11.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 / matomo.php
matomo Last commit date
app 1 day ago assets 1 day ago classes 1 day ago config 1 month ago languages 6 years ago misc 4 months ago node_modules 4 years ago plugins 1 day ago .htaccess 4 months ago LEGALNOTICE 2 years ago LICENSE 6 years ago matomo.php 1 day ago readme.txt 1 day ago shared.php 3 years ago uninstall.php 6 years ago wdio.conf.uninstall.ts 1 year ago
matomo.php
317 lines
1 <?php
2 /**
3 * Plugin Name: Matomo Analytics - Ethical Stats. Powerful Insights.
4 * Description: Privacy friendly, GDPR compliant and self-hosted. Matomo is the #1 Google Analytics alternative that gives you control of your data. Free and secure.
5 * Author: Matomo
6 * Author URI: https://matomo.org
7 * Version: 5.11.1
8 * Domain Path: /languages
9 * WC requires at least: 2.4.0
10 * WC tested up to: 10.9.1
11 *
12 * Matomo - free/libre analytics platform
13 *
14 * @link https://matomo.org
15 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
16 * @package matomo
17 * phpcs:disable WordPress.Security.ValidatedSanitizedInput
18 * phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
19 * phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
20 */
21 if ( ! defined( 'ABSPATH' ) ) {
22 exit; // if accessed directly
23 }
24
25 if ( ! defined( 'MATOMO_ANALYTICS_FILE' ) ) {
26 define( 'MATOMO_ANALYTICS_FILE', __FILE__ );
27 }
28
29 if ( ! defined( 'MATOMO_MARKETPLACE_PLUGIN_NAME' ) ) {
30 define( 'MATOMO_MARKETPLACE_PLUGIN_NAME', 'matomo-marketplace-for-wordpress/matomo-marketplace-for-wordpress.php' );
31 }
32
33 $GLOBALS['MATOMO_PLUGINS_ENABLED'] = array();
34
35 /** MATOMO_PLUGIN_FILES => used to check for updates etc */
36 $GLOBALS['MATOMO_PLUGIN_FILES'] = array( MATOMO_ANALYTICS_FILE );
37
38 add_action(
39 'init',
40 function () {
41 load_plugin_textdomain( 'matomo', false, basename( dirname( __FILE__ ) ) . '/languages' );
42 }
43 );
44
45 function matomo_has_compatible_content_dir() {
46 if ( ! empty( $_SERVER['MATOMO_WP_ROOT_PATH'] )
47 && file_exists( rtrim( $_SERVER['MATOMO_WP_ROOT_PATH'], '/' ) . '/wp-load.php' ) ) {
48 return true;
49 }
50
51 if ( ! defined( 'WP_CONTENT_DIR' ) ) {
52 return false;
53 }
54
55 $content_dir = rtrim( rtrim( WP_CONTENT_DIR, '/' ), DIRECTORY_SEPARATOR );
56 $content_dir = wp_normalize_path( $content_dir );
57 $abs_path = wp_normalize_path( ABSPATH );
58
59 $abs_paths = array(
60 $abs_path . 'wp-content',
61 $abs_path . '/wp-content',
62 $abs_path . DIRECTORY_SEPARATOR . 'wp-content',
63 );
64
65 if ( in_array( $content_dir, $abs_paths, true ) ) {
66 return true;
67 }
68
69 $wpload_base = '../../../wp-load.php';
70 $wpload_full = dirname( __FILE__ ) . '/' . $wpload_base;
71 if ( file_exists( $wpload_full ) && is_readable( $wpload_full ) ) {
72 return true;
73 } elseif ( realpath( $wpload_full ) && file_exists( realpath( $wpload_full ) ) && is_readable( realpath( $wpload_full ) ) ) {
74 return true;
75 } elseif ( ! empty( $_SERVER['SCRIPT_FILENAME'] ) && file_exists( $_SERVER['SCRIPT_FILENAME'] ) ) {
76 // seems symlinked... eg the wp-content dir or wp-content/plugins dir is symlinked from some very much other place...
77 $wpload_full = dirname( $_SERVER['SCRIPT_FILENAME'] ) . '/' . $wpload_base;
78 if ( file_exists( $wpload_full ) ) {
79 return true;
80 } elseif ( realpath( $wpload_full ) && file_exists( realpath( $wpload_full ) ) ) {
81 return true;
82 } elseif ( file_exists( dirname( $_SERVER['SCRIPT_FILENAME'] ) ) . '/wp-load.php' ) {
83 return true;
84 }
85 }
86
87 // look in plugins directory if there is a config file for us
88 $wpload_config = dirname( __FILE__ ) . '/../matomo.wpload_dir.php';
89 if ( file_exists( $wpload_config ) && is_readable( $wpload_config ) ) {
90 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
91 $content = @file_get_contents( $wpload_config ); // we do not include that file for security reasons
92 if ( ! empty( $content ) ) {
93 $content = str_replace( array( '<?php', 'exit;' ), '', $content );
94 $content = preg_replace( '/\s/', '', $content );
95 $content = trim( ltrim( trim( $content ), '#' ) ); // the path may be commented out # /abs/path
96 if ( strpos( $content, DIRECTORY_SEPARATOR ) === 0 ) {
97 $wpload_file = rtrim( $content, DIRECTORY_SEPARATOR ) . '/wp-load.php';
98 return file_exists( $wpload_file ) && is_readable( $wpload_file );
99 }
100 }
101 }
102
103 return false;
104 }
105
106 function matomo_header_icon( $full = false ) {
107 $class = 'matomo-header-icon';
108 $file = 'logo.png';
109 if ( $full ) {
110 $file = 'logo-full.png';
111 $class .= '-full';
112 }
113 echo '<img height="32" src="' . esc_url( plugins_url( 'assets/img/' . $file, MATOMO_ANALYTICS_FILE ) . '?v=' . rawurlencode( matomo_get_asset_version() ) ) . '" class="' . esc_attr( $class ) . '">';
114 }
115
116 function matomo_is_app_request() {
117 return ! empty( $_SERVER['SCRIPT_NAME'] )
118 && ( substr( $_SERVER['SCRIPT_NAME'], - 1 * strlen( 'matomo/app/index.php' ) ) === 'matomo/app/index.php' );
119 }
120
121 function matomo_has_tag_manager() {
122 if ( defined( 'MATOMO_ENABLE_TAG_MANAGER' ) ) {
123 return ! empty( MATOMO_ENABLE_TAG_MANAGER );
124 }
125
126 $is_multisite = function_exists( 'is_multisite' ) && is_multisite();
127 if ( $is_multisite ) {
128 return false;
129 }
130
131 return true;
132 }
133
134 function matomo_anonymize_value( $value ) {
135 if ( is_string( $value ) && ! empty( $value ) ) {
136 $values_to_anonymize = array(
137 ABSPATH => '$abs_path/',
138 str_replace( '/', '\/', ABSPATH ) => '$abs_path\/',
139 str_replace( '/', '\\', ABSPATH ) => '$abs_path\/',
140 WP_CONTENT_DIR => '$WP_CONTENT_DIR/',
141 str_replace( '/', '\\', WP_CONTENT_DIR ) => '$WP_CONTENT_DIR\\',
142 home_url() => '$home_url',
143 site_url() => '$site_url',
144 DB_PASSWORD => '$DB_PASSWORD',
145 DB_USER => '$DB_USER',
146 DB_HOST => '$DB_HOST',
147 DB_NAME => '$DB_NAME',
148 );
149 $keys = array( 'AUTH_KEY', 'SECURE_AUTH_KEY', 'LOGGED_IN_KEY', 'AUTH_SALT', 'NONCE_KEY', 'SECURE_AUTH_SALT', 'LOGGED_IN_SALT', 'NONCE_SALT' );
150 foreach ( $keys as $key ) {
151 if ( defined( $key ) ) {
152 $const_value = constant( $key );
153 if ( ! empty( $const_value ) && is_string( $const_value ) && strlen( $key ) > 3 ) {
154 $values_to_anonymize[ $const_value ] = '$' . $key;
155 }
156 }
157 }
158 foreach ( $values_to_anonymize as $search => $replace ) {
159 if ( $search ) {
160 $value = str_replace( $search, $replace, $value );
161 }
162 }
163 // replace anything like token_auth etc or md5 or sha1 ...
164 $value = preg_replace( '/[[:xdigit:]]{31,80}/', 'TOKEN_REPLACED', $value );
165 }
166
167 return $value;
168 }
169
170 $GLOBALS['MATOMO_MARKETPLACE_PLUGINS'] = array();
171
172 function matomo_rel_path( $to_dir, $from_dir ) {
173 $to_dir_parts = array_values( array_filter( explode( DIRECTORY_SEPARATOR, $to_dir ) ) );
174 $from_dir_parts = array_values( array_filter( explode( DIRECTORY_SEPARATOR, $from_dir ) ) );
175
176 $to_index = 0;
177 $from_index = 0;
178
179 $to_dir_segment_count = count( $to_dir_parts );
180 $from_dir_segment_count = count( $from_dir_parts );
181
182 // skip over common parts of $to_dir and $from_dir
183 for ( ; $to_index < $to_dir_segment_count && $from_index < $from_dir_segment_count && $to_dir_parts[ $to_index ] === $from_dir_parts[ $from_index ]; ++$to_index, ++$from_index );
184
185 // ascend from $to_dir to common root it has with $from_dir
186 $relative_path = str_repeat( '..' . DIRECTORY_SEPARATOR, count( $from_dir_parts ) - $from_index );
187
188 // descend from common root to target in rest of $to_dir
189 $rest = array_slice( $to_dir_parts, $to_index );
190 if ( ! empty( $rest ) ) {
191 $relative_path = $relative_path . implode( DIRECTORY_SEPARATOR, $rest );
192 }
193
194 return $relative_path;
195 }
196
197 function matomo_is_plugin_compatible( $wp_plugin_file ) {
198 require_once __DIR__ . '/app/core/Version.php';
199
200 $plugin_manifest_path = dirname( $wp_plugin_file ) . '/plugin.json';
201 clearstatcache( false, $plugin_manifest_path );
202
203 if ( ! is_file( $plugin_manifest_path )
204 || ! is_readable( $plugin_manifest_path )
205 ) {
206 return false;
207 }
208
209 $modified_time = filemtime( $plugin_manifest_path );
210 if ( false === $modified_time ) {
211 return false;
212 }
213
214 $cache_key = 'matomo_plugin_compatible_' . basename( $wp_plugin_file ) . '_' . \Piwik\Version::VERSION . '_' . $modified_time;
215 $cache_value = get_transient( $cache_key );
216 if ( false === $cache_value ) {
217 // assume the plugin is not compatible in case the below code fails.
218 // this way, the next request will work rather than trigger the same
219 // error.
220 $one_day = 24 * 60 * 60;
221 set_transient( $cache_key, 0, $one_day );
222
223 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
224 $plugin_manifest = file_get_contents( $plugin_manifest_path );
225 $plugin_manifest = json_decode( $plugin_manifest, true );
226 if ( empty( $plugin_manifest['require']['matomo'] )
227 && empty( $plugin_manifest['require']['piwik'] )
228 ) {
229 return false;
230 }
231
232 $core_requirement = isset( $plugin_manifest['require']['matomo'] )
233 ? $plugin_manifest['require']['matomo']
234 : $plugin_manifest['require']['piwik'];
235
236 require_once __DIR__ . '/app/vendor/autoload.php';
237
238 $dependency = new \Piwik\Plugin\Dependency();
239 $missing_dependencies = $dependency->getMissingDependencies( [ 'matomo' => $core_requirement ] );
240
241 $is_compatible = empty( $missing_dependencies );
242 $cache_value = (int) $is_compatible;
243
244 $two_months = 60 * 60 * 24 * 60;
245 set_transient( $cache_key, $cache_value, $two_months );
246 }
247
248 return 1 === (int) $cache_value;
249 }
250
251 function matomo_filter_incompatible_plugins( &$plugin_list ) {
252 if ( empty( $GLOBALS['MATOMO_MARKETPLACE_PLUGINS'] ) ) {
253 return;
254 }
255
256 $incompatible_plugins = [];
257 foreach ( $GLOBALS['MATOMO_MARKETPLACE_PLUGINS'] as $wp_plugin_file ) {
258 if ( matomo_is_plugin_compatible( $wp_plugin_file ) ) {
259 continue;
260 }
261
262 $plugin_name = basename( dirname( $wp_plugin_file ) );
263 $incompatible_plugins[] = $plugin_name;
264 }
265
266 $plugin_list = array_values( array_diff( $plugin_list, $incompatible_plugins ) );
267 }
268
269 function matomo_add_plugin( $plugins_directory, $wp_plugin_file, $is_marketplace_plugin = false ) {
270 if ( ! in_array( $wp_plugin_file, $GLOBALS['MATOMO_PLUGIN_FILES'], true ) ) {
271 $GLOBALS['MATOMO_PLUGIN_FILES'][] = $wp_plugin_file;
272 }
273
274 if ( empty( $GLOBALS['MATOMO_PLUGIN_DIRS'] ) ) {
275 $GLOBALS['MATOMO_PLUGIN_DIRS'] = array();
276 }
277
278 if ( $is_marketplace_plugin && dirname( $wp_plugin_file ) === $plugins_directory ) {
279 $GLOBALS['MATOMO_MARKETPLACE_PLUGINS'][] = $wp_plugin_file;
280 }
281
282 $GLOBALS['MATOMO_PLUGINS_ENABLED'][] = basename( $plugins_directory );
283 $root_dir = dirname( $plugins_directory );
284 foreach ( $GLOBALS['MATOMO_PLUGIN_DIRS'] as $path ) {
285 if ( $path['pluginsPathAbsolute'] === $root_dir ) {
286 return; // already added
287 }
288 }
289
290 $matomo_dir = __DIR__ . DIRECTORY_SEPARATOR . 'app';
291 $webroot_dir = matomo_rel_path( $root_dir, $matomo_dir );
292
293 $GLOBALS['MATOMO_PLUGIN_DIRS'][] = array(
294 'pluginsPathAbsolute' => $root_dir,
295 'webrootDirRelativeToMatomo' => $webroot_dir,
296 );
297 }
298
299 function matomo_get_asset_version() {
300 $version = \WpMatomo::VERSION;
301 $version = apply_filters( 'matomo_asset_version', $version );
302 return $version;
303 }
304
305 if ( matomo_is_app_request() || ! empty( $GLOBALS['MATOMO_LOADED_DIRECTLY'] ) ) {
306 // prevent layout being broken when thegem theme is used. their lazy items class causes the reporting UI to not appear
307 // because it creates a JS error because of escaping " too often. only breaks when " Activate image loading optimization (for desktops)"
308 // is enabled in the general theme settings
309 add_filter( 'thegem_lazy_items_need_process_content', '__return_false', 99999999, $args = 0 );
310 }
311
312 require_once __DIR__ . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'WpMatomo.php';
313 require 'shared.php';
314 matomo_add_plugin( __DIR__ . '/plugins/WordPress', MATOMO_ANALYTICS_FILE );
315
316 new WpMatomo();
317