PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / trunk
MainWP Dashboard: Self-hosted WordPress Management for Agencies vtrunk
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 trunk, at class/class-mainwp-sync.php

991 lines 43.1 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['premium_updates_results'] ) && is_array( $information['premium_updates_results'] ) ) {
649 foreach ( array( 'plugin', 'theme' ) as $type ) {
650 if ( isset( $information['premium_updates_results'][ $type ] ) ) {
651 $update_results = $information['premium_updates_results'][ $type ];
652 if ( is_array( $update_results ) ) {
653 foreach ( $update_results as $info ) {
654 if ( is_array( $info ) && isset( $info['other_data'] ) ) {
655 $output_array = $info['other_data'];
656 mainwp_get_actions_handler_instance()->do_action_mainwp_install_actions( $pWebsite, 'updated', $output_array, $type );
657 }
658 }
659 }
660 }
661 }
662 }
663
664 if ( isset( $information['primaryLasttimeBackup'] ) ) {
665 MainWP_DB::instance()->update_website_option( $pWebsite, 'primary_lasttime_backup', $information['primaryLasttimeBackup'] );
666 $done = true;
667 }
668
669 if ( isset( $information['child_site_actions_data'] ) ) {
670 if ( is_array( $information['child_site_actions_data'] ) && isset( $information['child_site_actions_data']['connected_admin'] ) ) {
671 unset( $information['child_site_actions_data']['connected_admin'] );
672 }
673 if ( class_exists( '\MainWP\Dashboard\Module\Log\Log_Manager' ) ) {
674 \MainWP\Dashboard\Module\Log\Log_Manager::instance()->sync_log_site_actions( $pWebsite->id, $information['child_site_actions_data'], $pWebsite );
675 }
676 $done = true;
677 }
678
679 if ( ! empty( $information['changes_logs_data'] ) && class_exists( '\MainWP\Dashboard\Module\Log\Log_Changes_Logs_Helper' ) ) {
680 \MainWP\Dashboard\Module\Log\Log_Changes_Logs_Helper::instance()->sync_changes_logs( $pWebsite->id, $information['changes_logs_data'], $pWebsite );
681 $done = true;
682 }
683
684 $monitor_data = array();
685 if ( isset( $information['child_monitor_data'] ) && is_array( $information['child_monitor_data'] ) ) {
686 $monitor_data = $information['child_monitor_data'];
687 $done = true;
688 }
689
690 if ( $done ) {
691 MainWP_DB::instance()->update_website_option( $pWebsite, 'child_monitor_data', wp_json_encode( $monitor_data ) );
692 }
693
694 if ( ! $done ) {
695 if ( isset( $information['wpversion'] ) ) {
696 $done = true;
697 } elseif ( isset( $information['error'] ) ) {
698 MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[' . esc_html( $information['error'] ) . ']' );
699 $error = true;
700 $done = true;
701 $_error = esc_html__( 'ERROR: ', 'mainwp' ) . esc_html( $information['error'] );
702 $websiteSyncValues['sync_errors'] = $_error;
703 } elseif ( ! empty( $sync_errors ) ) {
704 MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[' . $sync_errors . ']' );
705 $_error = $sync_errors;
706 $error = true;
707 if ( ! $pAllowDisconnect ) {
708 $sync_errors = '';
709 }
710
711 $websiteSyncValues['sync_errors'] = $sync_errors;
712 } else {
713 MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[Undefined error]' );
714 $error = true;
715 if ( $pAllowDisconnect ) {
716 $sync_errors = esc_html__( 'Undefined error! Please, reinstall the MainWP Child plugin on the child site.', 'mainwp' );
717 $websiteSyncValues['sync_errors'] = $sync_errors;
718 $_error = $sync_errors;
719 }
720 }
721 }
722
723 $sync_success = false;
724 if ( $done ) {
725 $sync_success = true;
726 $websiteSyncValues['dtsSync'] = time();
727 if ( $wp_updates_empty ) {
728 MainWP_DB::instance()->update_website_option(
729 $pWebsite,
730 'wp_upgrades',
731 $emptyArray
732 );
733 }
734 }
735 MainWP_DB::instance()->update_website_sync_values( $pWebsite->id, $websiteSyncValues );
736 MainWP_Logger::instance()->log_events( 'db-queries', sprintf( '[Update sync values=%s]', MainWP_DB::instance()->get_last_query() ) );
737
738 if ( ! empty( $websiteValues ) ) {
739 MainWP_DB::instance()->update_website_values( $pWebsite->id, $websiteValues );
740 MainWP_Logger::instance()->log_events( 'db-queries', sprintf( '[Update site sync data=%s]', MainWP_DB::instance()->get_last_query() ) );
741 }
742
743 $error_occurred = $error;
744 $msg_errors = $_error;
745
746 $error = apply_filters( 'mainwp_sync_site_after_sync_result', $error, $pWebsite, $information );
747
748 if ( ! empty( $plugins_info ) && is_array( $plugins_info ) ) {
749 foreach ( $plugins_info as $info ) {
750 if ( ! empty( $info['icon'] ) ) {
751 $icon_slug = MainWP_Utility::get_dir_slug( $info['slug'] );
752 MainWP_System_Utility::save_cached_icons( $info['icon'], $icon_slug, 'plugin' );
753 }
754 }
755 }
756
757 // Sync action.
758 if ( ! $error ) {
759
760 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.
761
762 /**
763 * Action: mainwp_site_synced
764 *
765 * Fires upon successful site synchronization.
766 *
767 * @param object $pWebsite Object containing child site info.
768 * @param array $information Array containing information returned from child site.
769 *
770 * @since 3.4
771 */
772 do_action( 'mainwp_site_synced', $pWebsite, $information );
773 }
774
775 $telem_info = static::get_telem_sync_info( $sync_success );
776
777 if ( isset( $information['version'] ) ) {
778 $telem_info['child_plugin_version'] = $information['version'];
779 }
780
781 if ( isset( $had_pending_updates ) ) {
782 $telem_info['site_had_pending_updates'] = $had_pending_updates ? true : false;
783 }
784
785 if ( $error_occurred && ! empty( $information['fetch_url_output'] ) && is_array( $information['fetch_url_output'] ) ) {
786 $output = $information['fetch_url_output'];
787 $telem_info['error_message'] = $msg_errors;
788 $telem_info['error_category'] = ! empty( $output['error_category'] ) ? $output['error_category'] : 'unknown';
789 $telem_info['error_code'] = ! empty( $output['error_code'] ) ? $output['error_code'] : 'undefined_error';
790 $telem_info['connection_step'] = ! empty( $output['connection_step'] ) ? $output['connection_step'] : 'handshake';
791 if ( ! empty( $output['http_status'] ) ) {
792 $telem_info['http_status'] = $output['http_status'];
793 }
794 }
795
796 /**
797 * Action: mainwp_after_site_synced
798 *
799 * Fires upon site synchronization.
800 *
801 * @param object $pWebsite Object containing child site info.
802 * @param array $information Array containing information returned from child site.
803 * @param mixed $error Sync error result.
804 * @param mixed $sync_errors Sync error message if existed.
805 * @param array $other Additional parameters.
806 * @param array $telem_info Telemetry information.
807 *
808 * @since 6.0
809 */
810 do_action( 'mainwp_after_site_synced', $pWebsite, $information, $error, $sync_errors, $other, $telem_info );
811
812 $post_data = array();
813
814 /**
815 * Action: mainwp_site_sync
816 *
817 * Fires upon successful site synchronization.
818 *
819 * @param object $pWebsite Object containing child site info.
820 * @param array $information Array containing information returned from child site.
821 * @param bool $sync_success action success or failed.
822 * @param string $_error Sync error message if existed.
823 * @param array $post_data Addition post data.
824 *
825 * @since 3.4
826 */
827 do_action( 'mainwp_site_sync', $pWebsite, $information, $sync_success, $_error, $post_data );
828
829 return ! $error;
830 }
831
832
833 /**
834 * Method get_telem_sync_info.
835 *
836 * @param mixed $sync_done
837 * @return void
838 */
839 public static function get_telem_sync_info( $sync_done ) {
840
841 $is_bulk_sync = ! empty( $_POST['bulkSync'] ) ? true : false; // phpcs:ignore -- NOSONAR - superglobal usage is acceptable.
842
843 $tp = 'post_add_site';
844
845 if ( $is_bulk_sync ) {
846 $tp = 'manual_bulk';
847 } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
848 $tp = 'auto_cron';
849 } elseif ( isset( $_POST['bulkSync'] ) && ! $is_bulk_sync ) { //phpcs:ignore -- NOSONAR - superglobal usage is acceptable.
850 $tp = 'manual_single';
851 }
852
853 $trigger = 'system';
854 if ( 'manual_single' === $tp || 'manual_bulk' === $tp ) {
855 $trigger = 'user_click';
856 } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
857 $trigger = 'cron';
858 }
859
860 $curr_stack = static::get_current_stack_action();
861 $prev_conn_status = in_array( $curr_stack, array( 'sync_before_reconnect', 'sync_reconnect' ) ) ? 'disconnected' : 'connected';
862 $new_conn_status = $sync_done ? 'disconnected' : 'connected';
863
864 return array(
865 'sync_type' => $tp,
866 'trigger' => $trigger,
867 'previous_connection_status' => $prev_conn_status,
868 'new_connection_status' => $new_conn_status,
869 'connection_status_changed' => $prev_conn_status === $new_conn_status ? false : true,
870 'sync_duration_ms' => MainWP_Execution_Helper::get_run_time( true ),
871 );
872 }
873
874 /**
875 * Method init empty sync values.
876 *
877 * @param object $pWebsite Object containing child site info.
878 *
879 * @return void
880 */
881 public static function sync_init_empty_values( $pWebsite ) {
882
883 $emptyArray = wp_json_encode( array() );
884
885 $opts = array(
886 'site_info',
887 'wp_upgrades',
888 'premium_upgrades',
889 'recent_comments',
890 'recent_posts',
891 'recent_pages',
892 'health_site_status',
893 'plugins_outdate_info',
894 'themes_outdate_info',
895 'directories',
896 'plugin_upgrades',
897 'theme_upgrades',
898 'translation_upgrades',
899 'securityIssues',
900 'themes',
901 'plugins',
902 'users',
903 'categories',
904 'password_policy_options',
905 );
906
907 foreach ( $opts as $opt ) {
908 MainWP_DB::instance()->update_website_option( $pWebsite, $opt, $emptyArray );
909 }
910 }
911
912
913 /**
914 * Method get_wp_icon()
915 *
916 * Get site's icon.
917 *
918 * @param mixed $siteId site's id.
919 *
920 * @return array result error or success
921 * @throws \MainWP_Exception Error message.
922 *
923 * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
924 * @uses \MainWP\Dashboard\MainWP_Connect::get_file_content()
925 * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
926 * @uses \MainWP\Dashboard\MainWP_DB_Common::update_website_option()
927 * @uses \MainWP\Dashboard\MainWP_Exception
928 * @uses \MainWP\Dashboard\MainWP_Logger::debug()
929 * @uses \MainWP\Dashboard\MainWP_System_Utility::can_edit_website()
930 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
931 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
932 * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
933 */
934 public static function get_wp_icon( $siteId = null ) { // phpcs:ignore -- NOSONAR - complex.
935 if ( MainWP_Utility::ctype_digit( $siteId ) ) {
936 $website = MainWP_DB::instance()->get_website_by_id( $siteId );
937 if ( MainWP_System_Utility::can_edit_website( $website ) ) {
938 $error = '';
939 try {
940 $information = MainWP_Connect::fetch_url_authed( $website, 'get_site_icon' );
941 } catch ( MainWP_Exception $e ) {
942 $error = $e->getMessage();
943 }
944
945 if ( ! empty( $error ) ) {
946 return array( 'error' => $error );
947 } elseif ( isset( $information['faviIconUrl'] ) && ! empty( $information['faviIconUrl'] ) ) {
948 MainWP_Logger::instance()->debug( 'Downloading icon :: ' . esc_html( $information['faviIconUrl'] ) );
949 $content = MainWP_Connect::get_file_content( $information['faviIconUrl'] );
950 if ( ! empty( $content ) ) {
951
952 MainWP_System_Utility::get_wp_file_system();
953
954 /**
955 * WordPress files system object.
956 *
957 * @global object
958 */
959 global $wp_filesystem;
960
961 $dirs = MainWP_System_Utility::get_mainwp_dir( 'icons', true );
962 $iconsDir = $dirs[0];
963 $filename = basename( $information['faviIconUrl'] );
964 $filename = strtok( $filename, '?' );
965 if ( $filename ) {
966 $filename = 'favi-' . $siteId . '-' . $filename;
967 $size = false;
968 if ( MainWP_Utility::check_image_file_name( $filename ) ) {
969 $size = $wp_filesystem->put_contents( $iconsDir . $filename, $content ); // phpcs:ignore --
970 }
971 if ( $size ) {
972 MainWP_Logger::instance()->debug( 'Icon size :: ' . $size );
973 MainWP_DB::instance()->update_website_option( $website, 'favi_icon', $filename );
974 return array( 'result' => 'success' );
975 } else {
976 return array( 'error' => 'Save icon file failed.' );
977 }
978 }
979 return array( 'undefined_error' => true );
980 } else {
981 return array( 'error' => esc_html__( 'Download icon file failed', 'mainwp' ) );
982 }
983 } else {
984 return array( 'undefined_error' => true );
985 }
986 }
987 }
988 return array( 'result' => 'NOSITE' );
989 }
990 }
991