PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.1
6.2.2 6.2.1 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 All 155 releases
← All changes | class/class-mainwp-sync.php +930 -581 5.0.2 → 6.2.1 View file →
@@ -8,664 +8,1013 @@
8 8 */
9 9
10 10 namespace MainWP\Dashboard;
11 11
12 +// Exit if accessed directly.
13 +if ( ! defined( 'ABSPATH' ) ) {
14 + exit;
15 +}
16 +
12 17 /**
13 18 * Class MainWP_Sync
14 19 *
15 20 * @package MainWP\Dashboard
16 21 */
17 -class MainWP_Sync {
22 +class MainWP_Sync { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
18 23
24 + /**
25 + * Clone websites setting.
26 + *
27 + * @var mixed Clone websites.
28 + */
29 + public static $clone_websites = null;
19 30
20 - /**
21 - * Method sync_website()
22 - *
23 - * Sync Child Site.
24 - *
25 - * @param object $website object.
26 - * @param bool $clear_session to run the ending session or not.
27 - *
28 - * @return bool sync result.
29 - */
30 - public static function sync_website( $website, $clear_session = true ) {
31 - if ( ! is_object( $website ) ) {
32 - return false;
33 - }
34 - MainWP_DB::instance()->update_website_sync_values( $website->id, array( 'dtsSyncStart' => time() ) );
35 - return self::sync_site( $website, false, true, $clear_session );
36 - }
31 + /**
32 + * Clone enabled setting.
33 + *
34 + * @var mixed Clone enabled.
35 + */
36 + public static $clone_enabled = null;
37 37
38 - /**
39 - * Method sync_site()
40 - *
41 - * @param mixed $pWebsite Null|userid.
42 - * @param bool $pForceFetch Check if a fourced Sync.
43 - * @param bool $pAllowDisconnect Check if allowed to disconect.
44 - * @param bool $clear_session to run the ending session or not.
45 - *
46 - * @return bool sync_information_array
47 - *
48 - * @uses \MainWP\Dashboard\MainWP_DB_Common::get_user_extension_by_user_id()
49 - * @uses \MainWP\Dashboard\MainWP_DB::query()
50 - * @uses \MainWP\Dashboard\MainWP_DB::update_website_option()
51 - * @uses \MainWP\Dashboard\MainWP_DB::fetch_object()
52 - * @uses \MainWP\Dashboard\MainWP_DB::free_result()
53 - * @uses \MainWP\Dashboard\MainWP_Exception
54 - * @uses \MainWP\Dashboard\MainWP_System_Utility::get_primary_backup()
55 - * @uses \MainWP\Dashboard\MainWP_Utility::end_session()
56 - */
57 - public static function sync_site( &$pWebsite = null, $pForceFetch = false, $pAllowDisconnect = true, $clear_session = true ) { // phpcs:ignore -- complexity method.
58 38
59 - // to support demo data.
60 - if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $pWebsite ) ) {
61 - return MainWP_Demo_Handle::get_instance()->handle_action_demo( $pWebsite, 'sync_site' );
62 - }
39 + /**
40 + * Disallowed Clone sites setting.
41 + *
42 + * @var mixed Disallowed clone.
43 + */
44 + public static $disallowed_clone_sites = null;
63 45
64 - if ( null === $pWebsite ) {
65 - return false;
66 - }
67 - $userExtension = MainWP_DB_Common::instance()->get_user_extension_by_user_id( $pWebsite->userid );
68 - if ( null === $userExtension ) {
69 - return false;
70 - }
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 + }
71 57
72 - if ( $clear_session ) {
73 - MainWP_Utility::end_session();
74 - }
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 + }
75 69
76 - try {
77 70
78 - /**
79 - * Filter: mainwp_clone_enabled
80 - *
81 - * Filters whether the Clone feature is enabled or disabled.
82 - *
83 - * @since Unknown
84 - */
85 - $cloneEnabled = apply_filters( 'mainwp_clone_enabled', false );
86 - $cloneSites = array();
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 + }
87 88
88 - $disallowed_current_site = false;
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.
89 109
90 - if ( $cloneEnabled ) {
91 - $disallowedCloneSites = get_option( 'mainwp_clone_disallowedsites' );
92 - if ( false === $disallowedCloneSites ) {
93 - $disallowedCloneSites = array();
94 - }
95 - $websites = MainWP_DB::instance()->query( MainWP_DB::instance()->get_sql_websites_for_current_user() );
96 - if ( $websites ) {
97 - while ( $websites && ( $website = MainWP_DB::fetch_object( $websites ) ) ) {
98 - if ( in_array( $website->id, $disallowedCloneSites ) ) {
99 - continue;
100 - }
101 - if ( (int) $website->id === (int) $pWebsite->id ) {
102 - continue;
103 - }
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 + }
104 114
105 - $cloneSites[ $website->id ] = array(
106 - 'name' => $website->name,
107 - 'url' => $website->url,
108 - 'extauth' => $website->extauth,
109 - 'size' => $website->totalsize,
110 - 'connect_admin' => $website->adminname,
111 - );
112 - }
113 - MainWP_DB::free_result( $websites );
114 - }
115 - $disallowed_current_site = in_array( $pWebsite->id, $disallowedCloneSites ) ? true : false;
116 - }
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 + }
117 122
118 - $primaryBackup = MainWP_System_Utility::get_primary_backup();
123 + if ( $clear_session ) {
124 + MainWP_Utility::end_session();
125 + }
119 126
120 - $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.
127 + $cur_id = MainWP_System_Utility::get_current_wpid();
128 + if ( empty( $cur_id ) ) {
129 + MainWP_System_Utility::set_current_wpid( $pWebsite->id );
130 + }
121 131
122 - /**
123 - * Filter: mainwp_sync_others_data
124 - *
125 - * Filters additional data in the sync request. Allows extensions or 3rd party plugins to hook data to the sync request.
126 - *
127 - * @param object $pWebsite Object contaning child site data.
128 - *
129 - * @since Unknown
130 - *
131 - * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
132 - */
133 - $othersData = apply_filters( 'mainwp_sync_others_data', $othersData, $pWebsite );
132 + MainWP_Logger::instance()->log_execution_sync( 'init', '', $pWebsite );
133 + $stats_track_id = MainWP_Execution_Helper::execute_call_track( 'start_point', $pWebsite );
134 134
135 - $saved_days_number = apply_filters( 'mainwp_site_actions_saved_days_number', 30 );
135 + try {
136 136
137 - $postdata = array(
138 - 'optimize' => 1 === (int) get_option( 'mainwp_optimize', 1 ) ? 1 : 0,
139 - 'cloneSites' => ( ! $cloneEnabled || $disallowed_current_site ? 0 : rawurlencode( wp_json_encode( $cloneSites ) ) ),
140 - 'othersData' => wp_json_encode( $othersData ),
141 - 'server' => get_admin_url(),
142 - 'numberdaysOutdatePluginTheme' => get_option( 'mainwp_numberdays_Outdate_Plugin_Theme', 365 ),
143 - 'primaryBackup' => $primaryBackup,
144 - 'siteId' => $pWebsite->id,
145 - 'child_actions_saved_days_number' => intval( $saved_days_number ),
146 - 'pingnonce' => MainWP_Utility::instance()->create_site_nonce( 'pingnonce', $pWebsite->id ),
147 - );
137 + if ( null === static::$clone_enabled ) {
148 138
149 - $information = MainWP_Connect::fetch_url_authed(
150 - $pWebsite,
151 - 'stats',
152 - $postdata,
153 - true,
154 - $pForceFetch
155 - );
156 - $return = self::sync_information_array( $pWebsite, $information, '', 1, false, $pAllowDisconnect );
157 - MainWP_Logger::instance()->log_execution_time( 'sync :: [siteid=' . $pWebsite->id . ']' );
158 - return $return;
159 - } catch ( MainWP_Exception $e ) {
160 - $sync_errors = '';
161 - $check_result = 1;
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();
162 148
163 - if ( $e->getMessage() === 'HTTPERROR' ) {
164 - $sync_errors = esc_html__( 'HTTP error', 'mainwp' ) . ( ! empty( $e->get_message_extra() ) ? ' - ' . $e->get_message_extra() : '' );
165 - $check_result = - 1;
166 - } elseif ( $e->getMessage() === 'NOMAINWP' ) {
167 - $sync_errors = sprintf( esc_html__( 'MainWP Child plugin not detected or could not be reached! Ensure the MainWP Child plugin is installed and activated on the child site, and there are no security rules blocking requests. If you continue experiencing this issue, check the %1$sMainWP Community%2$s for help.', 'mainwp' ), '<a href="https://managers.mainwp.com/c/community-support/5" target="_blank">', '</a> <i class="external alternate icon"></i>' );
168 - $check_result = 1;
169 - }
149 + if ( static::$clone_enabled ) {
170 150
171 - MainWP_Logger::instance()->log_execution_time( 'sync :: [siteid=' . $pWebsite->id . ']' );
172 - return self::sync_information_array( $pWebsite, $information, $sync_errors, $check_result, true, $pAllowDisconnect );
173 - }
174 - }
151 + static::$disallowed_clone_sites = get_option( 'mainwp_clone_disallowedsites' );
175 152
176 - /**
177 - * Method sync_information_array()
178 - *
179 - * Grab all Child Site Information.
180 - *
181 - * @param object $pWebsite The website object.
182 - * @param array $information Array contaning information returned from child site.
183 - * @param string $sync_errors Check for Sync Errors.
184 - * @param int $check_result Check if offline.
185 - * @param bool $error True|False.
186 - * @param bool $pAllowDisconnect True|False.
187 - *
188 - * @return bool true|false True on success, false on failure.
189 - *
190 - * @uses \MainWP\Dashboard\MainWP_DB::update_website_option()
191 - * @uses \MainWP\Dashboard\MainWP_DB::update_website_sync_values()
192 - * @uses \MainWP\Dashboard\MainWP_DB::update_website_values()
193 - * @uses \MainWP\Dashboard\MainWP_Logger::warning_for_website()
194 - * @uses \MainWP\Dashboard\MainWP_Monitoring_Handler::get_health_noticed_status_value()
195 - * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
196 - * @uses \MainWP\Dashboard\MainWP_Utility::get_site_health()
197 - */
198 - public static function sync_information_array( &$pWebsite, &$information, $sync_errors = '', $check_result = 1, $error = false, $pAllowDisconnect = true ) { // phpcs:ignore -- Current complexity is the only way to achieve desired results, pull request solutions appreciated.
199 - $emptyArray = wp_json_encode( array() );
200 - $websiteValues = array(
201 - 'directories' => $emptyArray,
202 - 'plugin_upgrades' => $emptyArray,
203 - 'theme_upgrades' => $emptyArray,
204 - 'translation_upgrades' => $emptyArray,
205 - 'securityIssues' => $emptyArray,
206 - 'themes' => $emptyArray,
207 - 'plugins' => $emptyArray,
208 - 'users' => $emptyArray,
209 - 'categories' => $emptyArray,
210 - 'offline_check_result' => $check_result,
211 - );
212 - $websiteSyncValues = array(
213 - 'sync_errors' => $sync_errors,
214 - 'version' => 0,
215 - );
153 + if ( ! is_array( static::$disallowed_clone_sites ) ) {
154 + static::$disallowed_clone_sites = array();
155 + }
216 156
217 - $_error = $sync_errors;
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 + );
218 167
219 - $done = false;
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 + }
220 176
221 - $current_siteid = 0;
222 - if ( is_string( $pWebsite ) || is_int( $pWebsite ) ) {
223 - $current_siteid = intval( $pWebsite );
224 - } elseif ( is_object( $pWebsite ) && ( ! property_exists( $pWebsite, 'plugin_updates' ) || ! property_exists( $pWebsite, 'theme_updates' ) ) ) {
225 - $current_siteid = $pWebsite->id;
226 - }
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 + }
227 190
228 - // to get full data.
229 - if ( $current_siteid ) {
230 - $pWebsite = MainWP_DB::instance()->get_website_by_id( $current_siteid );
231 - }
191 + $disallowed_current_site = static::$clone_enabled && is_array( static::$disallowed_clone_sites ) && in_array( $pWebsite->id, static::$disallowed_clone_sites ) ? true : false;
232 192
233 - /**
234 - * Filter: mainwp_before_save_sync_result
235 - *
236 - * Filters data returned from child site before saving to the database.
237 - *
238 - * @param object $pWebsite Object containing child site data.
239 - *
240 - * @since 3.4
241 - */
242 - $information = apply_filters( 'mainwp_before_save_sync_result', $information, $pWebsite );
193 + $primaryBackup = MainWP_System_Utility::get_primary_backup();
243 194
244 - if ( isset( $information['siteurl'] ) ) {
245 - $websiteValues['siteurl'] = $information['siteurl'];
246 - $done = true;
247 - }
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.
248 196
249 - if ( isset( $information['version'] ) ) {
250 - $websiteSyncValues['version'] = $information['version'];
251 - $done = true;
252 - }
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 );
253 209
254 - $phpversion = '';
255 - if ( isset( $information['site_info'] ) && ! empty( $information['site_info'] ) ) {
256 - if ( is_array( $information['site_info'] ) && isset( $information['site_info']['phpversion'] ) ) {
257 - $phpversion = $information['site_info']['phpversion'];
258 - }
259 - if ( is_array( $information['site_info'] ) && isset( $information['site_info']['ip'] ) ) {
260 - $websiteValues['ip'] = sanitize_text_field( wp_unslash( $information['site_info']['ip'] ) );
261 - }
262 - MainWP_DB::instance()->update_website_option( $pWebsite, 'site_info', wp_json_encode( $information['site_info'] ) );
263 - $done = true;
264 - } else {
265 - MainWP_DB::instance()->update_website_option( $pWebsite, 'site_info', $emptyArray );
266 - }
267 - if ( ! empty( $phpversion ) ) {
268 - MainWP_DB::instance()->update_website_option( $pWebsite, 'phpversion', $phpversion );
269 - }
270 - if ( isset( $information['directories'] ) && is_array( $information['directories'] ) ) {
271 - $websiteValues['directories'] = wp_json_encode( $information['directories'] );
272 - $done = true;
273 - } elseif ( isset( $information['directories'] ) ) {
274 - $websiteValues['directories'] = $information['directories'];
275 - $done = true;
276 - }
210 + $saved_days_number = apply_filters( 'mainwp_site_actions_saved_days_number', 30 );
277 211
278 - if ( isset( $information['wp_updates'] ) && ! empty( $information['wp_updates'] ) ) {
279 - MainWP_DB::instance()->update_website_option(
280 - $pWebsite,
281 - 'wp_upgrades',
282 - wp_json_encode(
283 - array(
284 - 'current' => $information['wpversion'],
285 - 'new' => $information['wp_updates'],
286 - )
287 - )
288 - );
289 - $done = true;
290 - } else {
291 - MainWP_DB::instance()->update_website_option( $pWebsite, 'wp_upgrades', $emptyArray );
292 - }
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 + }
293 220
294 - if ( isset( $information['plugin_updates'] ) ) {
295 - $update_values = array();
296 - if ( is_array( $information['plugin_updates'] ) ) {
297 - foreach ( $information['plugin_updates'] as $file => $update ) {
298 - $update_values[ $file ] = $update;
299 - }
300 - }
301 - $websiteValues['plugin_upgrades'] = wp_json_encode( $update_values );
302 - $done = true;
303 - }
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 + );
304 232
305 - if ( isset( $information['theme_updates'] ) ) {
306 - $update_values = array();
307 - if ( is_array( $information['theme_updates'] ) ) {
308 - foreach ( $information['theme_updates'] as $file => $update ) {
309 - $update_values[ $file ] = $update;
310 - }
311 - }
312 - $websiteValues['theme_upgrades'] = wp_json_encode( $update_values );
313 - $done = true;
314 - }
233 + $individual_settings_json = MainWP_DB::instance()->get_website_option( $pWebsite, 'password_policy_individual_settings' );
234 + $individual_settings = array();
315 235
316 - if ( isset( $information['translation_updates'] ) ) {
317 - $websiteValues['translation_upgrades'] = wp_json_encode( $information['translation_updates'] );
318 - $done = true;
319 - }
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 + }
320 242
321 - if ( isset( $information['premium_updates'] ) ) {
322 - MainWP_DB::instance()->update_website_option( $pWebsite, 'premium_upgrades', wp_json_encode( $information['premium_updates'] ) );
323 - $done = true;
324 - } else {
325 - MainWP_DB::instance()->update_website_option( $pWebsite, 'premium_upgrades', $emptyArray );
326 - }
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 + }
327 262
328 - if ( isset( $information['securityStats'] ) ) {
329 - $total_securityIssues = 0;
330 - $securityStats = $information['securityStats'];
331 - if ( is_array( $securityStats ) ) {
332 - /** This filter is documented in ../pages/page-mainwp-security-issues.php */
333 - $filterStats = apply_filters( 'mainwp_security_issues_stats', false, $securityStats, $pWebsite );
334 - if ( false !== $filterStats && is_array( $filterStats ) ) {
335 - $securityStats = array_merge( $securityStats, $filterStats );
336 - }
263 + $postdata['passwordPolicySettings'] = wp_json_encode( $password_policy_settings );
337 264
338 - $unset_scripts = apply_filters( 'mainwp_unset_security_scripts_stylesheets', true );
339 - if ( $unset_scripts ) {
340 - if ( isset( $securityStats['versions'] ) ) {
341 - unset( $securityStats['versions'] );
342 - }
343 - if ( isset( $securityStats['registered_versions'] ) ) {
344 - unset( $securityStats['registered_versions'] );
345 - }
346 - }
265 + $reg_verify = MainWP_DB::instance()->get_website_option( $pWebsite, 'register_verify_key', '' );
266 + if ( empty( $reg_verify ) ) {
267 + $postdata['sync_regverify'] = 1;
268 + }
347 269
348 - $tmp_issues = array_filter(
349 - $securityStats,
350 - function ( $v ) {
351 - return 'N' === $v;
352 - },
353 - ARRAY_FILTER_USE_BOTH
354 - );
355 - $total_securityIssues = count( $tmp_issues );
356 - $securityStats = wp_json_encode( $securityStats );
357 - } else {
358 - $securityStats = $emptyArray;
359 - }
360 - $websiteValues['securityIssues'] = $total_securityIssues;
361 - MainWP_DB::instance()->update_website_option( $pWebsite, 'security_stats', $securityStats );
362 - $done = true;
363 - } elseif ( isset( $information['securityIssues'] ) && MainWP_Utility::ctype_digit( $information['securityIssues'] ) && $information['securityIssues'] >= 0 ) {
364 - $websiteValues['securityIssues'] = $information['securityIssues'];
365 - $done = true;
366 - }
270 + $postdata['params_logs'] = apply_filters( 'mainwp_module_logs_changes_logs_sync_params', '', $pWebsite->id, $postdata, $pWebsite );
367 271
368 - if ( isset( $information['recent_comments'] ) ) {
369 - MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_comments', wp_json_encode( $information['recent_comments'] ) );
370 - $done = true;
371 - } else {
372 - MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_comments', $emptyArray );
373 - }
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 + }
374 276
375 - if ( isset( $information['recent_posts'] ) ) {
376 - MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_posts', wp_json_encode( $information['recent_posts'] ) );
377 - $done = true;
378 - } else {
379 - MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_posts', $emptyArray );
380 - }
277 + $synclist = MainWP_Settings::get_instance()->get_data_list_to_sync();
278 + $postdata['syncdata'] = wp_json_encode( $synclist );
381 279
382 - if ( isset( $information['recent_pages'] ) ) {
383 - MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_pages', wp_json_encode( $information['recent_pages'] ) );
384 - $done = true;
385 - } else {
386 - MainWP_DB::instance()->update_website_option( $pWebsite, 'recent_pages', $emptyArray );
387 - }
280 + static::push_stack_action( 'sync_stats' );
388 281
389 - if ( isset( $information['themes'] ) ) {
390 - $websiteValues['themes'] = wp_json_encode( $information['themes'] );
391 - $done = true;
392 - }
282 + $information = MainWP_Connect::fetch_url_authed(
283 + $pWebsite,
284 + 'stats',
285 + $postdata,
286 + true,
287 + $pForceFetch
288 + );
393 289
394 - if ( isset( $information['plugins'] ) ) {
395 - $websiteValues['plugins'] = wp_json_encode( $information['plugins'] );
396 - $done = true;
397 - }
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 = '';
398 297
399 - if ( isset( $information['users'] ) ) {
400 - $websiteValues['users'] = wp_json_encode( $information['users'] );
401 - $done = true;
402 - }
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 + }
403 303
404 - if ( isset( $information['categories'] ) ) {
405 - $websiteValues['categories'] = wp_json_encode( $information['categories'] );
406 - $done = true;
407 - }
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 + }
408 308
409 - if ( isset( $information['totalsize'] ) ) {
410 - $websiteSyncValues['totalsize'] = $information['totalsize'];
411 - $done = true;
412 - }
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 + );
413 340
414 - if ( isset( $information['dbsize'] ) ) {
415 - $websiteSyncValues['dbsize'] = $information['dbsize'];
416 - $done = true;
417 - }
341 + $_error = $sync_errors;
418 342
419 - if ( isset( $information['extauth'] ) ) {
420 - $websiteSyncValues['extauth'] = $information['extauth'];
421 - $done = true;
422 - }
343 + $done = false;
423 344
424 - if ( isset( $information['wpe'] ) ) {
425 - $websiteValues['wpe'] = $information['wpe'];
426 - $done = true;
427 - }
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 + }
428 351
429 - if ( isset( $information['wphost'] ) ) {
430 - MainWP_DB::instance()->update_website_option( $pWebsite, 'wphost', $information['wphost'] );
431 - }
352 + // to get full data.
353 + if ( $current_siteid ) {
354 + $pWebsite = MainWP_DB::instance()->get_website_by_id( $current_siteid );
355 + }
432 356
433 - if ( isset( $information['last_post_gmt'] ) ) {
434 - $websiteSyncValues['last_post_gmt'] = $information['last_post_gmt'];
435 - $done = true;
436 - }
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 );
437 367
438 - if ( isset( $information['health_site_status'] ) ) {
439 - $health_status = $information['health_site_status'];
440 - $hstatus = MainWP_Utility::get_site_health( $health_status );
441 - $custom_health_value = $hstatus['val'] - $hstatus['critical'] * 100; // computes custom health value to support sorting by sites health and sites health threshold.
442 - $websiteSyncValues['health_value'] = $custom_health_value;
443 - $done = true;
444 - MainWP_DB::instance()->update_website_option( $pWebsite, 'health_site_status', wp_json_encode( $health_status ) );
445 - $new_noticed = MainWP_Monitoring_Handler::get_health_noticed_status_value( $pWebsite, $custom_health_value );
446 - if ( null !== $new_noticed ) {
447 - MainWP_DB::instance()->update_website_sync_values(
448 - $pWebsite->id,
449 - array(
450 - 'health_site_noticed' => $new_noticed,
451 - )
452 - );
453 - }
368 + if ( ! empty( $information['regverify_info'] ) ) {
369 + MainWP_DB::instance()->update_website_option( $pWebsite, 'register_verify_key', $information['regverify_info'] );
370 + $done = true;
371 + }
454 372
455 - $hval = $hstatus['val'];
456 - $critical = $hstatus['critical'];
457 - $health_status = 0;
458 - if ( 80 <= $hval && empty( $critical ) ) {
459 - $health_status = 0; // Good.
460 - } else {
461 - $health_status = 1; // Should be improved'.
462 - }
463 - $websiteSyncValues['health_status'] = $health_status;
464 - } else {
465 - MainWP_DB::instance()->update_website_option( $pWebsite, 'health_site_status', $emptyArray );
466 - }
373 + if ( isset( $information['siteurl'] ) ) {
374 + $websiteValues['siteurl'] = $information['siteurl'];
375 + $done = true;
376 + }
467 377
468 - if ( isset( $information['mainwpdir'] ) ) {
469 - $websiteValues['mainwpdir'] = $information['mainwpdir'];
470 - $done = true;
471 - }
378 + if ( isset( $information['version'] ) ) {
379 + $websiteSyncValues['version'] = $information['version'];
380 + $done = true;
381 + }
472 382
473 - if ( isset( $information['uniqueId'] ) ) {
474 - $websiteValues['uniqueId'] = $information['uniqueId'];
475 - $done = true;
476 - }
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 + }
477 392
478 - if ( isset( $information['clone_adminname'] ) ) {
479 - $websiteValues['adminname'] = $information['clone_adminname'];
480 - $done = true;
481 - }
393 + if ( is_array( $information['site_info'] ) && isset( $information['site_info']['wpversion'] ) ) {
394 + $wpversion = $information['site_info']['wpversion'];
395 + }
482 396
483 - if ( isset( $information['admin_nicename'] ) ) {
484 - MainWP_DB::instance()->update_website_option( $pWebsite, 'admin_nicename', trim( $information['admin_nicename'] ) );
485 - $done = true;
486 - }
397 + MainWP_DB::instance()->update_website_option( $pWebsite, 'site_info', wp_json_encode( $information['site_info'] ) );
398 + $done = true;
399 + }
487 400
488 - if ( isset( $information['admin_useremail'] ) ) {
489 - MainWP_DB::instance()->update_website_option( $pWebsite, 'admin_useremail', trim( $information['admin_useremail'] ) );
490 - $done = true;
491 - }
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 + }
492 408
493 - if ( isset( $information['plugins_outdate_info'] ) ) {
494 - MainWP_DB::instance()->update_website_option( $pWebsite, 'plugins_outdate_info', wp_json_encode( $information['plugins_outdate_info'] ) );
495 - $done = true;
496 - } else {
497 - MainWP_DB::instance()->update_website_option( $pWebsite, 'plugins_outdate_info', $emptyArray );
498 - }
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 + }
499 416
500 - if ( isset( $information['themes_outdate_info'] ) ) {
501 - MainWP_DB::instance()->update_website_option( $pWebsite, 'themes_outdate_info', wp_json_encode( $information['themes_outdate_info'] ) );
502 - $done = true;
503 - } else {
504 - MainWP_DB::instance()->update_website_option( $pWebsite, 'themes_outdate_info', $emptyArray );
505 - }
417 + $had_pending_updates = null;
506 418
507 - if ( isset( $information['primaryLasttimeBackup'] ) ) {
508 - MainWP_DB::instance()->update_website_option( $pWebsite, 'primary_lasttime_backup', $information['primaryLasttimeBackup'] );
509 - $done = true;
510 - }
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 + }
511 435
512 - if ( isset( $information['child_site_actions_data'] ) ) {
513 - if ( is_array( $information['child_site_actions_data'] ) && isset( $information['child_site_actions_data']['connected_admin'] ) ) {
514 - unset( $information['child_site_actions_data']['connected_admin'] );
515 - }
516 - MainWP_DB_Site_Actions::instance()->sync_site_actions( $pWebsite->id, $information['child_site_actions_data'] );
517 - $done = true;
518 - }
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 + }
519 443
520 - if ( ! $done ) {
521 - if ( isset( $information['wpversion'] ) ) {
522 - $done = true;
523 - } elseif ( isset( $information['error'] ) ) {
524 - MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[' . esc_html( $information['error'] ) . ']' );
525 - $error = true;
526 - $done = true;
527 - $_error = esc_html__( 'ERROR: ', 'mainwp' ) . esc_html( $information['error'] );
528 - $websiteSyncValues['sync_errors'] = $_error;
529 - } elseif ( ! empty( $sync_errors ) ) {
530 - MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[' . $sync_errors . ']' );
531 - $_error = $sync_errors;
532 - $error = true;
533 - if ( ! $pAllowDisconnect ) {
534 - $sync_errors = '';
535 - }
444 + $had_pending_updates = ! empty( $update_values ) || (bool) $had_pending_updates;
536 445
537 - $websiteSyncValues['sync_errors'] = $sync_errors;
538 - } else {
539 - MainWP_Logger::instance()->warning_for_website( $pWebsite, 'SYNC ERROR', '[Undefined error]' );
540 - $error = true;
541 - if ( $pAllowDisconnect ) {
542 - $sync_errors = esc_html__( 'Undefined error! Please, reinstall the MainWP Child plugin on the child site.', 'mainwp' );
543 - $websiteSyncValues['sync_errors'] = $sync_errors;
544 - $_error = $sync_errors;
545 - }
546 - }
547 - }
446 + $websiteValues['plugin_upgrades'] = wp_json_encode( $update_values );
447 + $done = true;
448 + }
548 449
549 - $act_success = false;
550 - if ( $done ) {
551 - $act_success = true;
552 - $websiteSyncValues['dtsSync'] = time();
553 - }
554 - MainWP_DB::instance()->update_website_sync_values( $pWebsite->id, $websiteSyncValues );
555 - MainWP_DB::instance()->update_website_values( $pWebsite->id, $websiteValues );
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 + }
556 461
557 - // Sync action.
558 - if ( ! $error ) {
559 - do_action_deprecated( 'mainwp-site-synced', array( $pWebsite, $information ), '4.0.7.2', 'mainwp_site_synced' ); // @deprecated Use 'mainwp_site_synced' instead.
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 + }
560 467
561 - /**
562 - * Action: mainwp_site_synced
563 - *
564 - * Fires upon successful site synchronization.
565 - *
566 - * @param object $pWebsite Object containing child site info.
567 - * @param array $information Array containing information returned from child site.
568 - *
569 - * @since 3.4
570 - */
571 - do_action( 'mainwp_site_synced', $pWebsite, $information );
572 - }
468 + if ( isset( $information['premium_updates'] ) ) {
469 + $had_pending_updates = ! empty( $information['premium_updates'] ) || (bool) $had_pending_updates;
573 470
574 - $post_data = array();
471 + MainWP_DB::instance()->update_website_option( $pWebsite, 'premium_upgrades', wp_json_encode( $information['premium_updates'] ) );
472 + $done = true;
473 + }
575 474
576 - /**
577 - * Action: mainwp_site_sync
578 - *
579 - * Fires upon successful site synchronization.
580 - *
581 - * @param object $pWebsite Object containing child site info.
582 - * @param array $information Array containing information returned from child site.
583 - * @param bool $act_success action success or failed.
584 - * @param string $_error Sync error message if existed.
585 - * @param array $post_data Addition post data.
586 - *
587 - * @since 3.4
588 - */
589 - do_action( 'mainwp_site_sync', $pWebsite, $information, $act_success, $_error, $post_data );
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 + }
590 484
591 - return ( ! $error );
592 - }
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 + }
593 504
594 - /**
595 - * Method get_wp_icon()
596 - *
597 - * Get site's icon.
598 - *
599 - * @param mixed $siteId site's id.
600 - *
601 - * @return array result error or success
602 - * @throws \Exception Error message.
603 - *
604 - * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
605 - * @uses \MainWP\Dashboard\MainWP_Connect::get_file_content()
606 - * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
607 - * @uses \MainWP\Dashboard\MainWP_DB_Common::update_website_option()
608 - * @uses \MainWP\Dashboard\MainWP_Exception
609 - * @uses \MainWP\Dashboard\MainWP_Logger::debug()
610 - * @uses \MainWP\Dashboard\MainWP_System_Utility::can_edit_website()
611 - * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
612 - * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
613 - * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
614 - */
615 - public static function get_wp_icon( $siteId = null ) {
616 - if ( MainWP_Utility::ctype_digit( $siteId ) ) {
617 - $website = MainWP_DB::instance()->get_website_by_id( $siteId );
618 - if ( MainWP_System_Utility::can_edit_website( $website ) ) {
619 - $error = '';
620 - try {
621 - $information = MainWP_Connect::fetch_url_authed( $website, 'get_site_icon' );
622 - } catch ( MainWP_Exception $e ) {
623 - $error = $e->getMessage();
624 - }
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 + }
625 509
626 - if ( ! empty( $error ) ) {
627 - return array( 'error' => $error );
628 - } elseif ( isset( $information['faviIconUrl'] ) && ! empty( $information['faviIconUrl'] ) ) {
629 - MainWP_Logger::instance()->debug( 'Downloading icon :: ' . esc_html( $information['faviIconUrl'] ) );
630 - $content = MainWP_Connect::get_file_content( $information['faviIconUrl'] );
631 - if ( ! empty( $content ) ) {
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 + }
632 514
633 - $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
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 + }
634 519
635 - /**
636 - * WordPress files system object.
637 - *
638 - * @global object
639 - */
640 - global $wp_filesystem;
520 + if ( isset( $information['themes'] ) ) {
521 + $websiteValues['themes'] = wp_json_encode( $information['themes'] );
522 + $done = true;
523 + }
641 524
642 - $dirs = MainWP_System_Utility::get_mainwp_dir( 'icons', true );
643 - $iconsDir = $dirs[0];
644 - $filename = basename( $information['faviIconUrl'] );
645 - $filename = strtok( $filename, '?' );
646 - if ( $filename ) {
647 - $filename = 'favi-' . $siteId . '-' . $filename;
648 - $size = false;
649 - if ( MainWP_Utility::check_image_file_name( $filename ) ) {
650 - $size = $wp_filesystem->put_contents( $iconsDir . $filename, $content ); // phpcs:ignore --
651 - }
652 - if ( $size ) {
653 - MainWP_Logger::instance()->debug( 'Icon size :: ' . $size );
654 - MainWP_DB::instance()->update_website_option( $website, 'favi_icon', $filename );
655 - return array( 'result' => 'success' );
656 - } else {
657 - return array( 'error' => 'Save icon file failed.' );
658 - }
659 - }
660 - return array( 'undefined_error' => true );
661 - } else {
662 - return array( 'error' => esc_html__( 'Download icon file failed', 'mainwp' ) );
663 - }
664 - } else {
665 - return array( 'undefined_error' => true );
666 - }
667 - }
668 - }
669 - return array( 'result' => 'NOSITE' );
670 - }
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 + * Method sync_partial_information()
834 + *
835 + * @param object $pWebsite The website object.
836 + * @param array $information Array contaning information returned from child site.
837 + */
838 + public static function sync_partial_information( &$pWebsite, &$information ) {
839 + $websiteValues = array();
840 +
841 + /**
842 + * Filter: mainwp_before_save_partial_sync_result
843 + *
844 + * Filters partial sync data returned from the child site before saving it to the database.
845 + *
846 + * @param array $information Partial sync data returned from the child site.
847 + * @param object $pWebsite Object containing child site data.
848 + *
849 + * @since 6.2.1
850 + */
851 + $information = apply_filters( 'mainwp_before_save_partial_sync_result', $information, $pWebsite );
852 +
853 + if ( isset( $information['plugins'] ) ) {
854 + $plugins_info = $information['plugins'];
855 + $websiteValues['plugins'] = wp_json_encode( $plugins_info );
856 + }
857 + if ( ! empty( $websiteValues ) ) {
858 + MainWP_DB::instance()->update_website_values( $pWebsite->id, $websiteValues );
859 + }
860 + }
861 +
862 +
863 + /**
864 + * Method get_telem_sync_info.
865 + *
866 + * @param mixed $sync_done
867 + * @return void
868 + */
869 + public static function get_telem_sync_info( $sync_done ) {
870 +
871 + $is_bulk_sync = ! empty( $_POST['bulkSync'] ) ? true : false; // phpcs:ignore -- NOSONAR - superglobal usage is acceptable.
872 +
873 + $tp = 'post_add_site';
874 +
875 + if ( $is_bulk_sync ) {
876 + $tp = 'manual_bulk';
877 + } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
878 + $tp = 'auto_cron';
879 + } elseif ( isset( $_POST['bulkSync'] ) && ! $is_bulk_sync ) { //phpcs:ignore -- NOSONAR - superglobal usage is acceptable.
880 + $tp = 'manual_single';
881 + }
882 +
883 + $trigger = 'system';
884 + if ( 'manual_single' === $tp || 'manual_bulk' === $tp ) {
885 + $trigger = 'user_click';
886 + } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
887 + $trigger = 'cron';
888 + }
889 +
890 + $curr_stack = static::get_current_stack_action();
891 + $prev_conn_status = in_array( $curr_stack, array( 'sync_before_reconnect', 'sync_reconnect' ) ) ? 'disconnected' : 'connected';
892 + $new_conn_status = $sync_done ? 'disconnected' : 'connected';
893 +
894 + return array(
895 + 'sync_type' => $tp,
896 + 'trigger' => $trigger,
897 + 'previous_connection_status' => $prev_conn_status,
898 + 'new_connection_status' => $new_conn_status,
899 + 'connection_status_changed' => $prev_conn_status === $new_conn_status ? false : true,
900 + 'sync_duration_ms' => MainWP_Execution_Helper::get_run_time( true ),
901 + );
902 + }
903 +
904 + /**
905 + * Method init empty sync values.
906 + *
907 + * @param object $pWebsite Object containing child site info.
908 + *
909 + * @return void
910 + */
911 + public static function sync_init_empty_values( $pWebsite ) {
912 +
913 + $emptyArray = wp_json_encode( array() );
914 +
915 + $opts = array(
916 + 'site_info',
917 + 'wp_upgrades',
918 + 'premium_upgrades',
919 + 'recent_comments',
920 + 'recent_posts',
921 + 'recent_pages',
922 + 'health_site_status',
923 + 'plugins_outdate_info',
924 + 'themes_outdate_info',
925 + 'directories',
926 + 'plugin_upgrades',
927 + 'theme_upgrades',
928 + 'translation_upgrades',
929 + 'securityIssues',
930 + 'themes',
931 + 'plugins',
932 + 'users',
933 + 'categories',
934 + 'password_policy_options',
935 + );
936 +
937 + foreach ( $opts as $opt ) {
938 + MainWP_DB::instance()->update_website_option( $pWebsite, $opt, $emptyArray );
939 + }
940 + }
941 +
942 +
943 + /**
944 + * Method get_wp_icon()
945 + *
946 + * Get site's icon.
947 + *
948 + * @param mixed $siteId site's id.
949 + *
950 + * @return array result error or success
951 + * @throws \MainWP_Exception Error message.
952 + *
953 + * @uses \MainWP\Dashboard\MainWP_Connect::fetch_url_authed()
954 + * @uses \MainWP\Dashboard\MainWP_Connect::get_file_content()
955 + * @uses \MainWP\Dashboard\MainWP_DB::get_website_by_id()
956 + * @uses \MainWP\Dashboard\MainWP_DB_Common::update_website_option()
957 + * @uses \MainWP\Dashboard\MainWP_Exception
958 + * @uses \MainWP\Dashboard\MainWP_Logger::debug()
959 + * @uses \MainWP\Dashboard\MainWP_System_Utility::can_edit_website()
960 + * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
961 + * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
962 + * @uses \MainWP\Dashboard\MainWP_Utility::ctype_digit()
963 + */
964 + public static function get_wp_icon( $siteId = null ) { // phpcs:ignore -- NOSONAR - complex.
965 + if ( MainWP_Utility::ctype_digit( $siteId ) ) {
966 + $website = MainWP_DB::instance()->get_website_by_id( $siteId );
967 + if ( MainWP_System_Utility::can_edit_website( $website ) ) {
968 + $error = '';
969 + try {
970 + $information = MainWP_Connect::fetch_url_authed( $website, 'get_site_icon' );
971 + } catch ( MainWP_Exception $e ) {
972 + $error = $e->getMessage();
973 + }
974 +
975 + if ( ! empty( $error ) ) {
976 + return array( 'error' => $error );
977 + } elseif ( isset( $information['faviIconUrl'] ) && ! empty( $information['faviIconUrl'] ) ) {
978 + MainWP_Logger::instance()->debug( 'Downloading icon :: ' . esc_html( $information['faviIconUrl'] ) );
979 + $content = MainWP_Connect::get_file_content( $information['faviIconUrl'] );
980 + if ( ! empty( $content ) ) {
981 +
982 + MainWP_System_Utility::get_wp_file_system();
983 +
984 + /**
985 + * WordPress files system object.
986 + *
987 + * @global object
988 + */
989 + global $wp_filesystem;
990 +
991 + $dirs = MainWP_System_Utility::get_mainwp_dir( 'icons', true );
992 + $iconsDir = $dirs[0];
993 + $filename = basename( $information['faviIconUrl'] );
994 + $filename = strtok( $filename, '?' );
995 + if ( $filename ) {
996 + $filename = 'favi-' . $siteId . '-' . $filename;
997 + $size = false;
998 + if ( MainWP_Utility::check_image_file_name( $filename ) ) {
999 + $size = $wp_filesystem->put_contents( $iconsDir . $filename, $content ); // phpcs:ignore --
1000 + }
1001 + if ( $size ) {
1002 + MainWP_Logger::instance()->debug( 'Icon size :: ' . $size );
1003 + MainWP_DB::instance()->update_website_option( $website, 'favi_icon', $filename );
1004 + return array( 'result' => 'success' );
1005 + } else {
1006 + return array( 'error' => 'Save icon file failed.' );
1007 + }
1008 + }
1009 + return array( 'undefined_error' => true );
1010 + } else {
1011 + return array( 'error' => esc_html__( 'Download icon file failed', 'mainwp' ) );
1012 + }
1013 + } else {
1014 + return array( 'undefined_error' => true );
1015 + }
1016 + }
1017 + }
1018 + return array( 'result' => 'NOSITE' );
1019 + }
671 1020 }