PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.3.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.3.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 / Site / Sync.php
matomo / classes / WpMatomo / Site Last commit date
Sync 6 years ago Sync.php 5 years ago
Sync.php
290 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 */
9
10 namespace WpMatomo\Site;
11
12 use Piwik\Access;
13 use Piwik\API\Request;
14 use Piwik\Common;
15 use Piwik\Config;
16 use Piwik\Plugins\SitesManager\Model;
17 use Piwik\Plugins\SitesManager;
18 use WpMatomo\Bootstrap;
19 use WpMatomo\Installer;
20 use WpMatomo\Logger;
21 use WpMatomo\Settings;
22 use WpMatomo\Site;
23 use WpMatomo\Site\Sync\SyncConfig;
24
25 if ( ! defined( 'ABSPATH' ) ) {
26 exit; // if accessed directly
27 }
28
29 class Sync {
30 const MAX_LENGTH_SITE_NAME = 90;
31
32 /**
33 * @var Logger
34 */
35 private $logger;
36
37 /**
38 * @var Settings
39 */
40 private $settings;
41
42 /**
43 * @var SyncConfig
44 */
45 private $config_sync;
46
47 public function __construct( Settings $settings ) {
48 $this->logger = new Logger();
49 $this->settings = $settings;
50 $this->config_sync = new SyncConfig( $settings );
51 }
52
53 public function register_hooks() {
54 add_action( 'update_option_blogname', array( $this, 'sync_current_site_ignore_error' ) );
55 add_action( 'update_option_home', array( $this, 'sync_current_site_ignore_error' ) );
56 add_action( 'update_option_siteurl', array( $this, 'sync_current_site_ignore_error' ) );
57 add_action( 'update_option_timezone_string', array( $this, 'sync_current_site_ignore_error' ) );
58 add_action( 'matomo_setting_change_track_ecommerce', array( $this, 'sync_current_site_ignore_error' ) );
59 add_action( 'matomo_setting_change_site_currency', array( $this, 'sync_current_site_ignore_error' ) );
60 }
61
62 public function sync_current_site_ignore_error()
63 {
64 try {
65 $this->sync_current_site();
66 } catch (\Exception $e) {
67 $this->logger->log( 'Ignoring site sync error: ' . $e->getMessage());
68 $this->logger->log_exception('sync_site_ignore', $e);
69 }
70 }
71
72 public function sync_all() {
73 $succeed_all = true;
74
75 Bootstrap::do_bootstrap();
76
77 if ( is_multisite() && function_exists( 'get_sites' ) ) {
78 foreach ( get_sites() as $site ) {
79 /** @var \WP_Site $site */
80 switch_to_blog( $site->blog_id );
81 try {
82 $installer = new Installer( $this->settings );
83 if ( ! $installer->looks_like_it_is_installed() ) {
84 $this->logger->log( sprintf( 'Matomo was not installed yet for blog: %s installing now.', $site->blog_id ) );
85
86 // prevents error that it wouldn't fully install matomo for a different site as it would think it already did install it etc.
87 // and would otherwise think plugins are already activated etc
88 Bootstrap::set_not_bootstrapped();
89 $config = Config::getInstance();
90 $installed = $config->PluginsInstalled;
91 $installed['PluginsInstalled'] = array();
92 $config->PluginsInstalled = $installed;
93
94 if ( $installer->can_be_installed() ) {
95 $installer->install();
96 } else {
97 continue;
98 }
99 }
100
101 $success = $this->sync_site( $site->blog_id, $site->blogname, $site->siteurl );
102 } catch ( \Exception $e ) {
103 $success = false;
104 // we don't want to rethrow exception otherwise some other blogs might never sync
105 $this->logger->log( 'Matomo error syncing site: ' . $e->getMessage() );
106 }
107
108 $succeed_all = $succeed_all && $success;
109 restore_current_blog();
110 }
111 } else {
112 $success = $this->sync_current_site();
113 $succeed_all = $succeed_all && $success;
114 }
115
116 return $succeed_all;
117 }
118
119 public function sync_current_site() {
120 return $this->sync_site( get_current_blog_id(), get_bloginfo( 'name' ), get_bloginfo( 'url' ) );
121 }
122
123 public function sync_site( $blog_id, $blog_name, $blog_url ) {
124 Bootstrap::do_bootstrap();
125 $this->logger->log( 'Matomo is now syncing blogId ' . $blog_id );
126
127 $idsite = Site::get_matomo_site_id( $blog_id );
128
129 if ( empty( $blog_name ) ) {
130 $blog_name = esc_html__( 'Default', 'matomo' );
131 } else {
132 $blog_name = substr( $blog_name, 0, self::MAX_LENGTH_SITE_NAME );
133 }
134
135 $track_ecommerce = (int) $this->settings->get_global_option( 'track_ecommerce' );
136 $site_currency = $this->settings->get_global_option( Settings::SITE_CURRENCY );
137 $detected_timezone = $this->detect_timezone();
138
139 $valid_currencies = \Piwik\Site::getCurrencyList();
140 if (!array_key_exists($site_currency, $valid_currencies)){
141 $site_currency = 'USD';
142 }
143
144 if ( ! empty( $idsite ) ) {
145 $this->logger->log( 'Matomo site is known for blog (' . $idsite . ')... will update' );
146
147 $sites_manager_model = new Model();
148 $site = $sites_manager_model->getSiteFromId($idsite);
149 if ($site['name'] != $blog_name
150 || $site['main_url'] != $blog_url
151 || $site['ecommerce'] != $track_ecommerce
152 || $site['currency'] != $site_currency
153 || $site['timezone'] != $detected_timezone) {
154
155 /** @var \WP_Site $site */
156 $params = array(
157 'name' => $blog_name,
158 'main_url' => $blog_url,
159 'ecommerce' => $track_ecommerce,
160 'currency' => $site_currency,
161 'timezone' => $detected_timezone,
162 );
163 $sites_manager_model->updateSite( $params, $idsite );
164
165 do_action( 'matomo_site_synced', $idsite, $blog_id );
166
167 // no actual setting changed but we make sure the tracking code will be updated after an update
168 $this->settings->apply_tracking_related_changes( array() );
169 }
170
171 $this->config_sync->sync_config_for_current_site();
172
173 return true;
174 }
175
176 $this->logger->log( 'Matomo site is not known for blog... will create site' );
177
178 /** @var \WP_Site $site */
179 $idsite = null;
180
181 $this->set_enable_sites_admin( 1 );
182
183 Access::doAsSuperUser(
184 function () use ( $blog_name, $blog_url, $detected_timezone, $track_ecommerce, &$idsite, $site_currency ) {
185 SitesManager\API::unsetInstance();
186 // we need to unset the instance to make sure it fetches the
187 // up to date dependencies eg current plugin manager etc
188
189 $idsite = SitesManager\API::getInstance()->addSite(
190 $blog_name,
191 array( $blog_url ),
192 $track_ecommerce,
193 $site_search = null,
194 $search_keyword_parameters = null,
195 $search_category_parameters = null,
196 $excluded_ips = null,
197 $excluded_query_parameters = null,
198 $detected_timezone,
199 $site_currency
200 );
201 }
202 );
203 $this->set_enable_sites_admin( 0 );
204
205 $this->logger->log( 'Matomo created site with ID ' . $idsite . ' for blog' );
206
207 Site::map_matomo_site_id( $blog_id, $idsite );
208
209 if ( ! is_numeric( $idsite ) || 0 === $idsite || '0' === $idsite ) {
210 $this->logger->log( sprintf( 'Creating the website failed: %s', wp_json_encode( $blog_id ) ) );
211
212 return false;
213 }
214
215 $this->config_sync->sync_config_for_current_site();
216
217 do_action( 'matomo_site_synced', $idsite, $blog_id );
218
219 return true;
220 }
221
222 private function set_enable_sites_admin( $enabled ) {
223 $general = Config::getInstance()->General;
224 $general['enable_sites_admin'] = (int) $enabled;
225 Config::getInstance()->General = $general;
226 }
227
228 private function detect_timezone() {
229 $timezone = get_option( 'timezone_string' );
230
231 if ( $timezone && $this->check_and_try_to_set_default_timezone( $timezone ) ) {
232 return $timezone;
233 }
234
235 // older WordPress
236 $utc_offset = (int) get_option( 'gmt_offset', 0 );
237
238 if ( 0 === $utc_offset ) {
239 return 'UTC';
240 }
241
242 $utc_offset_in_seconds = $utc_offset * 3600;
243 $timezone = timezone_name_from_abbr( '', $utc_offset_in_seconds );
244
245 if ( $timezone && $this->check_and_try_to_set_default_timezone( $timezone ) ) {
246 return $timezone;
247 }
248
249 $dst = (bool) date( 'I' );
250 foreach ( timezone_abbreviations_list() as $abbr ) {
251 foreach ( $abbr as $city ) {
252 if ( $dst === (bool) $city['dst']
253 && $city['timezone_id']
254 && (int) $city['offset'] === $utc_offset_in_seconds ) {
255 return $city['timezone_id'];
256 }
257 }
258 }
259
260 if ( is_numeric( $utc_offset ) ) {
261 if ( $utc_offset > 0 ) {
262 $timezone = 'UTC+' . $utc_offset;
263 } else {
264 $timezone = 'UTC' . $utc_offset;
265 }
266
267 if ( $this->check_and_try_to_set_default_timezone( $timezone ) ) {
268 return $timezone;
269 }
270 }
271
272 return 'UTC';
273 }
274
275 private function check_and_try_to_set_default_timezone( $timezone ) {
276 try {
277 Access::doAsSuperUser(function () use ($timezone) {
278 // make sure we're loading the latest instance with all up to date dependencies... mainly needed for tests
279 SitesManager\API::unsetInstance();
280 SitesManager\API::getInstance()->setDefaultTimezone( $timezone );
281 });
282 } catch ( \Exception $e ) {
283 return false;
284 }
285
286 return true;
287 }
288
289 }
290