PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.0.11
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.0.11
6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 5.2.2 5.3 All 153 releases
mainwp / class / class-mainwp-sync.php

class-mainwp-sync.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies 6.0.11, at class/class-mainwp-sync.php

965 lines 41.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MainWP Sync Handler
4 *
5 * Handle all syncing between MainWP & Child Site Network.
6 *
7 * @package MainWP/Dashboard
8 */
9
10 namespace MainWP\Dashboard;
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Class MainWP_Sync
19 *
20 * @package MainWP\Dashboard
21 */
22 class MainWP_Sync { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
23
24 /**
25 * Clone websites setting.
26 *
27 * @var mixed Clone websites.
28 */
29 public static $clone_websites = null;
30
31 /**
32 * Clone enabled setting.
33 *
34 * @var mixed Clone enabled.
35 */
36 public static $clone_enabled = null;
37
38
39 /**
40 * Disallowed Clone sites setting.
41 *
42 * @var mixed Disallowed clone.
43 */
44 public static $disallowed_clone_sites = null;
45
46 /**
47 * Get the current stack action if the helper is available.
48 *
49 * Some execution paths can reach sync handlers before the stack helper
50 * has been loaded, so telemetry must degrade safely instead of fatalling.
51 *
52 * @return string|null
53 */
54 protected static function get_current_stack_action() {
55 return class_exists( __NAMESPACE__ . '\MainWP_Stack_Helper' ) ? MainWP_Stack_Helper::stack_current() : null;
56 }
57
58 /**
59 * Push a stack action if the helper is available.
60 *
61 * @param string $action Stack action.
62 * @return void
63 */
64 protected static function push_stack_action( $action ) {
65 if ( class_exists( __NAMESPACE__ . '\MainWP_Stack_Helper' ) ) {
66 MainWP_Stack_Helper::stack_push( $action );
67 }
68 }
69
70
71 /**
72 * Method sync_website()
73 *
74 * Sync Child Site.
75 *
76 * @param object $website object.
77 * @param bool $clear_session to run the ending session or not.
78 *
79 * @return bool sync result.
80 */
81 public static function sync_website( $website, $clear_session = true ) {
82 if ( ! is_object( $website ) ) {
83 return false;
84 }
85 MainWP_DB::instance()->update_website_sync_values( $website->id, array( 'dtsSyncStart' => time() ) );
86 return static::sync_site( $website, false, true, $clear_session );
87 }
88
89 /**
90 * Method sync_site()
91 *
92 * @param mixed $pWebsite Null|userid.
93 * @param bool $pForceFetch Check if a fourced Sync.
94 * @param bool $pAllowDisconnect Check if allowed to disconect.
95 * @param bool $clear_session to run the ending session or not.
96 *
97 * @return bool sync_information_array
98 *
99 * @uses \MainWP\Dashboard\MainWP_DB_Common::get_user_extension_by_user_id()
100 * @uses \MainWP\Dashboard\MainWP_DB::query()
101 * @uses \MainWP\Dashboard\MainWP_DB::update_website_option()
102 * @uses \MainWP\Dashboard\MainWP_DB::fetch_object()
103 * @uses \MainWP\Dashboard\MainWP_DB::free_result()
104 * @uses \MainWP\Dashboard\MainWP_Exception
105 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_primary_backup()
106 * @uses \MainWP\Dashboard\MainWP_Utility::end_session()
107 */
108 public static function sync_site( &$pWebsite = null, $pForceFetch = false, $pAllowDisconnect = true, $clear_session = true ) { // phpcs:ignore -- NOSONAR - complexity method.
109
110 // to support demo data.
111 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $pWebsite ) ) {
112 return MainWP_Demo_Handle::get_instance()->handle_action_demo( $pWebsite, 'sync_site' );
113 }
114
115 if ( null === $pWebsite ) {
116 return false;
117 }
118 $userExtension = MainWP_DB_Common::instance()->get_user_extension_by_user_id( $pWebsite->userid );
119 if ( null === $userExtension ) {
120 return false;
121 }
122
123 if ( $clear_session ) {
124 MainWP_Utility::end_session();
125 }
126
127 $cur_id = MainWP_System_Utility::get_current_wpid();
128 if ( empty( $cur_id ) ) {
129 MainWP_System_Utility::set_current_wpid( $pWebsite->id );
130 }
131
132 MainWP_Logger::instance()->log_execution_sync( 'init', '', $pWebsite );
133 $stats_track_id = MainWP_Execution_Helper::execute_call_track( 'start_point', $pWebsite );
134
135 try {
136
137 if ( null === static::$clone_enabled ) {
138
139 /**
140 * Filter: mainwp_clone_enabled
141 *
142 * Filters whether the Clone feature is enabled or disabled.
143 *
144 * @since Unknown
145 */
146 static::$clone_enabled = apply_filters( 'mainwp_clone_enabled', false );
147 static::$clone_websites = array();
148
149 if ( static::$clone_enabled ) {
150
151 static::$disallowed_clone_sites = get_option( 'mainwp_clone_disallowedsites' );
152
153 if ( ! is_array( static::$disallowed_clone_sites ) ) {
154 static::$disallowed_clone_sites = array();
155 }
156
157 $wpsite_fields = array( 'id', 'name', 'url', 'adminname' );
158 $sync_fields = array( 'extauth', 'totalsize' );
159 $websites = MainWP_DB::instance()->query(
160 MainWP_DB::instance()->get_sql_websites_for_current_user_by_params(
161 array(
162 'select_wp_fields' => $wpsite_fields,
163 'select_sync_fields' => $sync_fields,
164 )
165 )
166 );
167
168 if ( $websites ) {
169 while ( $websites && ( $website = MainWP_DB::fetch_object( $websites ) ) ) {
170 if ( in_array( $website->id, static::$disallowed_clone_sites ) ) {
171 continue;
172 }
173 if ( (int) $website->id === (int) $pWebsite->id ) {
174 continue;
175 }
176
177 static::$clone_websites[ $website->id ] = array(
178 'name' => $website->name,
179 'url' => $website->url,
180 'extauth' => $website->extauth,
181 'size' => $website->totalsize,
182 'connect_admin' => $website->adminname,
183 );
184 }
185 MainWP_DB::free_result( $websites );
186 }
187 $disallowed_current_site = in_array( $pWebsite->id, static::$disallowed_clone_sites ) ? true : false;
188 }
189 }
190
191 $disallowed_current_site = static::$clone_enabled && is_array( static::$disallowed_clone_sites ) && in_array( $pWebsite->id, static::$disallowed_clone_sites ) ? true : false;
192
193 $primaryBackup = MainWP_System_Utility::get_primary_backup();
194
195 $othersData = apply_filters_deprecated( 'mainwp-sync-others-data', array( array(), $pWebsite ), '4.0.7.2', 'mainwp_sync_others_data' ); // @deprecated Use 'mainwp_sync_others_data' instead. NOSONAR - not IP.
196
197 /**
198 * Filter: mainwp_sync_others_data
199 *
200 * Filters additional data in the sync request. Allows extensions or 3rd party plugins to hook data to the sync request.
201 *
202 * @param object $pWebsite Object contaning child site data.
203 *
204 * @since Unknown
205 *
206 * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
207 */
208 $othersData = apply_filters( 'mainwp_sync_others_data', $othersData, $pWebsite );
209
210 $saved_days_number = apply_filters( 'mainwp_site_actions_saved_days_number', 30 );
211
212 $backup_method = '';
213 if ( property_exists( $pWebsite, 'primary_backup_method' ) ) {
214 if ( '' === $pWebsite->primary_backup_method || 'global' === $pWebsite->primary_backup_method ) {
215 $backup_method = $primaryBackup;
216 } else {
217 $backup_method = $pWebsite->primary_backup_method;
218 }
219 }
220
221 $postdata = array(
222 'optimize' => 1 === (int) get_option( 'mainwp_optimize', 1 ) ? 1 : 0,
223 'cloneSites' => ( ! static::$clone_enabled || $disallowed_current_site ) ? 0 : rawurlencode( wp_json_encode( static::$clone_websites ) ),
224 'othersData' => wp_json_encode( $othersData ),
225 'server' => get_admin_url(),
226 'numberdaysOutdatePluginTheme' => get_option( 'mainwp_numberdays_Outdate_Plugin_Theme', 365 ),
227 'primaryBackup' => $backup_method, // if empty site backup method will not sync the backup info from child site.
228 'siteId' => $pWebsite->id,
229 'child_actions_saved_days_number' => intval( $saved_days_number ),
230 'pingnonce' => MainWP_Utility::instance()->create_site_nonce( 'pingnonce', $pWebsite->id ),
231 );
232
233 $individual_settings_json = MainWP_DB::instance()->get_website_option( $pWebsite, 'password_policy_individual_settings' );
234 $individual_settings = array();
235
236 if ( ! empty( $individual_settings_json ) ) {
237 $individual_settings = json_decode( $individual_settings_json, true );
238 if ( ! is_array( $individual_settings ) ) {
239 $individual_settings = array();
240 }
241 }
242
243 if ( ! empty( $individual_settings['overwrite_enabled'] ) ) {
244 $password_policy_settings = wp_parse_args(
245 $individual_settings,
246 array(
247 'max_age_days' => 0,
248 'due_soon_message' => __( 'Your password is due to be changed soon. Please update it as soon as possible. This helps keep your account secure.', 'mainwp' ),
249 'overdue_message' => __( 'Your password change is overdue. Please update your password now. This is required by your site\'s password policy.', 'mainwp' ),
250 'show_notices_to' => 'edit_posts',
251 )
252 );
253 } else {
254 $password_policy_defaults = array(
255 'max_age_days' => 0,
256 'due_soon_message' => __( 'Your password is due to be changed soon. Please update it as soon as possible. This helps keep your account secure.', 'mainwp' ),
257 'overdue_message' => __( 'Your password change is overdue. Please update your password now. This is required by your site\'s password policy.', 'mainwp' ),
258 'show_notices_to' => 'edit_posts',
259 );
260 $password_policy_settings = wp_parse_args( get_option( 'mainwp_password_policy_settings', array() ), $password_policy_defaults );
261 }
262
263 $postdata['passwordPolicySettings'] = wp_json_encode( $password_policy_settings );
264
265 $reg_verify = MainWP_DB::instance()->get_website_option( $pWebsite, 'register_verify_key', '' );
266 if ( empty( $reg_verify ) ) {
267 $postdata['sync_regverify'] = 1;
268 }
269
270 $postdata['params_logs'] = apply_filters( 'mainwp_module_logs_changes_logs_sync_params', '', $pWebsite->id, $postdata, $pWebsite );
271
272 if ( class_exists( '\MainWP\Dashboard\Module\Log\Log_Manager' ) ) {
273 $sync_last_created = \MainWP\Dashboard\Module\Log\Log_Manager::instance()->get_sync_actions_last_created( $pWebsite->id );
274 $postdata['child_actions_last_created'] = (float) $sync_last_created;
275 }
276
277 $synclist = MainWP_Settings::get_instance()->get_data_list_to_sync();
278 $postdata['syncdata'] = wp_json_encode( $synclist );
279
280 static::push_stack_action( 'sync_stats' );
281
282 $information = MainWP_Connect::fetch_url_authed(
283 $pWebsite,
284 'stats',
285 $postdata,
286 true,
287 $pForceFetch
288 );
289
290 $return = static::sync_information_array( $pWebsite, $information, '', false, false, $pAllowDisconnect );
291 MainWP_Logger::instance()->log_execution_time( 'sync :: [siteid=' . $pWebsite->id . ']' );
292 MainWP_Execution_Helper::execute_call_track( 'end_point', $pWebsite, array(), $stats_track_id, 'stats site' );
293 return $return;
294 } catch ( MainWP_Exception $e ) {
295 MainWP_Execution_Helper::execute_call_track( 'end_point', $pWebsite, array(), $stats_track_id, 'stats site' );
296 $sync_errors = '';
297
298 if ( $e->getMessage() === 'HTTPERROR' ) {
299 $sync_errors = esc_html__( 'HTTP error', 'mainwp' ) . ( ! empty( $e->get_message_extra() ) ? ' - ' . $e->get_message_extra() : '' );
300 } elseif ( $e->getMessage() === 'NOMAINWP' ) {
301 $sync_errors = MainWP_Error_Helper::get_error_not_detected_connect();
302 }
303
304 MainWP_Logger::instance()->log_execution_time( 'sync :: [siteid=' . $pWebsite->id . ']' );
305 return static::sync_information_array( $pWebsite, $information, $sync_errors, false, true, $pAllowDisconnect );
306 }
307 }
308
309 /**
310 * Method sync_information_array()
311 *
312 * Grab all Child Site Information.
313 *
314 * @param object $pWebsite The website object.
315 * @param array $information Array contaning information returned from child site.
316 * @param string $sync_errors Check for Sync Errors.
317 * @param int $check_result Check if offline.
318 * @param bool $error True|False.
319 * @param bool $pAllowDisconnect True|False.
320 * @param array $other Additional parameters.
321 * @param array $fetch_output Fetch output.
322 *
323 * @return bool true|false True on success, false on failure.
324 *
325 * @uses \MainWP\Dashboard\MainWP_DB::update_website_option()
326 * @uses \MainWP\Dashboard\MainWP_DB::update_website_sync_values()
327 * @uses \MainWP\Dashboard\MainWP_DB::update_website_values()
328 * @uses \MainWP\Dashboard\MainWP_Logger::warning_for_website()
329 * @uses \MainWP\Dashboard\MainWP_Monitoring_Handler::get_health_noticed_status_value()
330 * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
331 * @uses \MainWP\Dashboard\MainWP_Utility::get_site_health()
332 */
333 public static function sync_information_array( &$pWebsite, &$information, $sync_errors = '', $check_result = false, $error = false, $pAllowDisconnect = true, $other = array(), $fetch_output = array() ) { // phpcs:ignore -- NOSONAR -Current complexity is the only way to achieve desired results, pull request solutions appreciated.
334 $emptyArray = wp_json_encode( array() );
335 $websiteValues = array();
336 $websiteSyncValues = array(
337 'sync_errors' => $sync_errors,
338 'version' => 0,
339 );
340
341 $_error = $sync_errors;
342
343 $done = false;
344
345 $current_siteid = 0;
346 if ( is_string( $pWebsite ) || is_int( $pWebsite ) ) {
347 $current_siteid = intval( $pWebsite );
348 } elseif ( is_object( $pWebsite ) && ( ! property_exists( $pWebsite, 'plugin_updates' ) || ! property_exists( $pWebsite, 'theme_updates' ) ) ) {
349 $current_siteid = $pWebsite->id;
350 }
351
352 // to get full data.
353 if ( $current_siteid ) {
354 $pWebsite = MainWP_DB::instance()->get_website_by_id( $current_siteid );
355 }
356
357 /**
358 * Filter: mainwp_before_save_sync_result
359 *
360 * Filters data returned from child site before saving to the database.
361 *
362 * @param object $pWebsite Object containing child site data.
363 *
364 * @since 3.4
365 */
366 $information = apply_filters( 'mainwp_before_save_sync_result', $information, $pWebsite );
367
368 if ( ! empty( $information['regverify_info'] ) ) {
369 MainWP_DB::instance()->update_website_option( $pWebsite, 'register_verify_key', $information['regverify_info'] );
370 $done = true;
371 }
372
373 if ( isset( $information['siteurl'] ) ) {
374 $websiteValues['siteurl'] = $information['siteurl'];
375 $done = true;
376 }
377
378 if ( isset( $information['version'] ) ) {
379 $websiteSyncValues['version'] = $information['version'];
380 $done = true;
381 }
382
383 $phpversion = '';
384 $wpversion = '';
385 if ( isset( $information['site_info'] ) && ! empty( $information['site_info'] ) ) {
386 if ( is_array( $information['site_info'] ) && isset( $information['site_info']['phpversion'] ) ) {
387 $phpversion = $information['site_info']['phpversion'];
388 }
389 if ( is_array( $information['site_info'] ) && isset( $information['site_info']['ip'] ) ) {
390 $websiteValues['ip'] = sanitize_text_field( wp_unslash( $information['site_info']['ip'] ) );
391 }
392
393 if ( is_array( $information['site_info'] ) && isset( $information['site_info']['wpversion'] ) ) {
394 $wpversion = $information['site_info']['wpversion'];
395 }
396
397 MainWP_DB::instance()->update_website_option( $pWebsite, 'site_info', wp_json_encode( $information['site_info'] ) );
398 $done = true;
399 }
400
401 if ( ! empty( $phpversion ) ) {
402 MainWP_DB::instance()->update_website_option( $pWebsite, 'phpversion', $phpversion );
403 }
404 if ( ! empty( $wpversion ) ) { // to support sorting by wpversion.
405 $ver_num = MainWP_Utility::instance()->wp_versions_order_num( $wpversion );
406 MainWP_DB::instance()->update_website_option( $pWebsite, 'wpversion_order_num', $ver_num );
407 }
408
409 if ( isset( $information['directories'] ) && is_array( $information['directories'] ) ) {
410 $websiteValues['directories'] = wp_json_encode( $information['directories'] );
411 $done = true;
412 } elseif ( isset( $information['directories'] ) ) {
413 $websiteValues['directories'] = $information['directories'];
414 $done = true;
415 }
416
417 $had_pending_updates = null;
418
419 $wp_updates_empty = true;
420 if ( isset( $information['wp_updates'] ) && ! empty( $information['wp_updates'] ) ) {
421 MainWP_DB::instance()->update_website_option(
422 $pWebsite,
423 'wp_upgrades',
424 wp_json_encode(
425 array(
426 'current' => $information['wpversion'],
427 'new' => $information['wp_updates'],
428 )
429 )
430 );
431 $done = true;
432 $wp_updates_empty = false;
433 $had_pending_updates = true;
434 }
435
436 if ( isset( $information['plugin_updates'] ) ) {
437 $update_values = array();
438 if ( is_array( $information['plugin_updates'] ) ) {
439 foreach ( $information['plugin_updates'] as $file => $update ) {
440 $update_values[ $file ] = $update;
441 }
442 }
443
444 $had_pending_updates = ! empty( $update_values ) || (bool) $had_pending_updates;
445
446 $websiteValues['plugin_upgrades'] = wp_json_encode( $update_values );
447 $done = true;
448 }
449
450 if ( isset( $information['theme_updates'] ) ) {
451 $update_values = array();
452 if ( is_array( $information['theme_updates'] ) ) {
453 foreach ( $information['theme_updates'] as $file => $update ) {
454 $update_values[ $file ] = $update;
455 }
456 }
457 $had_pending_updates = ! empty( $update_values ) || (bool) $had_pending_updates;
458 $websiteValues['theme_upgrades'] = wp_json_encode( $update_values );
459 $done = true;
460 }
461
462 if ( isset( $information['translation_updates'] ) ) {
463 $had_pending_updates = ! empty( $information['translation_updates'] ) || (bool) $had_pending_updates;
464 $websiteValues['translation_upgrades'] = wp_json_encode( $information['translation_updates'] );
465 $done = true;
466 }
467
468 if ( isset( $information['premium_updates'] ) ) {
469 $had_pending_updates = ! empty( $information['premium_updates'] ) || (bool) $had_pending_updates;
470
471 MainWP_DB::instance()->update_website_option( $pWebsite, 'premium_upgrades', wp_json_encode( $information['premium_updates'] ) );
472 $done = true;
473 }
474
475 if ( isset( $information['securityStats'] ) ) {
476 $total_securityIssues = 0;
477 $securityStats = $information['securityStats'];
478 if ( is_array( $securityStats ) ) {
479 /** This filter is documented in ../pages/page-mainwp-security-issues.php */
480 $filterStats = apply_filters( 'mainwp_security_issues_stats', false, $securityStats, $pWebsite );
481 if ( false !== $filterStats && is_array( $filterStats ) ) {
482 $securityStats = array_merge( $securityStats, $filterStats );
483 }
484
485 $tmp_issues = array_filter(
486 $securityStats,
487 function ( $v ) {
488 return 'N' === $v;
489 },
490 ARRAY_FILTER_USE_BOTH
491 );
492 $total_securityIssues = count( $tmp_issues );
493 $securityStats = wp_json_encode( $securityStats );
494 } else {
495 $securityStats = $emptyArray;
496 }
497 $websiteValues['securityIssues'] = $total_securityIssues;
498 MainWP_DB::instance()->update_website_option( $pWebsite, 'security_stats', $securityStats );
499 $done = true;
500 } elseif ( isset( $information['securityIssues'] ) && MainWP_Utility::ctype_digit( $information['securityIssues'] ) && $information['securityIssues'] >= 0 ) {
501 $websiteValues['securityIssues'] = $information['securityIssues'];
502 $done = true;
503 }
504
505 if ( isset( $information['recent_comments'] ) ) {
506 MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_comments', wp_json_encode( $information['recent_comments'] ) );
507 $done = true;
508 }
509
510 if ( isset( $information['recent_posts'] ) ) {
511 MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_posts', wp_json_encode( $information['recent_posts'] ) );
512 $done = true;
513 }
514
515 if ( isset( $information['recent_pages'] ) ) {
516 MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_pages', wp_json_encode( $information['recent_pages'] ) );
517 $done = true;
518 }
519
520 if ( isset( $information['themes'] ) ) {
521 $websiteValues['themes'] = wp_json_encode( $information['themes'] );
522 $done = true;
523 }
524
525 $plugins_info = array();
526
527 if ( isset( $information['plugins'] ) ) {
528 $plugins_info = $information['plugins'];
529 $websiteValues['plugins'] = wp_json_encode( $plugins_info );
530 $done = true;
531 }
532
533 if ( isset( $information['users'] ) ) {
534 $websiteValues['users'] = wp_json_encode( $information['users'] );
535 $done = true;
536 }
537
538 if ( isset( $information['categories_list'] ) ) {
539 $websiteValues['categories'] = wp_json_encode( $information['categories_list'] );
540 $done = true;
541 } elseif ( isset( $information['categories'] ) ) { // support old child version.
542 $websiteValues['categories'] = wp_json_encode( $information['categories'] );
543 $done = true;
544 }
545
546 if ( isset( $information['totalsize'] ) ) {
547 $websiteSyncValues['totalsize'] = $information['totalsize'];
548 $done = true;
549 }
550
551 if ( isset( $information['dbsize'] ) ) {
552 $websiteSyncValues['dbsize'] = $information['dbsize'];
553 $done = true;
554 }
555
556 if ( isset( $information['dbsize_activitylogs'] ) ) {
557 MainWP_DB::instance()->update_website_option( $pWebsite, 'dbsize_activitylogs', $information['dbsize_activitylogs'] );
558 $done = true;
559 }
560
561 if ( isset( $information['extauth'] ) ) {
562 $websiteSyncValues['extauth'] = $information['extauth'];
563 $done = true;
564 }
565
566 if ( isset( $information['wpe'] ) ) {
567 $websiteValues['wpe'] = $information['wpe'];
568 $done = true;
569 }
570
571 if ( isset( $information['wphost'] ) ) {
572 MainWP_DB::instance()->update_website_option( $pWebsite, 'wphost', $information['wphost'] );
573 }
574
575 if ( isset( $information['last_post_gmt'] ) ) {
576 $websiteSyncValues['last_post_gmt'] = $information['last_post_gmt'];
577 $done = true;
578 }
579
580 if ( isset( $information['health_site_status'] ) ) {
581 $health_status = $information['health_site_status'];
582 $hstatus = MainWP_Utility::get_site_health( $health_status );
583 $custom_health_value = $hstatus['val'] - $hstatus['critical'] * 100; // computes custom health value to support sorting by sites health and sites health threshold.
584 $websiteSyncValues['health_value'] = $custom_health_value;
585 $done = true;
586 MainWP_DB::instance()->update_website_option( $pWebsite, 'health_site_status', wp_json_encode( $health_status ) );
587 $new_noticed = MainWP_Monitoring_Handler::get_health_noticed_status_value( $pWebsite, $custom_health_value );
588 if ( null !== $new_noticed ) {
589 MainWP_DB::instance()->update_website_sync_values(
590 $pWebsite->id,
591 array(
592 'health_site_noticed' => $new_noticed,
593 )
594 );
595 }
596
597 $hval = $hstatus['val'];
598 $critical = $hstatus['critical'];
599 $health_status = 0;
600 if ( 80 <= $hval && empty( $critical ) ) {
601 $health_status = 0; // Good.
602 } else {
603 $health_status = 1; // Should be improved'.
604 }
605 $websiteSyncValues['health_status'] = $health_status;
606 }
607
608 if ( isset( $information['mainwpdir'] ) ) {
609 $websiteValues['mainwpdir'] = $information['mainwpdir'];
610 $done = true;
611 }
612
613 if ( isset( $information['uniqueId'] ) ) {
614 $websiteValues['uniqueId'] = $information['uniqueId'];
615 $done = true;
616 }
617
618 if ( isset( $information['clone_adminname'] ) ) {
619 $websiteValues['adminname'] = $information['clone_adminname'];
620 $done = true;
621 }
622
623 if ( isset( $information['admin_nicename'] ) ) {
624 MainWP_DB::instance()->update_website_option( $pWebsite, 'admin_nicename', trim( $information['admin_nicename'] ) );
625 $done = true;
626 }
627
628 if ( isset( $information['admin_useremail'] ) ) {
629 MainWP_DB::instance()->update_website_option( $pWebsite, 'admin_useremail', trim( $information['admin_useremail'] ) );
630 $done = true;
631 }
632
633 if ( isset( $information['plugins_outdate_info'] ) ) {
634 MainWP_DB::instance()->update_website_option( $pWebsite, 'plugins_outdate_info', wp_json_encode( $information['plugins_outdate_info'] ) );
635 $done = true;
636 }
637
638 if ( isset( $information['themes_outdate_info'] ) ) {
639 MainWP_DB::instance()->update_website_option( $pWebsite, 'themes_outdate_info', wp_json_encode( $information['themes_outdate_info'] ) );
640 $done = true;
641 }
642
643 if ( isset( $information['password_policy_options'] ) ) {
644 MainWP_DB::instance()->update_website_option( $pWebsite, 'password_policy_options', wp_json_encode( $information['password_policy_options'] ) );
645 $done = true;
646 }
647
648 if ( isset( $information['primaryLasttimeBackup'] ) ) {
649 MainWP_DB::instance()->update_website_option( $pWebsite, 'primary_lasttime_backup', $information['primaryLasttimeBackup'] );
650 $done = true;
651 }
652
653 if ( isset( $information['child_site_actions_data'] ) ) {
654 if ( is_array( $information['child_site_actions_data'] ) && isset( $information['child_site_actions_data']['connected_admin'] ) ) {
655 unset( $information['child_site_actions_data']['connected_admin'] );
656 }
657 if ( class_exists( '\MainWP\Dashboard\Module\Log\Log_Manager' ) ) {
658 \MainWP\Dashboard\Module\Log\Log_Manager::instance()->sync_log_site_actions( $pWebsite->id, $information['child_site_actions_data'], $pWebsite );
659 }
660 $done = true;
661 }
662
663 if ( ! empty( $information['changes_logs_data'] ) && class_exists( '\MainWP\Dashboard\Module\Log\Log_Changes_Logs_Helper' ) ) {
664 \MainWP\Dashboard\Module\Log\Log_Changes_Logs_Helper::instance()->sync_changes_logs( $pWebsite->id, $information['changes_logs_data'], $pWebsite );
665 $done = true;
666 }
667
668 if ( ! $done ) {
669 if ( isset( $information['wpversion'] ) ) {
670 $done = true;
671 } elseif ( isset( $information['error'] ) ) {
672 MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[' . esc_html( $information['error'] ) . ']' );
673 $error = true;
674 $done = true;
675 $_error = esc_html__( 'ERROR: ', 'mainwp' ) . esc_html( $information['error'] );
676 $websiteSyncValues['sync_errors'] = $_error;
677 } elseif ( ! empty( $sync_errors ) ) {
678 MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[' . $sync_errors . ']' );
679 $_error = $sync_errors;
680 $error = true;
681 if ( ! $pAllowDisconnect ) {
682 $sync_errors = '';
683 }
684
685 $websiteSyncValues['sync_errors'] = $sync_errors;
686 } else {
687 MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[Undefined error]' );
688 $error = true;
689 if ( $pAllowDisconnect ) {
690 $sync_errors = esc_html__( 'Undefined error! Please, reinstall the MainWP Child plugin on the child site.', 'mainwp' );
691 $websiteSyncValues['sync_errors'] = $sync_errors;
692 $_error = $sync_errors;
693 }
694 }
695 }
696
697 $sync_success = false;
698 if ( $done ) {
699 $sync_success = true;
700 $websiteSyncValues['dtsSync'] = time();
701 if ( $wp_updates_empty ) {
702 MainWP_DB::instance()->update_website_option(
703 $pWebsite,
704 'wp_upgrades',
705 $emptyArray
706 );
707 }
708 }
709 MainWP_DB::instance()->update_website_sync_values( $pWebsite->id, $websiteSyncValues );
710 MainWP_Logger::instance()->log_events( 'db-queries', sprintf( '[Update sync values=%s]', MainWP_DB::instance()->get_last_query() ) );
711
712 if ( ! empty( $websiteValues ) ) {
713 MainWP_DB::instance()->update_website_values( $pWebsite->id, $websiteValues );
714 MainWP_Logger::instance()->log_events( 'db-queries', sprintf( '[Update site sync data=%s]', MainWP_DB::instance()->get_last_query() ) );
715 }
716
717 $error_occurred = $error;
718 $msg_errors = $_error;
719
720 $error = apply_filters( 'mainwp_sync_site_after_sync_result', $error, $pWebsite, $information );
721
722 if ( ! empty( $plugins_info ) && is_array( $plugins_info ) ) {
723 foreach ( $plugins_info as $info ) {
724 if ( ! empty( $info['icon'] ) ) {
725 $icon_slug = MainWP_Utility::get_dir_slug( $info['slug'] );
726 MainWP_System_Utility::save_cached_icons( $info['icon'], $icon_slug, 'plugin' );
727 }
728 }
729 }
730
731 // Sync action.
732 if ( ! $error ) {
733
734 do_action_deprecated( 'mainwp-site-synced', array( $pWebsite, $information ), '4.0.7.2', 'mainwp_site_synced' ); // @deprecated Use 'mainwp_site_synced' instead. NOSONAR - not IP.
735
736 /**
737 * Action: mainwp_site_synced
738 *
739 * Fires upon successful site synchronization.
740 *
741 * @param object $pWebsite Object containing child site info.
742 * @param array $information Array containing information returned from child site.
743 *
744 * @since 3.4
745 */
746 do_action( 'mainwp_site_synced', $pWebsite, $information );
747 }
748
749 $telem_info = static::get_telem_sync_info( $sync_success );
750
751 if ( isset( $information['version'] ) ) {
752 $telem_info['child_plugin_version'] = $information['version'];
753 }
754
755 if ( isset( $had_pending_updates ) ) {
756 $telem_info['site_had_pending_updates'] = $had_pending_updates ? true : false;
757 }
758
759 if ( $error_occurred && ! empty( $information['fetch_url_output'] ) && is_array( $information['fetch_url_output'] ) ) {
760 $output = $information['fetch_url_output'];
761 $telem_info['error_message'] = $msg_errors;
762 $telem_info['error_category'] = ! empty( $output['error_category'] ) ? $output['error_category'] : 'unknown';
763 $telem_info['error_code'] = ! empty( $output['error_code'] ) ? $output['error_code'] : 'undefined_error';
764 $telem_info['connection_step'] = ! empty( $output['connection_step'] ) ? $output['connection_step'] : 'handshake';
765 if ( ! empty( $output['http_status'] ) ) {
766 $telem_info['http_status'] = $output['http_status'];
767 }
768 }
769
770 /**
771 * Action: mainwp_after_site_synced
772 *
773 * Fires upon site synchronization.
774 *
775 * @param object $pWebsite Object containing child site info.
776 * @param array $information Array containing information returned from child site.
777 * @param mixed $error Sync error result.
778 * @param mixed $sync_errors Sync error message if existed.
779 * @param array $other Additional parameters.
780 * @param array $telem_info Telemetry information.
781 *
782 * @since 6.0
783 */
784 do_action( 'mainwp_after_site_synced', $pWebsite, $information, $error, $sync_errors, $other, $telem_info );
785
786 $post_data = array();
787
788 /**
789 * Action: mainwp_site_sync
790 *
791 * Fires upon successful site synchronization.
792 *
793 * @param object $pWebsite Object containing child site info.
794 * @param array $information Array containing information returned from child site.
795 * @param bool $sync_success action success or failed.
796 * @param string $_error Sync error message if existed.
797 * @param array $post_data Addition post data.
798 *
799 * @since 3.4
800 */
801 do_action( 'mainwp_site_sync', $pWebsite, $information, $sync_success, $_error, $post_data );
802
803 return ! $error;
804 }
805
806
807 /**
808 * Method get_telem_sync_info.
809 *
810 * @param mixed $sync_done
811 * @return void
812 */
813 public static function get_telem_sync_info( $sync_done ) {
814
815 $is_bulk_sync = ! empty( $_POST['bulkSync'] ) ? true : false; // phpcs:ignore -- NOSONAR - superglobal usage is acceptable.
816
817 $tp = 'post_add_site';
818
819 if ( $is_bulk_sync ) {
820 $tp = 'manual_bulk';
821 } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
822 $tp = 'auto_cron';
823 } elseif ( isset( $_POST['bulkSync'] ) && ! $is_bulk_sync ) { //phpcs:ignore -- NOSONAR - superglobal usage is acceptable.
824 $tp = 'manual_single';
825 }
826
827 $trigger = 'system';
828 if ( 'manual_single' === $tp || 'manual_bulk' === $tp ) {
829 $trigger = 'user_click';
830 } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
831 $trigger = 'cron';
832 }
833
834 $curr_stack = static::get_current_stack_action();
835 $prev_conn_status = in_array( $curr_stack, array( 'sync_before_reconnect', 'sync_reconnect' ) ) ? 'disconnected' : 'connected';
836 $new_conn_status = $sync_done ? 'disconnected' : 'connected';
837
838 return array(
839 'sync_type' => $tp,
840 'trigger' => $trigger,
841 'previous_connection_status' => $prev_conn_status,
842 'new_connection_status' => $new_conn_status,
843 'connection_status_changed' => $prev_conn_status === $new_conn_status ? false : true,
844 'sync_duration_ms' => MainWP_Execution_Helper::get_run_time( true ),
845 );
846 }
847
848 /**
849 * Method init empty sync values.
850 *
851 * @param object $pWebsite Object containing child site info.
852 *
853 * @return void
854 */
855 public static function sync_init_empty_values( $pWebsite ) {
856
857 $emptyArray = wp_json_encode( array() );
858
859 $opts = array(
860 'site_info',
861 'wp_upgrades',
862 'premium_upgrades',
863 'recent_comments',
864 'recent_posts',
865 'recent_pages',
866 'health_site_status',
867 'plugins_outdate_info',
868 'themes_outdate_info',
869 'directories',
870 'plugin_upgrades',
871 'theme_upgrades',
872 'translation_upgrades',
873 'securityIssues',
874 'themes',
875 'plugins',
876 'users',
877 'categories',
878 'password_policy_options',
879 );
880
881 foreach ( $opts as $opt ) {
882 MainWP_DB::instance()->update_website_option( $pWebsite, $opt, $emptyArray );
883 }
884 }
885
886
887 /**
888 * Method get_wp_icon()
889 *
890 * Get site's icon.
891 *
892 * @param mixed $siteId site's id.
893 *
894 * @return array result error or success
895 * @throws \MainWP_Exception Error message.
896 *
897 * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
898 * @uses \MainWP\Dashboard\MainWP_Connect::get_file_content()
899 * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
900 * @uses \MainWP\Dashboard\MainWP_DB_Common::update_website_option()
901 * @uses \MainWP\Dashboard\MainWP_Exception
902 * @uses \MainWP\Dashboard\MainWP_Logger::debug()
903 * @uses \MainWP\Dashboard\MainWP_System_Utility::can_edit_website()
904 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
905 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
906 * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
907 */
908 public static function get_wp_icon( $siteId = null ) { // phpcs:ignore -- NOSONAR - complex.
909 if ( MainWP_Utility::ctype_digit( $siteId ) ) {
910 $website = MainWP_DB::instance()->get_website_by_id( $siteId );
911 if ( MainWP_System_Utility::can_edit_website( $website ) ) {
912 $error = '';
913 try {
914 $information = MainWP_Connect::fetch_url_authed( $website, 'get_site_icon' );
915 } catch ( MainWP_Exception $e ) {
916 $error = $e->getMessage();
917 }
918
919 if ( ! empty( $error ) ) {
920 return array( 'error' => $error );
921 } elseif ( isset( $information['faviIconUrl'] ) && ! empty( $information['faviIconUrl'] ) ) {
922 MainWP_Logger::instance()->debug( 'Downloading icon :: ' . esc_html( $information['faviIconUrl'] ) );
923 $content = MainWP_Connect::get_file_content( $information['faviIconUrl'] );
924 if ( ! empty( $content ) ) {
925
926 MainWP_System_Utility::get_wp_file_system();
927
928 /**
929 * WordPress files system object.
930 *
931 * @global object
932 */
933 global $wp_filesystem;
934
935 $dirs = MainWP_System_Utility::get_mainwp_dir( 'icons', true );
936 $iconsDir = $dirs[0];
937 $filename = basename( $information['faviIconUrl'] );
938 $filename = strtok( $filename, '?' );
939 if ( $filename ) {
940 $filename = 'favi-' . $siteId . '-' . $filename;
941 $size = false;
942 if ( MainWP_Utility::check_image_file_name( $filename ) ) {
943 $size = $wp_filesystem->put_contents( $iconsDir . $filename, $content ); // phpcs:ignore --
944 }
945 if ( $size ) {
946 MainWP_Logger::instance()->debug( 'Icon size :: ' . $size );
947 MainWP_DB::instance()->update_website_option( $website, 'favi_icon', $filename );
948 return array( 'result' => 'success' );
949 } else {
950 return array( 'error' => 'Save icon file failed.' );
951 }
952 }
953 return array( 'undefined_error' => true );
954 } else {
955 return array( 'error' => esc_html__( 'Download icon file failed', 'mainwp' ) );
956 }
957 } else {
958 return array( 'undefined_error' => true );
959 }
960 }
961 }
962 return array( 'result' => 'NOSITE' );
963 }
964 }
965