Matomo Analytics – Ethical Stats. Powerful Insights. - Version 1.3.0

Version Description

Download this release

Release Info

Developer matomoteam
Plugin Icon 128x128 Matomo Analytics – Ethical Stats. Powerful Insights.
Version 1.3.0
Comparing to
See all releases

Code changes from version 1.2.0 to 1.3.0

app/core/DataAccess/LogAggregator.php CHANGED
@@ -280,7 +280,9 @@ class LogAggregator
280
  if (defined('PIWIK_TEST_MODE') && PIWIK_TEST_MODE) {
281
  $engine = 'ENGINE=MEMORY';
282
  }
283
- $createTableSql = 'CREATE TEMPORARY TABLE ' . $table . ' (idvisit BIGINT(10) UNSIGNED NOT NULL) ' . $engine;
 
 
284
  // we do not insert the data right away using create temporary table ... select ...
285
  // to avoid metadata lock see eg https://www.percona.com/blog/2018/01/10/why-avoid-create-table-as-select-statement/
286
 
@@ -290,8 +292,24 @@ class LogAggregator
290
  } catch (\Exception $e) {
291
  if ($readerDb->isErrNo($e, \Piwik\Updater\Migration\Db::ERROR_CODE_TABLE_EXISTS)) {
292
  return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  }
294
- throw $e;
295
  }
296
 
297
  $transactionLevel = new Db\TransactionLevel($readerDb);
280
  if (defined('PIWIK_TEST_MODE') && PIWIK_TEST_MODE) {
281
  $engine = 'ENGINE=MEMORY';
282
  }
283
+
284
+ $tempTableIdVisitColumn = 'idvisit BIGINT(10) UNSIGNED NOT NULL';
285
+ $createTableSql = 'CREATE TEMPORARY TABLE ' . $table . ' (' . $tempTableIdVisitColumn . ') ' . $engine;
286
  // we do not insert the data right away using create temporary table ... select ...
287
  // to avoid metadata lock see eg https://www.percona.com/blog/2018/01/10/why-avoid-create-table-as-select-statement/
288
 
292
  } catch (\Exception $e) {
293
  if ($readerDb->isErrNo($e, \Piwik\Updater\Migration\Db::ERROR_CODE_TABLE_EXISTS)) {
294
  return;
295
+ } elseif ($readerDb->isErrNo($e, 1173)
296
+ || $readerDb->isErrNo($e, 3750)
297
+ || stripos($e->getMessage(), 'requires a primary key') !== false
298
+ || stripos($e->getMessage(), 'table without a primary key') !== false) {
299
+ $createTableSql = str_replace($tempTableIdVisitColumn, $tempTableIdVisitColumn . ', PRIMARY KEY (`idvisit`)', $createTableSql);
300
+
301
+ try {
302
+ $readerDb->query($createTableSql);
303
+ } catch (\Exception $e) {
304
+ if ( $readerDb->isErrNo( $e, \Piwik\Updater\Migration\Db::ERROR_CODE_TABLE_EXISTS ) ) {
305
+ return;
306
+ } else {
307
+ throw $e;
308
+ }
309
+ }
310
+ } else {
311
+ throw $e;
312
  }
 
313
  }
314
 
315
  $transactionLevel = new Db\TransactionLevel($readerDb);
app/plugins/UserCountryMap/Controller.php CHANGED
@@ -224,7 +224,7 @@ class Controller extends \Piwik\Plugin\Controller
224
 
225
  $view->config = array(
226
  'metrics' => array(),
227
- 'svgBasePath' => $view->piwikUrl . 'plugins/UserCountryMap/svg/',
228
  'liveRefreshAfterMs' => $liveRefreshAfterMs,
229
  '_' => $locale,
230
  'reqParams' => $reqParams,
224
 
225
  $view->config = array(
226
  'metrics' => array(),
227
+ 'svgBasePath' => 'plugins/UserCountryMap/svg/',
228
  'liveRefreshAfterMs' => $liveRefreshAfterMs,
229
  '_' => $locale,
230
  'reqParams' => $reqParams,
assets/js/optout.js ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function () {
2
+ var cookiename = 'mtm_consent_removed';
3
+
4
+ function listen_event(e, type, callback) {
5
+ if (e.addEventListener) {
6
+ return e.addEventListener(type, callback, false);
7
+ }
8
+
9
+ if (e.attachEvent) {
10
+ return e.attachEvent('on' + type, callback);
11
+ }
12
+
13
+ e['on' + type] = callback;
14
+ }
15
+ function by_id(id) {
16
+ return document.getElementById(id);
17
+ }
18
+ function are_cookies_disabled() {
19
+ return navigator && !navigator.cookieEnabled;
20
+ }
21
+ function set_display(id, status)
22
+ {
23
+ var e = by_id(id);
24
+ if (e) {
25
+ e.style.display = status;
26
+ }
27
+ }
28
+ function is_opted_out() {
29
+ // piwik_ignore check for BC.
30
+ return document.cookie && (document.cookie.indexOf(cookiename + '=1') !== -1 || document.cookie.indexOf('piwik_ignore=') !== -1);
31
+ }
32
+ function update_status()
33
+ {
34
+ if (are_cookies_disabled()) {
35
+ set_display('matomo_outout_err_cookies', 'block');
36
+ set_display('matomo_optout_checkbox', 'none');
37
+ } else if (is_opted_out()) {
38
+ set_display('matomo_opted_out_intro', 'block');
39
+ set_display('matomo_opted_in_intro', 'none');
40
+ set_display('matomo_opted_out_label', 'inline');
41
+ set_display('matomo_opted_in_label', 'none');
42
+ by_id('matomo_optout_checkbox').checked = false;
43
+ } else {
44
+ set_display('matomo_opted_out_intro', 'none');
45
+ set_display('matomo_opted_in_intro', 'block');
46
+ set_display('matomo_opted_out_label', 'none');
47
+ set_display('matomo_opted_in_label', 'inline');
48
+ by_id('matomo_optout_checkbox').checked = true;
49
+ }
50
+ }
51
+ function on_ready(callback) {
52
+ if (document.readyState === 'complete' || document.readyState === 'interactive') {
53
+ setTimeout(callback, 1);
54
+ } else {
55
+ document.addEventListener('DOMContentLoaded', callback);
56
+ }
57
+ }
58
+
59
+ function set_cookie(name, val, expires, path, domain)
60
+ {
61
+ var cookie = name + '=' + val + ';expires=' + expires + ';SameSite=Lax;path=' + (path || '/');
62
+ if (domain) {
63
+ cookie += ';domain=' + domain;
64
+ }
65
+ document.cookie = cookie;
66
+ }
67
+
68
+ on_ready(function () {
69
+ update_status();
70
+
71
+ if (are_cookies_disabled()) {
72
+ return;
73
+ }
74
+
75
+ listen_event(by_id('matomo_optout_checkbox'),'change', function () {
76
+ var trackers = [];
77
+ if ('object' === typeof window.Piwik && 'function' === typeof Piwik.getAsyncTrackers) {
78
+ trackers = Piwik.getAsyncTrackers();
79
+ }
80
+ var value = 0;
81
+ var expires = 'Thu, 01 Jan 1970 00:00:01 GMT'
82
+ if (is_opted_out()) {
83
+ // for BC additionally remove any set piwik_ignore cookie
84
+ set_cookie('piwik_ignore', 0, expires, '/');
85
+ } else {
86
+ value = 1;
87
+ var expire = new Date();
88
+ expire.setTime(expire.getTime() + (86400 * 365 * 30 * 1000));
89
+ expires = expire.toGMTString();
90
+ }
91
+
92
+ if (trackers.length) {
93
+ // respect tracker settings
94
+ for (var i = 0; i < trackers.length; i++) {
95
+ set_cookie(cookiename, value, expires, trackers[i].getCookiePath(), trackers[i].getCookieDomain());
96
+ }
97
+ } else {
98
+ // fallback
99
+ set_cookie(cookiename, value, expires, '/');
100
+ }
101
+
102
+ update_status();
103
+ });
104
+ })
105
+ })();
classes/WpMatomo/Admin/Menu.php CHANGED
@@ -260,6 +260,13 @@ class Menu {
260
 
261
  $url = self::get_reporting_url();
262
 
 
 
 
 
 
 
 
263
  if ( ! empty( $_GET['report_date'] ) ) {
264
  $url = add_query_arg(
265
  array(
@@ -269,12 +276,6 @@ class Menu {
269
  $url
270
  );
271
 
272
- $site = new Site();
273
- $idsite = $site->get_current_matomo_site_id();
274
-
275
- if ( $idsite ) {
276
- $url = add_query_arg( array( 'idSite' => (int) $idsite ), $url );
277
- }
278
 
279
  $date = new Dates();
280
  list( $period, $date ) = $date->detect_period_and_date( $_GET['report_date'] );
260
 
261
  $url = self::get_reporting_url();
262
 
263
+ $site = new Site();
264
+ $idsite = $site->get_current_matomo_site_id();
265
+
266
+ if ( $idsite ) {
267
+ $url = add_query_arg( array( 'idSite' => (int) $idsite ), $url );
268
+ }
269
+
270
  if ( ! empty( $_GET['report_date'] ) ) {
271
  $url = add_query_arg(
272
  array(
276
  $url
277
  );
278
 
 
 
 
 
 
 
279
 
280
  $date = new Dates();
281
  list( $period, $date ) = $date->detect_period_and_date( $_GET['report_date'] );
classes/WpMatomo/Admin/PrivacySettings.php CHANGED
@@ -17,7 +17,7 @@ if ( ! defined( 'ABSPATH' ) ) {
17
 
18
  class PrivacySettings implements AdminSettingsInterface {
19
  const EXAMPLE_MINIMAL = '[matomo_opt_out]';
20
- const EXAMPLE_FULL = '[matomo_opt_out language=de background_color=red font_color=fff font_size=34 font_family=Arial width=500px height=100px]';
21
 
22
  /**
23
  * @var Settings
17
 
18
  class PrivacySettings implements AdminSettingsInterface {
19
  const EXAMPLE_MINIMAL = '[matomo_opt_out]';
20
+ const EXAMPLE_FULL = '[matomo_opt_out language=de]';
21
 
22
  /**
23
  * @var Settings
classes/WpMatomo/Admin/views/info_help.php CHANGED
@@ -22,7 +22,10 @@ if ( ! defined( 'ABSPATH' ) ) {
22
  href="https://matomo.org/docs/"><?php esc_html_e( 'User guides', 'matomo' ); ?></a>
23
  - <?php esc_html_e( 'Learn how to configure Matomo and how to effectively analyse your data', 'matomo' ); ?>
24
  </li>
25
- <li><a target="_blank" rel="noreferrer noopener" href="https://matomo.org/faq/"><?php esc_html_e( 'FAQs', 'matomo' ); ?></a>
 
 
 
26
  - <?php esc_html_e( 'Get answers to frequently asked questions', 'matomo' ); ?>
27
  </li>
28
  <li><a target="_blank" rel="noreferrer noopener"
22
  href="https://matomo.org/docs/"><?php esc_html_e( 'User guides', 'matomo' ); ?></a>
23
  - <?php esc_html_e( 'Learn how to configure Matomo and how to effectively analyse your data', 'matomo' ); ?>
24
  </li>
25
+ <li><a target="_blank" rel="noreferrer noopener" href="https://matomo.org/faq/wordpress/"><?php esc_html_e( 'Matomo for WordPress FAQs', 'matomo' ); ?></a>
26
+ - <?php esc_html_e( 'Get answers to frequently asked questions', 'matomo' ); ?>
27
+ </li>
28
+ <li><a target="_blank" rel="noreferrer noopener" href="https://matomo.org/faq/"><?php esc_html_e( 'General FAQs', 'matomo' ); ?></a>
29
  - <?php esc_html_e( 'Get answers to frequently asked questions', 'matomo' ); ?>
30
  </li>
31
  <li><a target="_blank" rel="noreferrer noopener"
classes/WpMatomo/Admin/views/privacy_gdpr.php CHANGED
@@ -86,13 +86,6 @@ if ( ! defined( 'ABSPATH' ) ) {
86
  <?php esc_html_e( 'You can use these short code options:', 'matomo' ); ?>
87
  </p>
88
  <ul class="matomo-list">
89
- <li>language - eg de or
90
- en. <?php esc_html_e( 'By default the language is detected automatically based on the user\'s browser', 'matomo' ); ?></li>
91
- <li>background_color - eg black or #000</li>
92
- <li>font_color - eg black or #000</li>
93
- <li>font_size - eg 15px</li>
94
- <li>font_family - eg Arial or Verdana</li>
95
- <li>width - eg 600, 600px or 100%</li>
96
- <li>height - eg 200, 200px or 20%</li>
97
  </ul>
98
  <p><?php esc_html_e( 'Example', 'matomo' ); ?>: <code><?php echo esc_html( PrivacySettings::EXAMPLE_FULL ); ?></code></p>
86
  <?php esc_html_e( 'You can use these short code options:', 'matomo' ); ?>
87
  </p>
88
  <ul class="matomo-list">
89
+ <li>language - eg de or en. <?php esc_html_e( 'By default the language is detected automatically based on the user\'s browser', 'matomo' ); ?></li>
 
 
 
 
 
 
 
90
  </ul>
91
  <p><?php esc_html_e( 'Example', 'matomo' ); ?>: <code><?php echo esc_html( PrivacySettings::EXAMPLE_FULL ); ?></code></p>
classes/WpMatomo/OptOut.php CHANGED
@@ -9,64 +9,85 @@
9
 
10
  namespace WpMatomo;
11
 
 
 
 
12
  if ( ! defined( 'ABSPATH' ) ) {
13
  exit; // if accessed directly
14
  }
15
 
16
  class OptOut {
17
 
 
 
18
  public function register_hooks() {
19
  add_shortcode( 'matomo_opt_out', array( $this, 'show_opt_out' ) );
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
 
22
  public function show_opt_out( $atts ) {
23
  $a = shortcode_atts(
24
  array(
25
- 'language' => '',
26
- 'background_color' => '',
27
- 'font_color' => '',
28
- 'font_size' => '',
29
- 'font_family' => '',
30
- 'width' => '600',
31
- 'height' => '200',
32
  ),
33
  $atts
34
  );
 
 
 
35
 
36
- $url = plugins_url( 'app', MATOMO_ANALYTICS_FILE ) . '/index.php';
37
-
38
- $map = array(
39
- 'background_color' => 'backgroundColor',
40
- 'font_color' => 'fontColor',
41
- 'font_size' => 'fontSize',
42
- 'font_family' => 'fontFamily',
43
- );
44
- $params = array(
45
- 'module' => 'CoreAdminHome',
46
- 'action' => 'optOut',
47
- );
48
- if ( ! empty( $a['language'] ) ) {
49
- $params['language'] = $a['language'];
50
  }
51
- foreach ( $map as $param => $urlparam ) {
52
- if ( ! empty( $a[ $param ] ) ) {
53
- $params[ $urlparam ] = rawurlencode( $a[ $param ] );
54
- }
 
 
55
  }
56
 
57
- $url = $url . '?' . http_build_query( $params );
58
- $sizes = array( 'width', 'height' );
59
- $add_style = '';
60
- foreach ( $sizes as $size ) {
61
- if ( is_numeric( $a[ $size ] ) || preg_match( '/\d+px/', $a[ $size ] ) || preg_match( '/\d+%/', $a[ $size ] ) ) {
62
- if ( is_numeric( $a[ $size ] ) ) {
63
- $a[ $size ] = $a[ $size ] . 'px';
64
- }
65
- $add_style .= $size . ':' . $a[ $size ] . ';';
66
- }
 
 
67
  }
68
 
69
- return '<iframe style="border: 0; ' . $add_style . '" src="' . $url . '"></iframe>';
 
 
 
 
 
 
 
 
 
 
 
70
  }
71
 
72
  }
9
 
10
  namespace WpMatomo;
11
 
12
+ use Piwik\Piwik;
13
+ use Piwik\Plugins\PrivacyManager\DoNotTrackHeaderChecker;
14
+
15
  if ( ! defined( 'ABSPATH' ) ) {
16
  exit; // if accessed directly
17
  }
18
 
19
  class OptOut {
20
 
21
+ private $language = null;
22
+
23
  public function register_hooks() {
24
  add_shortcode( 'matomo_opt_out', array( $this, 'show_opt_out' ) );
25
+ add_action( 'wp_enqueue_scripts', array( $this, 'load_scripts' ) );
26
+ }
27
+
28
+ public function load_scripts() {
29
+ if (!is_admin()) {
30
+ wp_register_script( 'matomo_opt_out_js', plugins_url( 'assets/js/optout.js', MATOMO_ANALYTICS_FILE ), array(), null, true );
31
+ }
32
+ }
33
+
34
+ private function translate($id)
35
+ {
36
+ return esc_html(Piwik::translate($id, array(), $this->language));
37
  }
38
 
39
  public function show_opt_out( $atts ) {
40
  $a = shortcode_atts(
41
  array(
42
+ 'language' => null,
 
 
 
 
 
 
43
  ),
44
  $atts
45
  );
46
+ if (!empty($a['language']) && strlen($a['language']) < 6) {
47
+ $this->language = $a['language'];
48
+ }
49
 
50
+ try {
51
+ Bootstrap::do_bootstrap();
52
+ } catch (\Throwable $e ) {
53
+ $logger = new Logger();
54
+ $logger->log_exception('optout', $e);
55
+ return '<p>An error occurred. Please check Matomo system report in WP-Admin.</p>';
 
 
 
 
 
 
 
 
56
  }
57
+
58
+ $dnt_checker = new DoNotTrackHeaderChecker();
59
+ $dnt_enabled = $dnt_checker->isDoNotTrackFound();
60
+
61
+ if (!empty($dnt_enabled)) {
62
+ return '<p>'. $this->translate('CoreAdminHome_OptOutDntFound').'</p>';
63
  }
64
 
65
+ wp_enqueue_script( 'matomo_opt_out_js' );
66
+
67
+ $track_visits = empty($_COOKIE['mtm_consent_removed']);
68
+
69
+ $style_tracking_enabled = '';
70
+ $style_tracking_disabled = '';
71
+ $checkbox_attr = '';
72
+ if ($track_visits) {
73
+ $style_tracking_enabled = 'style="display:none;"';
74
+ $checkbox_attr = 'checked="checked"';
75
+ } else {
76
+ $style_tracking_disabled = 'style="display:none;"';
77
  }
78
 
79
+ $content = '<p id="matomo_opted_out_intro" ' . $style_tracking_enabled . '>' . $this->translate('CoreAdminHome_OptOutComplete') . ' ' . $this->translate('CoreAdminHome_OptOutCompleteBis') . '</p>';
80
+ $content .= '<p id="matomo_opted_in_intro" ' .$style_tracking_disabled . '>' . $this->translate('CoreAdminHome_YouMayOptOut2') . ' ' . $this->translate('CoreAdminHome_YouMayOptOut3') . '</p>';
81
+
82
+ $content .= '<form>
83
+ <input type="checkbox" id="matomo_optout_checkbox" '.$checkbox_attr.'/>
84
+ <label for="matomo_optout_checkbox"><strong>
85
+ <span id="matomo_opted_in_label" '.$style_tracking_disabled.'>'.$this->translate('CoreAdminHome_YouAreNotOptedOut') .' ' . $this->translate('CoreAdminHome_UncheckToOptOut') . '</span>
86
+ <span id="matomo_opted_out_label" '.$style_tracking_enabled.'>'.$this->translate('CoreAdminHome_YouAreOptedOut') .' ' . $this->translate('CoreAdminHome_CheckToOptIn') . '</span>
87
+ </strong></label></form>';
88
+ $content .= '<noscript><p><strong style="color: #ff0000;">This opt out feature requires JavaScript.</strong></p></noscript>';
89
+ $content .= '<p id="matomo_outout_err_cookies" style="display: none;"><strong>' . $this->translate('CoreAdminHome_OptOutErrorNoCookies') . '</strong></p>';
90
+ return $content;
91
  }
92
 
93
  }
classes/WpMatomo/TrackingCode/TrackingCodeGenerator.php CHANGED
@@ -293,7 +293,7 @@ g.type='text/javascript'; g.async=true; g.src=" . wp_json_encode( $js_endpoint )
293
  $script .= '</script>';
294
  $script .= '<!-- End Matomo Code -->';
295
 
296
- $no_script = '<noscript><p><img src="' . esc_url( $tracker_endpoint ) . '?idsite=' . intval( $idsite ) . '&amp;rec=1" style="border:0;" alt="" /></p></noscript>';
297
 
298
  $script = apply_filters( 'matomo_tracking_code_script', $script, $idsite );
299
  $script = apply_filters( 'matomo_tracking_code_noscript', $script, $idsite );
293
  $script .= '</script>';
294
  $script .= '<!-- End Matomo Code -->';
295
 
296
+ $no_script = '<noscript><p><img referrerpolicy="no-referrer-when-downgrade" src="' . esc_url( $tracker_endpoint ) . '?idsite=' . intval( $idsite ) . '&amp;rec=1" style="border:0;" alt="" /></p></noscript>';
297
 
298
  $script = apply_filters( 'matomo_tracking_code_script', $script, $idsite );
299
  $script = apply_filters( 'matomo_tracking_code_noscript', $script, $idsite );
classes/WpMatomo/User/Sync.php CHANGED
@@ -9,6 +9,7 @@
9
 
10
  namespace WpMatomo\User;
11
 
 
12
  use Piwik\Access\Role\Admin;
13
  use Piwik\Access\Role\View;
14
  use Piwik\Access\Role\Write;
@@ -180,6 +181,30 @@ class Sync {
180
  }
181
  }
182
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  }
184
 
185
  foreach ( $super_users as $matomo_login => $user ) {
9
 
10
  namespace WpMatomo\User;
11
 
12
+ use Piwik\Access;
13
  use Piwik\Access\Role\Admin;
14
  use Piwik\Access\Role\View;
15
  use Piwik\Access\Role\Write;
181
  }
182
  }
183
  }
184
+
185
+ if ($idsite != 1) {
186
+ // only needed if the actual site is not the default site... makes sure when they click in Matomo
187
+ // UI on "Dashboard" that the correct site is being opened by default
188
+ // eg if the linked site is actually idSite=2.
189
+ Access::doAsSuperUser(
190
+ function () use ( $matomo_login, &$idsite ) {
191
+ try {
192
+ UsersManager\API::unsetInstance();
193
+ // we need to unset the instance to make sure it fetches the
194
+ // up to date dependencies eg current plugin manager etc
195
+
196
+ UsersManager\API::getInstance()->setUserPreference(
197
+ $matomo_login,
198
+ UsersManager\API::PREFERENCE_DEFAULT_REPORT,
199
+ $idsite
200
+ );
201
+ } catch (\Exception $e) {
202
+ // ignore any error for now
203
+ }
204
+
205
+ }
206
+ );
207
+ }
208
  }
209
 
210
  foreach ( $super_users as $matomo_login => $user ) {
matomo.php CHANGED
@@ -4,7 +4,7 @@
4
  * Description: The #1 Google Analytics alternative that gives you full control over your data and protects the privacy for your users. Free, secure and open.
5
  * Author: Matomo
6
  * Author URI: https://matomo.org
7
- * Version: 1.2.0
8
  * Domain Path: /languages
9
  * WC requires at least: 2.4.0
10
  * WC tested up to: 4.0.0
4
  * Description: The #1 Google Analytics alternative that gives you full control over your data and protects the privacy for your users. Free, secure and open.
5
  * Author: Matomo
6
  * Author URI: https://matomo.org
7
+ * Version: 1.3.0
8
  * Domain Path: /languages
9
  * WC requires at least: 2.4.0
10
  * WC tested up to: 4.0.0
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_i
4
  Tags: matomo,piwik,analytics,statistics,stats,tracking,ecommerce
5
  Requires at least: 4.8
6
  Tested up to: 5.5
7
- Stable tag: 1.2.0
8
  Requires PHP: 7.2
9
  License: GPLv3 or later
10
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
@@ -53,7 +53,7 @@ Matomo is free, secure and open - your ethical user insights platform.
53
 
54
  **Features include:**
55
 
56
- * Ecommerce features
57
  * Campaign tracking
58
  * Visitor profiles
59
  * Tag Manager
4
  Tags: matomo,piwik,analytics,statistics,stats,tracking,ecommerce
5
  Requires at least: 4.8
6
  Tested up to: 5.5
7
+ Stable tag: 1.3.0
8
  Requires PHP: 7.2
9
  License: GPLv3 or later
10
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
53
 
54
  **Features include:**
55
 
56
+ * Ecommerce features (supports WooCommerce, Easy Digital Downloads and MemberPress out of the box)
57
  * Campaign tracking
58
  * Visitor profiles
59
  * Tag Manager