PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.2
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.2
6.3 6.2.3 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 All 157 releases
mainwp / class / class-mainwp-cron-jobs-auto-updates.php

class-mainwp-cron-jobs-auto-updates.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies 6.2.2, at class/class-mainwp-cron-jobs-auto-updates.php

1,080 lines 50.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MainWP System Cron Jobs.
4 *
5 * @package MainWP/Dashboard
6 */
7
8 namespace MainWP\Dashboard;
9
10 // Exit if accessed directly.
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit;
13 }
14
15 /**
16 * Class MainWP_Cron_Jobs_Auto_Updates
17 *
18 * @package MainWP\Dashboard
19 */
20 class MainWP_Cron_Jobs_Auto_Updates { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
21
22 /**
23 * Singleton.
24 *
25 * @var null $instance
26 */
27 private static $instance = null;
28
29
30 /**
31 * MainWP Cron Instance.
32 *
33 * @return self $instance
34 */
35 public static function instance() {
36 if ( null === static::$instance ) {
37 static::$instance = new self();
38 }
39
40 return static::$instance;
41 }
42
43 /**
44 * Constructor.
45 *
46 * Run each time the class is called.
47 */
48 public function __construct() {
49 }
50
51
52 /**
53 * Method check_to_run_auto_updates()
54 *
55 * @return mixed results.
56 */
57 public function check_to_run_auto_updates() {
58
59 $enable_automaticCoreUpdates = get_option( 'mainwp_automaticDailyUpdate' );
60 $plugin_automaticDailyUpdate = get_option( 'mainwp_pluginAutomaticDailyUpdate' );
61 $theme_automaticDailyUpdate = get_option( 'mainwp_themeAutomaticDailyUpdate' );
62
63 $diabled_auto_updates = 1 !== (int) $enable_automaticCoreUpdates && 1 !== (int) $plugin_automaticDailyUpdate && 1 !== (int) $theme_automaticDailyUpdate;
64
65 $auto_updates_running = get_option( 'mainwp_automatic_updates_is_running', 0 );
66
67 if ( $diabled_auto_updates && $auto_updates_running ) {
68 $this->finished_auto_updates();
69 MainWP_Utility::update_option( 'mainwp_automatic_update_next_run_timestamp', 0 );
70 return false;
71 }
72
73 $local_timestamp = MainWP_Utility::get_timestamp();
74
75 if ( $auto_updates_running ) {
76 $start_time = get_option( 'mainwp_automatic_updates_start_lasttime', 0 );
77 if ( ! empty( $start_time ) && $local_timestamp > (int) $start_time + 4 * HOUR_IN_SECONDS ) {
78 MainWP_Logger::instance()->log_events( 'debug-updates-crons', 'Auto Updates: Stopped — timeout reached.' );
79 $this->finished_auto_updates();
80 return false;
81 }
82 MainWP_Logger::instance()->log_events( 'debug-updates-crons', 'Auto Updates: Running.' );
83 return true;
84 } else {
85 $time_to_auto_updates = get_option( 'mainwp_automatic_update_next_run_timestamp', 0 );
86
87 // to fix compatiple.
88 $frequency_AutoUpdate = get_option( 'mainwp_frequency_AutoUpdate' );
89 if ( false === $frequency_AutoUpdate ) {
90 MainWP_Utility::update_option( 'mainwp_frequency_AutoUpdate', 'daily' );
91 static::set_next_auto_updates_time();
92 }
93
94 if ( ! empty( $time_to_auto_updates ) && $local_timestamp > $time_to_auto_updates ) {
95 static::set_next_auto_updates_time();
96
97 $this->log_start_auto_updates();
98
99 MainWP_Utility::update_option( 'mainwp_automatic_updates_start_lasttime', $local_timestamp );
100 MainWP_Utility::update_option( 'mainwp_automatic_updates_is_running', 1 );
101 MainWP_Updates_Report_Manager::init();
102
103 $websites = MainWP_Auto_Updates_DB::instance()->get_websites_to_start_updates( false, true ); // included disconnected sites.
104 while ( $websites && ( $website = MainWP_DB::fetch_object( $websites ) ) ) {
105 $websiteValues = array(
106 'dtsAutomaticSyncStart' => $local_timestamp,
107 );
108 MainWP_DB::instance()->update_website_sync_values( $website->id, $websiteValues );
109 MainWP_DB::instance()->update_website_option( $website, 'bulk_updates_info', wp_json_encode( array() ) );
110 }
111 MainWP_DB::free_result( $websites );
112 MainWP_Logger::instance()->log_events( 'debug-updates-crons', 'Auto Updates: Starting run.' );
113 return true;
114 }
115
116 if ( get_option( 'mainwp_automatic_updates_ready_to_send_notification', 0 ) ) {
117 MainWP_Updates_Report_Manager::send_auto_update_info();
118 MainWP_Utility::update_option( 'mainwp_automatic_updates_ready_to_send_notification', 0 );
119 MainWP_Logger::instance()->log_events( 'auto-updates', 'Auto updates: notification process completed' );
120 }
121 }
122 return false;
123 }
124
125 /**
126 * Method handle_cron_auto_updates()
127 *
128 * MainWP Cron Check Update
129 *
130 * This Cron Checks to see if Automatic Daily Updates need to be performed.
131 *
132 * @return mixed results.
133 */
134 public function handle_cron_auto_updates() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity -- NOSONAR Current complexity is the only way to achieve desired results, pull request solutions appreciated.
135
136 $sites_limit = apply_filters( 'mainwp_cron_bulk_update_sites_limit', 3 );
137 $items_limit = apply_filters( 'mainwp_cron_bulk_update_items_limit', 3 );
138
139 $local_timestamp = MainWP_Utility::get_timestamp();
140 $enable_automaticCoreUpdates = get_option( 'mainwp_automaticDailyUpdate' );
141 $plugin_automaticDailyUpdate = get_option( 'mainwp_pluginAutomaticDailyUpdate' );
142 $theme_automaticDailyUpdate = get_option( 'mainwp_themeAutomaticDailyUpdate' );
143 $tran_automaticDailyUpdate = get_option( 'mainwp_transAutomaticDailyUpdate' );
144
145 $websites = array();
146
147 $lasttime_start = get_option( 'mainwp_automatic_updates_start_lasttime' );
148
149 $autoupdates_websites = MainWP_Auto_Updates_DB::instance()->get_websites_to_continue_updates( $sites_limit, $lasttime_start, false, true ); // included disconnected sites.
150
151 MainWP_Logger::instance()->log_events( 'debug-updates-crons', 'Auto updates :: found :: ' . ( ! empty( $autoupdates_websites ) ? count( $autoupdates_websites ) : 0 ) );
152
153 if ( empty( $autoupdates_websites ) ) { // not found automatic sites to updates.
154 $this->finished_auto_updates();
155 MainWP_Logger::instance()->info( 'Automatic updates finished' );
156 MainWP_Logger::instance()->log_update_check( 'Automatic updates finished' );
157 MainWP_Logger::instance()->log_events( 'debug-updates-crons', 'Auto Updates: Finished.' );
158
159 // Legacy logs.
160 if ( ! empty( $lasttime_start ) ) {
161 $busyCounter = MainWP_Auto_Updates_DB::instance()->get_websites_count_where_dts_automatic_sync_smaller_then_start( $lasttime_start );
162 if ( ! empty( $busyCounter ) ) {
163 MainWP_Logger::instance()->log_update_check( 'Automatic updates busy counter :: [found=' . intval( $busyCounter ) . ' websites]' );
164 $lastAutomaticUpdate = MainWP_Auto_Updates_DB::instance()->get_websites_last_automatic_sync();
165 if ( ( $local_timestamp - $lastAutomaticUpdate ) < HOUR_IN_SECONDS ) {
166 MainWP_Logger::instance()->log_update_check( 'Automatic updates last update :: ' . $lastAutomaticUpdate );
167 }
168 }
169 }
170 return;
171 } else {
172 // @since 5.4.0.2 +.
173 $sync_before = apply_filters( 'mainwp_auto_updates_sync_data_before_run', true );
174 foreach ( $autoupdates_websites as $website ) {
175 if ( ! empty( $website->sync_errors ) ) {
176 if ( ! MainWP_Sync::sync_site( $website, false, true ) ) {
177 $this->finished_site_auto_updates( $website ); // to skip sync error sites.
178 }
179 } elseif ( $sync_before && ! MainWP_Sync::sync_site( $website, false, true ) ) {
180 $this->finished_site_auto_updates( $website ); // to skip.
181 } else {
182 $websites[] = $website;
183 }
184 }
185
186 $log_lastsstart = ! empty( $lasttime_start ) ? ' :: [lasttime_start=' . MainWP_Utility::format_timestamp( $lasttime_start ) . '] ' : '';
187 MainWP_Logger::instance()->info( 'Automatic updates found [count=' . count( $autoupdates_websites ) . ']' . $log_lastsstart );
188 MainWP_Logger::instance()->log_update_check( 'Automatic updates found [count=' . count( $autoupdates_websites ) . ']' . $log_lastsstart );
189 unset( $autoupdates_websites );
190 }
191
192 MainWP_Logger::instance()->log_events( 'debug-updates-crons', 'Auto updates :: running :: count :: ' . count( $websites ) );
193
194 MainWP_Logger::instance()->log_events( 'auto-updates', 'Auto updates :: found sites :: [count=' . count( $websites ) . ']' );
195
196 $count_processed_now = 0;
197
198 $userExtension = MainWP_DB_Common::instance()->get_user_extension_by_user_id();
199
200 $decodedIgnoredCores = ! empty( $userExtension->ignored_wp_upgrades ) ? json_decode( $userExtension->ignored_wp_upgrades, true ) : array();
201 $decodedIgnoredPlugins = ! empty( $userExtension->ignored_plugins ) ? json_decode( $userExtension->ignored_plugins, true ) : array();
202 $trustedPlugins = ! empty( $userExtension->trusted_plugins ) ? json_decode( $userExtension->trusted_plugins, true ) : array();
203 $decodedIgnoredThemes = ! empty( $userExtension->ignored_themes ) ? json_decode( $userExtension->ignored_themes, true ) : array();
204 $trustedThemes = ! empty( $userExtension->trusted_themes ) ? json_decode( $userExtension->trusted_themes, true ) : array();
205
206 if ( ! is_array( $decodedIgnoredCores ) ) {
207 $decodedIgnoredCores = array();
208 }
209
210 if ( ! is_array( $decodedIgnoredPlugins ) ) {
211 $decodedIgnoredPlugins = array();
212 }
213
214 if ( ! is_array( $trustedPlugins ) ) {
215 $trustedPlugins = array();
216 }
217
218 if ( ! is_array( $trustedThemes ) ) {
219 $trustedThemes = array();
220 }
221
222 if ( ! is_array( $decodedIgnoredThemes ) ) {
223 $decodedIgnoredThemes = array();
224 }
225
226 $finished_updates_sites = array();
227
228 $coreToUpdateNow = array();
229 $pluginsToUpdateNow = array();
230 $themesToUpdateNow = array();
231 $transToUpdateNow = array();
232
233 $delay_autoupdate = get_option( 'mainwp_delay_autoupdate', 1 );
234
235 $processed_init = array(
236 'wp' => array(),
237 'plugins' => array(),
238 'themes' => array(),
239 'trans' => array(),
240 );
241
242 foreach ( $websites as $website ) {
243 $params = array(
244 'view' => 'updates_view',
245 'include' => array( $website->id ),
246 'others_fields' => array(
247 'core_update_check',
248 'plugins_update_check',
249 'themes_update_check',
250 'trans_update_check',
251 'premium_upgrades',
252 'ignored_wp_upgrades',
253 'ignored_trans_updates',
254 'bulk_wp_upgrades',
255 'bulk_plugin_upgrades',
256 'bulk_theme_upgrades',
257 'bulk_updates_info',
258 ),
259 );
260
261 $fetch_one = MainWP_DB::instance()->query( MainWP_DB::instance()->get_sql_websites_for_current_user_by_params( $params ) );
262 if ( $fetch_one ) {
263 $website = MainWP_DB::fetch_object( $fetch_one );
264 MainWP_DB::free_result( $fetch_one );
265 }
266
267 if ( empty( $website ) ) {
268 continue;
269 }
270
271 $found_updates = 0;
272
273 $websiteDecodedIgnoredPlugins = json_decode( $website->ignored_plugins, true );
274 if ( ! is_array( $websiteDecodedIgnoredPlugins ) ) {
275 $websiteDecodedIgnoredPlugins = array();
276 }
277
278 $websiteDecodedIgnoredThemes = json_decode( $website->ignored_themes, true );
279 if ( ! is_array( $websiteDecodedIgnoredThemes ) ) {
280 $websiteDecodedIgnoredThemes = array();
281 }
282
283 $websiteCoreUpgrades = ! empty( $website->wp_upgrades ) ? json_decode( $website->wp_upgrades, true ) : array();
284 $websiteIgnoredCores = ! empty( $website->ignored_wp_upgrades ) ? json_decode( $website->ignored_wp_upgrades, true ) : array();
285
286 if ( ! is_array( $websiteCoreUpgrades ) ) {
287 $websiteCoreUpgrades = array();
288 }
289
290 if ( ! is_array( $websiteIgnoredCores ) ) {
291 $websiteIgnoredCores = array();
292 }
293
294 $websiteCoreUpdateCheck = 0;
295 $websitePluginsUpdateCheck = array();
296 $websiteThemesUpdateCheck = array();
297 $websiteTransUpdateCheck = array();
298
299 if ( ! empty( $delay_autoupdate ) ) {
300 $websiteCoreUpdateCheck = ! empty( $website->core_update_check ) ? intval( $website->core_update_check ) : 0;
301 $websitePluginsUpdateCheck = ! empty( $website->plugins_update_check ) ? json_decode( $website->plugins_update_check, true ) : array();
302 $websiteThemesUpdateCheck = ! empty( $website->themes_update_check ) ? json_decode( $website->themes_update_check, true ) : array();
303 $websiteTransUpdateCheck = ! empty( $website->trans_update_check ) ? json_decode( $website->trans_update_check, true ) : array();
304 }
305
306 if ( ! is_array( $websitePluginsUpdateCheck ) ) {
307 $websitePluginsUpdateCheck = array();
308 }
309
310 if ( ! is_array( $websiteThemesUpdateCheck ) ) {
311 $websiteThemesUpdateCheck = array();
312 }
313
314 if ( ! is_array( $websiteTransUpdateCheck ) ) {
315 $websiteTransUpdateCheck = array();
316 }
317
318 $updated_status = ! empty( $website->bulk_updates_info ) ? json_decode( $website->bulk_updates_info, true ) : array();
319 if ( ! is_array( $updated_status ) ) {
320 $updated_status = array();
321 }
322
323 MainWP_Logger::instance()->log_events(
324 'debug-updates-crons',
325 'Auto Updates: site: [siteid=' . intval( $website->id ) . '] :: bulk_updates_info :: ' . print_r( // phpcs:ignore -- NOSONAR - debug mode only.
326 $updated_status,
327 true
328 )
329 );
330
331 if ( ! isset( $updated_status['auto_updates_processed'] ) ) {
332 $updated_status['auto_updates_processed'] = $processed_init;
333 }
334
335 $item = array(
336 'id' => $website->id,
337 'name' => $website->name,
338 'url' => $website->url,
339 'current' => isset( $websiteCoreUpgrades['current'] ) ? $websiteCoreUpgrades['current'] : '',
340 'new_version' => isset( $websiteCoreUpgrades['new'] ) ? $websiteCoreUpgrades['new'] : '',
341 );
342
343 if ( ! empty( $website->automatic_update ) && 1 === (int) $website->automatic_update && 1 === (int) $enable_automaticCoreUpdates && isset( $websiteCoreUpgrades['current'] ) && ! $website->is_ignoreCoreUpdates && ! MainWP_Common_Functions::instance()->is_ignored_updates( $item, $websiteIgnoredCores, 'core' ) && ! MainWP_Common_Functions::instance()->is_ignored_updates( $item, $decodedIgnoredCores, 'core' ) ) {
344 $_update_now = false;
345 if ( ! empty( $delay_autoupdate ) ) {
346 if ( empty( $websiteCoreUpdateCheck ) ) {
347 $websiteCoreUpdateCheck = time();
348 } elseif ( ! empty( $websiteCoreUpdateCheck ) && time() > $delay_autoupdate * DAY_IN_SECONDS + intval( $websiteCoreUpdateCheck ) ) {
349 $_update_now = true;
350 }
351 } else {
352 $_update_now = true;
353 }
354
355 if ( $_update_now && ( empty( $updated_status['wp'] ) || empty( $updated_status['wp']['lasttime_error'] ) || ( ! empty( $updated_status['wp']['lasttime_error'] ) && (int) $updated_status['wp']['lasttime_error'] + 6 * HOUR_IN_SECONDS < time() ) ) ) {
356 $coreToUpdateNow[ $website->id ] = $item;
357 ++$found_updates;
358 }
359 }
360
361 $websitePlugins = ! empty( $website->plugin_upgrades ) ? json_decode( $website->plugin_upgrades, true ) : array();
362 $websiteThemes = ! empty( $website->theme_upgrades ) ? json_decode( $website->theme_upgrades, true ) : array();
363 $decodedPremiumUpgrades = ! empty( $website->premium_upgrades ) ? json_decode( $website->premium_upgrades, true ) : array();
364 $websiteTrans = ! empty( $website->translation_upgrades ) ? json_decode( $website->translation_upgrades, true ) : array();
365
366 if ( ! is_array( $websitePlugins ) ) {
367 $websitePlugins = array();
368 }
369
370 if ( ! is_array( $websiteThemes ) ) {
371 $websiteThemes = array();
372 }
373
374 if ( ! is_array( $websiteTrans ) ) {
375 $websiteTrans = array();
376 }
377
378 if ( is_array( $decodedPremiumUpgrades ) ) {
379 foreach ( $decodedPremiumUpgrades as $slug => $premiumUpgrade ) {
380 if ( 'plugin' === $premiumUpgrade['type'] ) {
381 $websitePlugins[ $slug ] = $premiumUpgrade;
382 } elseif ( 'theme' === $premiumUpgrade['type'] ) {
383 $websiteThemes[ $slug ] = $premiumUpgrade;
384 }
385 }
386 }
387
388 if ( 1 === (int) $plugin_automaticDailyUpdate ) {
389 foreach ( $websitePlugins as $pluginSlug => $pluginInfo ) {
390 if ( $website->is_ignorePluginUpdates ) {
391 continue;
392 }
393
394 if ( MainWP_Common_Functions::instance()->is_ignored_updates( $pluginInfo, $decodedIgnoredPlugins, 'plugin' ) || MainWP_Common_Functions::instance()->is_ignored_updates( $pluginInfo, $websiteDecodedIgnoredPlugins, 'plugin' ) ) {
395 continue;
396 }
397
398 $change_log = '';
399 if ( isset( $pluginInfo['update']['url'] ) && ( false !== strpos( $pluginInfo['update']['url'], 'wordpress.org/plugins' ) ) ) {
400 $change_log = $pluginInfo['update']['url'];
401 if ( substr( $change_log, - 1 ) !== '/' ) {
402 $change_log .= '/';
403 }
404 $change_log .= '#developers';
405 }
406
407 $item = array(
408 'id' => $website->id,
409 'name' => $website->name,
410 'url' => $website->url,
411 'plugin' => $pluginInfo['Name'],
412 'current' => $pluginInfo['Version'],
413 'new_version' => $pluginInfo['update']['new_version'],
414 'change_log' => $change_log,
415 );
416 if ( in_array( $pluginSlug, $trustedPlugins ) ) {
417 $_update_now = false;
418 $check_timestamp = isset( $websitePluginsUpdateCheck[ $pluginSlug ] ) ? $websitePluginsUpdateCheck[ $pluginSlug ] : 0;
419 if ( ! empty( $delay_autoupdate ) ) {
420 if ( ! empty( $check_timestamp ) && ( time() > $delay_autoupdate * DAY_IN_SECONDS + intval( $check_timestamp ) ) ) {
421 $_update_now = true;
422 }
423 if ( empty( $check_timestamp ) ) {
424 $websitePluginsUpdateCheck[ $pluginSlug ] = time();
425 }
426 } else {
427 $_update_now = true;
428 }
429 if ( $_update_now && ( ! isset( $updated_status['auto_updates_processed']['plugins'][ $pluginSlug ] ) || ( $item['new_version'] !== $updated_status['auto_updates_processed']['plugins'][ $pluginSlug ]['new_version'] ) ) ) {
430 $pluginsToUpdateNow[ $website->id ][ $pluginSlug ] = $item;
431 ++$found_updates;
432 }
433 }
434 }
435 }
436
437 if ( 1 === (int) $theme_automaticDailyUpdate ) {
438 foreach ( $websiteThemes as $themeSlug => $themeInfo ) {
439
440 if ( $website->is_ignoreThemeUpdates ) {
441 continue;
442 }
443
444 if ( MainWP_Common_Functions::instance()->is_ignored_updates( $themeInfo, $decodedIgnoredThemes, 'theme' ) || MainWP_Common_Functions::instance()->is_ignored_updates( $themeInfo, $websiteDecodedIgnoredThemes, 'theme' ) ) {
445 continue;
446 }
447 $item = array(
448 'id' => $website->id,
449 'name' => $website->name,
450 'url' => $website->url,
451 'theme' => $themeInfo['Name'],
452 'current' => $themeInfo['Version'],
453 'new_version' => $themeInfo['update']['new_version'],
454 'slug' => $themeSlug,
455 );
456
457 if ( in_array( $themeSlug, $trustedThemes ) ) {
458 $_update_now = false;
459
460 $check_timestamp = isset( $websiteThemesUpdateCheck[ $themeSlug ] ) ? $websiteThemesUpdateCheck[ $themeSlug ] : 0;
461 if ( ! empty( $delay_autoupdate ) ) {
462 if ( ! empty( $check_timestamp ) && time() > $delay_autoupdate * DAY_IN_SECONDS + intval( $check_timestamp ) ) {
463 $_update_now = true;
464 }
465 if ( empty( $check_timestamp ) ) {
466 $websiteThemesUpdateCheck[ $themeSlug ] = time();
467 }
468 } else {
469 $_update_now = true;
470 }
471
472 if ( $_update_now && ( ! isset( $updated_status['auto_updates_processed']['themes'][ $themeSlug ] ) || ( $item['new_version'] !== $updated_status['auto_updates_processed']['themes'][ $themeSlug ]['new_version'] ) ) ) {
473 $themesToUpdateNow[ $website->id ][ $themeSlug ] = $item;
474 ++$found_updates;
475 }
476 }
477 }
478 }
479
480 if ( 1 === (int) $tran_automaticDailyUpdate ) {
481 foreach ( $websiteTrans as $transInfo ) {
482
483 $trans_name = isset( $transInfo['name'] ) ? $transInfo['name'] : $transInfo['slug'];
484 $trans_slug = esc_attr( $transInfo['slug'] );
485
486 $item = array(
487 'id' => $website->id,
488 'name' => $website->name,
489 'url' => $website->url,
490 'translation' => $trans_name,
491 'version' => $transInfo['version'],
492 'slug' => $trans_slug,
493 );
494
495 if ( MainWP_Manage_Sites_Update_View::is_trans_trusted_update( $transInfo, $trustedPlugins, $trustedThemes ) ) {
496 $_update_now = false;
497 $check_timestamp = isset( $websiteTransUpdateCheck[ $trans_slug ] ) ? $websiteTransUpdateCheck[ $trans_slug ] : 0;
498 if ( ! empty( $delay_autoupdate ) ) {
499 if ( ! empty( $check_timestamp ) && ( time() > $delay_autoupdate * DAY_IN_SECONDS + intval( $check_timestamp ) ) ) {
500 $_update_now = true;
501 }
502 if ( empty( $check_timestamp ) ) {
503 $websiteTransUpdateCheck[ $trans_slug ] = time();
504 }
505 } else {
506 $_update_now = true;
507 }
508 if ( $_update_now && ( ! isset( $updated_status['auto_updates_processed']['trans'][ $trans_slug ] ) ) ) {
509 $transToUpdateNow[ $website->id ][ $trans_slug ] = $item;
510 ++$found_updates;
511 }
512 }
513 }
514 }
515
516 MainWP_Logger::instance()->log_update_check( 'Automatic found updates :: [siteid=' . $website->id . '] :: [found_updates=' . $found_updates . ']' );
517
518 MainWP_Logger::instance()->log_events( 'auto-updates', 'Auto updates :: found updates :: [siteid=' . $website->id . '] :: [found_updates=' . $found_updates . ']' );
519
520 if ( ! $found_updates ) {
521 $this->finished_site_auto_updates( $website );
522 $finished_updates_sites[] = $website->id;
523 }
524
525 if ( ! empty( $delay_autoupdate ) ) {
526 foreach ( $websitePluginsUpdateCheck as $slug => $check_time ) {
527 if ( ( time() > $check_time + 30 * DAY_IN_SECONDS ) && is_array( $websitePlugins ) && ! empty( $websitePlugins ) && ! isset( $websitePlugins[ $slug ] ) ) {
528 unset( $websitePluginsUpdateCheck[ $slug ] );
529 }
530 }
531
532 foreach ( $websiteThemesUpdateCheck as $slug => $check_time ) {
533 if ( ( time() > $check_time + 30 * DAY_IN_SECONDS ) && is_array( $websiteThemes ) && ! empty( $websiteThemes ) && ! isset( $websiteThemes[ $slug ] ) ) {
534 unset( $websiteThemesUpdateCheck[ $slug ] );
535 }
536 }
537 MainWP_DB::instance()->update_website_option( $website, 'core_update_check', $websiteCoreUpdateCheck );
538 MainWP_DB::instance()->update_website_option( $website, 'plugins_update_check', ( ! empty( $websitePluginsUpdateCheck ) ? wp_json_encode( $websitePluginsUpdateCheck ) : '' ) );
539 MainWP_DB::instance()->update_website_option( $website, 'themes_update_check', ( ! empty( $websiteThemesUpdateCheck ) ? wp_json_encode( $websiteThemesUpdateCheck ) : '' ) );
540 MainWP_DB::instance()->update_website_option( $website, 'trans_update_check', ( ! empty( $websiteTransUpdateCheck ) ? wp_json_encode( $websiteTransUpdateCheck ) : '' ) );
541 } elseif ( ! empty( $websitePluginsUpdateCheck ) || ! empty( $websiteThemesUpdateCheck ) ) {
542 MainWP_DB::instance()->update_website_option( $website, 'core_update_check', 0 );
543 MainWP_DB::instance()->update_website_option( $website, 'plugins_update_check', '' );
544 MainWP_DB::instance()->update_website_option( $website, 'themes_update_check', '' );
545 MainWP_DB::instance()->update_website_option( $website, 'trans_update_check', '' );
546 }
547 }
548
549 // going to retired.
550 if ( get_option( 'mainwp_enableLegacyBackupFeature' ) && get_option( 'mainwp_backup_before_upgrade' ) === 1 ) {
551 $sitesCheckCompleted = get_option( 'mainwp_automaticUpdate_backupChecks' );
552 if ( ! is_array( $sitesCheckCompleted ) ) {
553 $sitesCheckCompleted = array();
554 }
555
556 $websitesToCheck = array();
557
558 if ( 1 === (int) $plugin_automaticDailyUpdate ) {
559 foreach ( $pluginsToUpdateNow as $websiteId => $updates_plugins ) {
560 $websitesToCheck[ $websiteId ] = true;
561 }
562 }
563
564 if ( 1 === (int) $theme_automaticDailyUpdate ) {
565 foreach ( $themesToUpdateNow as $websiteId => $slugs ) {
566 $websitesToCheck[ $websiteId ] = true;
567 }
568 }
569
570 if ( 1 === (int) $enable_automaticCoreUpdates ) {
571 foreach ( $coreToUpdateNow as $websiteId => $info ) {
572 $websitesToCheck[ $websiteId ] = true;
573 }
574 }
575
576 if ( 1 === (int) $tran_automaticDailyUpdate ) {
577 foreach ( $transToUpdateNow as $websiteId => $updates_trans ) {
578 $websitesToCheck[ $websiteId ] = true;
579 }
580 }
581
582 $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
583
584 /**
585 * WordPress files system object.
586 *
587 * @global object
588 */
589 global $wp_filesystem;
590
591 if ( $hasWPFileSystem && ! empty( $wp_filesystem ) ) {
592 foreach ( $websitesToCheck as $siteId => $bool ) {
593 if ( empty( $website->backup_before_upgrade ) ) {
594 $sitesCheckCompleted[ $siteId ] = true;
595 }
596 if ( isset( $sitesCheckCompleted[ $siteId ] ) ) {
597 continue;
598 }
599
600 $dir = MainWP_System_Utility::get_mainwp_specific_dir( $siteId );
601 $dh = opendir( $dir );
602 $lastBackup = - 1;
603 if ( $wp_filesystem->exists( $dir ) && $dh ) {
604 while ( ( $file = readdir( $dh ) ) !== false ) {
605 if ( '.' !== $file && '..' !== $file ) {
606 $theFile = $dir . $file;
607 if ( MainWP_Backup_Handler::is_archive( $file ) && ! MainWP_Backup_Handler::is_sql_archive( $file ) && ( $wp_filesystem->mtime( $theFile ) > $lastBackup ) ) {
608 $lastBackup = $wp_filesystem->mtime( $theFile );
609 }
610 }
611 }
612 closedir( $dh );
613 }
614
615 $mainwp_backup_before_upgrade_days = get_option( 'mainwp_backup_before_upgrade_days' );
616 if ( empty( $mainwp_backup_before_upgrade_days ) || ! ctype_digit( $mainwp_backup_before_upgrade_days ) ) {
617 $mainwp_backup_before_upgrade_days = 7;
618 }
619
620 $backupRequired = ( $lastBackup < ( time() - ( $mainwp_backup_before_upgrade_days * 24 * 60 * 60 ) ) ? true : false );
621
622 if ( ! $backupRequired ) {
623 $sitesCheckCompleted[ $siteId ] = true;
624 MainWP_Utility::update_option( 'mainwp_automaticUpdate_backupChecks', $sitesCheckCompleted );
625 continue;
626 }
627
628 try {
629 $result = MainWP_Backup_Handler::backup( $siteId, 'full', '', '', 0, 0, 0, 0 );
630 MainWP_Backup_Handler::backup_download_file( $siteId, 'full', $result['url'], $result['local'] );
631 $sitesCheckCompleted[ $siteId ] = true;
632 MainWP_Utility::update_option( 'mainwp_automaticUpdate_backupChecks', $sitesCheckCompleted );
633 } catch ( \Exception $e ) {
634 $sitesCheckCompleted[ $siteId ] = false;
635 MainWP_Utility::update_option( 'mainwp_automaticUpdate_backupChecks', $sitesCheckCompleted );
636 }
637 }
638 }
639 } else {
640 $sitesCheckCompleted = null;
641 }
642
643 MainWP_Logger::instance()->log_events(
644 'debug-updates-crons',
645 'Auto Updates: Starting process :: ' . print_r( // phpcs:ignore -- NOSONAR - debug mode only.
646 compact( 'coreToUpdateNow', 'pluginsToUpdateNow', 'themesToUpdateNow', 'transToUpdateNow' ),
647 true
648 )
649 );
650
651 /** Auto updates part. */
652 if ( 1 === (int) $plugin_automaticDailyUpdate ) {
653 foreach ( $pluginsToUpdateNow as $websiteId => $updates_plugins ) {
654 if ( ( null !== $sitesCheckCompleted ) && ( false === $sitesCheckCompleted[ $websiteId ] ) ) {
655 continue;
656 }
657
658 // reload.
659 $updated_status = MainWP_DB::instance()->get_json_website_option( $websiteId, 'bulk_updates_info' );
660 if ( ! is_array( $updated_status ) ) {
661 $updated_status = array();
662 }
663
664 if ( ! isset( $updated_status['auto_updates_processed'] ) ) {
665 $updated_status['auto_updates_processed'] = $processed_init;
666 }
667
668 $slugs = array();
669 foreach ( $updates_plugins as $slug => $info ) {
670 if ( ! isset( $updated_status['auto_updates_processed']['plugins'][ $slug ] ) || ( $info['new_version'] !== $updated_status['auto_updates_processed']['plugins'][ $slug ]['new_version'] ) ) {
671 ++$count_processed_now;
672 $slugs[] = $slug;
673 $updated_status['auto_updates_processed']['plugins'][ $slug ] = $info;
674 if ( $count_processed_now >= $items_limit ) {
675 break;
676 }
677 }
678 }
679
680 MainWP_Logger::instance()->log_update_check( 'Automatic updates plugins now:: [count_slugs=' . count( $slugs ) . ']' );
681
682 if ( ! empty( $slugs ) ) {
683 try {
684
685 MainWP_DB::instance()->update_website_option( $websiteId, 'bulk_updates_info', wp_json_encode( $updated_status ) );
686
687 MainWP_Logger::instance()->log_update_check( 'Automatic updates plugins [siteid=' . $websiteId . '] :: [slugs=' . urldecode( implode( ',', $slugs ) ) . ']' );
688
689 $website = MainWP_DB::instance()->get_website_by_id( $websiteId );
690
691 /**
692 * Action: mainwp_before_plugin_theme_translation_update
693 *
694 * Fires before plugin/theme/translation update actions.
695 *
696 * @since 4.1
697 */
698 do_action( 'mainwp_before_plugin_theme_translation_update', 'plugin', implode( ',', $slugs ), $website );
699
700 $information = MainWP_Connect::fetch_url_authed(
701 $website,
702 'upgradeplugintheme',
703 array(
704 'type' => 'plugin',
705 'list' => urldecode( implode( ',', $slugs ) ),
706 )
707 );
708
709 if ( is_array( $information ) && isset( $information['other_data'] ) ) { // ok.
710 $output_array = $information['other_data']; // updated_data: plugins,themes,trans.
711 mainwp_get_actions_handler_instance()->do_action_mainwp_install_actions( $website, 'updated', $output_array, 'plugin', array(), false, true );
712 }
713
714 $upgrades = '';
715 if ( is_array( $information ) && isset( $information['upgrades'] ) && is_array( $information['upgrades'] ) ) {
716 $upgrades = wp_json_encode( $information['upgrades'] ); // phpcs:ignore -- logging.
717 }
718 MainWP_Logger::instance()->log_update_check( 'Automatic updates plugins [siteid=' . $websiteId . '] :: [upgrades results=' . $upgrades . ']' );
719
720 /**
721 * Action: mainwp_after_plugin_theme_translation_update
722 *
723 * Fires before plugin/theme/translation update actions.
724 *
725 * @since 4.1
726 */
727 do_action( 'mainwp_after_plugin_theme_translation_update', $information, 'plugin', implode( ',', $slugs ), $website );
728 } catch ( \Exception $e ) {
729 // ok.
730 }
731 }
732 }
733 }
734
735 if ( 1 === (int) $theme_automaticDailyUpdate && $count_processed_now < $items_limit ) {
736
737 foreach ( $themesToUpdateNow as $websiteId => $updates_themes ) {
738 if ( ( null !== $sitesCheckCompleted ) && ( false === $sitesCheckCompleted[ $websiteId ] ) ) {
739 continue;
740 }
741
742 // reload.
743 $updated_status = MainWP_DB::instance()->get_json_website_option( $websiteId, 'bulk_updates_info' );
744 if ( ! is_array( $updated_status ) ) {
745 $updated_status = array();
746 }
747
748 if ( ! isset( $updated_status['auto_updates_processed'] ) ) {
749 $updated_status['auto_updates_processed'] = $processed_init;
750 }
751
752 $slugs = array();
753 foreach ( $updates_themes as $slug => $info ) {
754 if ( ! isset( $updated_status['auto_updates_processed']['themes'][ $slug ] ) || ( $info['new_version'] !== $updated_status['auto_updates_processed']['themes'][ $slug ]['new_version'] ) ) {
755 ++$count_processed_now;
756 $slugs[] = $slug;
757 $updated_status['auto_updates_processed']['themes'][ $slug ] = $info;
758 if ( $count_processed_now >= $items_limit ) {
759 break;
760 }
761 }
762 }
763
764 MainWP_Logger::instance()->log_update_check( 'Automatic updates themes now:: [count_slugs=' . count( $slugs ) . ']' );
765
766 if ( ! empty( $slugs ) ) {
767
768 MainWP_DB::instance()->update_website_option( $websiteId, 'bulk_updates_info', wp_json_encode( $updated_status ) );
769
770 MainWP_Logger::instance()->log_update_check( 'Automatic updates theme [siteid=' . $websiteId . '] :: themes :: ' . implode( ',', $slugs ) );
771
772 $website = MainWP_DB::instance()->get_website_by_id( $websiteId );
773
774 /**
775 * Action: mainwp_before_plugin_theme_translation_update
776 *
777 * Fires before plugin/theme/translation update actions.
778 *
779 * @since 4.1
780 */
781 do_action( 'mainwp_before_plugin_theme_translation_update', 'theme', implode( ',', $slugs ), $website );
782
783 try {
784 $information = MainWP_Connect::fetch_url_authed(
785 $website,
786 'upgradeplugintheme',
787 array(
788 'type' => 'theme',
789 'list' => urldecode( implode( ',', $slugs ) ),
790 )
791 );
792
793 if ( is_array( $information ) && isset( $information['other_data'] ) ) { // ok.
794 $output_array = $information['other_data']; // updated_data: plugins,themes,trans.
795 mainwp_get_actions_handler_instance()->do_action_mainwp_install_actions( $website, 'updated', $output_array, 'theme', array(), false, true );
796 }
797 } catch ( \Exception $e ) {
798 // ok.
799 }
800
801 /**
802 * Action: mainwp_after_plugin_theme_translation_update
803 *
804 * Fires before plugin/theme/translation update actions.
805 *
806 * @since 4.1
807 */
808 do_action( 'mainwp_after_plugin_theme_translation_update', $information, 'theme', implode( ',', $slugs ), $website );
809 }
810 }
811 }
812
813 if ( 1 === (int) $tran_automaticDailyUpdate && $count_processed_now < $items_limit ) {
814
815 foreach ( $transToUpdateNow as $websiteId => $updates_trans ) {
816 if ( ( null !== $sitesCheckCompleted ) && ( false === $sitesCheckCompleted[ $websiteId ] ) ) {
817 continue;
818 }
819
820 // reload.
821 $updated_status = MainWP_DB::instance()->get_json_website_option( $websiteId, 'bulk_updates_info' );
822 if ( ! is_array( $updated_status ) ) {
823 $updated_status = array();
824 }
825
826 if ( ! isset( $updated_status['auto_updates_processed'] ) ) {
827 $updated_status['auto_updates_processed'] = $processed_init;
828 }
829
830 $slugs = array();
831 foreach ( $updates_trans as $slug => $info ) {
832 if ( ! isset( $updated_status['auto_updates_processed']['trans'][ $slug ] ) ) {
833 ++$count_processed_now;
834 $slugs[] = $slug;
835 $updated_status['auto_updates_processed']['trans'][ $slug ] = $info;
836 if ( $count_processed_now >= $items_limit ) {
837 break;
838 }
839 }
840 }
841
842 MainWP_Logger::instance()->log_update_check( 'Automatic updates translation now:: [count_slugs=' . count( $slugs ) . ']' );
843
844 if ( ! empty( $slugs ) ) {
845
846 MainWP_DB::instance()->update_website_option( $websiteId, 'bulk_updates_info', wp_json_encode( $updated_status ) );
847
848 MainWP_Logger::instance()->log_update_check( 'Automatic updates translation [siteid=' . $websiteId . '] :: translations :: ' . implode( ',', $slugs ) );
849
850 $website = MainWP_DB::instance()->get_website_by_id( $websiteId );
851
852 /**
853 * Action: mainwp_before_plugin_theme_translation_update
854 *
855 * Fires before plugin/theme/translation update actions.
856 *
857 * @since 4.1
858 */
859 do_action( 'mainwp_before_plugin_theme_translation_update', 'translation', implode( ',', $slugs ), $website );
860
861 try {
862 $information = MainWP_Connect::fetch_url_authed(
863 $website,
864 'upgradetranslation',
865 array(
866 'type' => 'translation',
867 'list' => urldecode( implode( ',', $slugs ) ),
868 )
869 );
870
871 if ( is_array( $information ) && isset( $information['other_data'] ) ) { // ok.
872 $output_array = $information['other_data']; // updated_data: plugins,themes,trans.
873 mainwp_get_actions_handler_instance()->do_action_mainwp_install_actions( $website, 'updated', $output_array, 'trans', array(), false, true );
874 }
875 } catch ( \Exception $e ) {
876 // ok.
877 }
878
879 /**
880 * Action: mainwp_after_plugin_theme_translation_update
881 *
882 * Fires before plugin/theme/translation update actions.
883 *
884 * @since 4.1
885 */
886 do_action( 'mainwp_after_plugin_theme_translation_update', $information, 'translation', implode( ',', $slugs ), $website );
887 }
888 }
889 }
890
891 if ( 1 === (int) $enable_automaticCoreUpdates && $count_processed_now < $items_limit ) {
892 foreach ( $coreToUpdateNow as $websiteId => $info ) {
893 if ( ( null !== $sitesCheckCompleted ) && ( false === $sitesCheckCompleted[ $websiteId ] ) ) {
894 continue;
895 }
896
897 // reload.
898 $updated_status = MainWP_DB::instance()->get_json_website_option( $websiteId, 'bulk_updates_info' );
899 if ( ! is_array( $updated_status ) ) {
900 $updated_status = array();
901 }
902
903 if ( ! isset( $updated_status['auto_updates_processed'] ) ) {
904 $updated_status['auto_updates_processed'] = $processed_init;
905 }
906
907 $updated_status['auto_updates_processed']['wp'] = $info;
908
909 // Clear previous errors before processing.
910 if ( isset( $updated_status['wp']['error'] ) ) {
911 unset( $updated_status['wp']['error'] );
912 }
913
914 if ( isset( $updated_status['wp']['lasttime_error'] ) ) {
915 unset( $updated_status['wp']['lasttime_error'] );
916 }
917
918 MainWP_DB::instance()->update_website_option( $websiteId, 'bulk_updates_info', wp_json_encode( $updated_status ) );
919
920 MainWP_Logger::instance()->log_update_check( 'Automatic updates core [siteid=' . $websiteId . ']' );
921
922 $website = MainWP_DB::instance()->get_website_by_id( $websiteId );
923
924 try {
925 $upgrade_information = MainWP_Connect::fetch_url_authed( $website, 'upgrade' );
926 MainWP_Updates_Handler::activity_log_upgrade( $website, $upgrade_information, true ); // see do_action_mainwp_install_actions for more details about the upgrade: plugins, themes, translation.
927
928 } catch ( \Exception $e ) {
929 $updated_status['wp']['error'] = $e->getMessage();
930 $updated_status['wp']['lasttime_error'] = time();
931 MainWP_DB::instance()->update_website_option( $website, 'bulk_updates_info', wp_json_encode( $updated_status ) );
932 }
933 }
934 }
935
936 MainWP_Logger::instance()->log_events( 'debug-updates-crons', 'Auto updates :: processed count :: ' . $count_processed_now );
937
938 MainWP_Logger::instance()->log_events( 'auto-updates', 'Auto updates :: processed count :: ' . $count_processed_now );
939
940 if ( ! empty( $finished_updates_sites ) ) {
941 foreach ( $finished_updates_sites as $websiteId ) {
942 $updated_status = MainWP_DB::instance()->get_json_website_option( $websiteId, 'bulk_updates_info' );
943 if ( ! is_array( $updated_status ) ) {
944 $updated_status = array();
945 }
946 $updated_status['finished'] = MainWP_Utility::get_timestamp();
947 MainWP_DB::instance()->update_website_option( $websiteId, 'bulk_updates_info', wp_json_encode( $updated_status ) );
948 }
949 }
950 }
951
952
953 /**
954 * Method get_next_auto_updates_timestamp()
955 */
956 public function get_next_auto_updates_timestamp() {
957
958 $time_AutoUpdate = get_option( 'mainwp_time_AutoUpdate' );
959 $dayinweek_AutoUpdate = (int) get_option( 'mainwp_dayinweek_AutoUpdate', 0 );
960 $dayinmonth_AutoUpdate = (int) get_option( 'mainwp_dayinmonth_AutoUpdate', 1 );
961 $frequency_AutoUpdate = get_option( 'mainwp_frequency_AutoUpdate', 'daily' );
962
963 if ( ! in_array( $frequency_AutoUpdate, array( 'daily', 'weekly', 'monthly' ) ) ) {
964 $frequency_AutoUpdate = 'daily';
965 }
966
967 $local_timestamp = MainWP_Utility::get_timestamp();
968 $next_run = 0;
969
970 if ( 'daily' === $frequency_AutoUpdate ) {
971 $next_run = MainWP_System_Cron_Jobs::get_timestamp_from_hh_mm( $time_AutoUpdate );
972 if ( $next_run < $local_timestamp ) {
973 $next_run += DAY_IN_SECONDS;
974 }
975 } elseif ( 'weekly' === $frequency_AutoUpdate ) {
976 $days = array( 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun' );
977 if ( isset( $days[ $dayinweek_AutoUpdate ] ) ) {
978 $day_time = strtotime( 'next ' . $days[ $dayinweek_AutoUpdate ] );
979 $next_run = MainWP_System_Cron_Jobs::get_timestamp_from_hh_mm( $time_AutoUpdate, $day_time );
980 }
981 } elseif ( 'monthly' === $frequency_AutoUpdate ) {
982
983 $today = gmdate( 'd', $local_timestamp );
984 if ( $today < $dayinmonth_AutoUpdate ) {
985 $next_month = gmdate( 'm', $local_timestamp );
986 } else {
987 $next_month = gmdate( 'm', $local_timestamp ) + 1;
988 }
989
990 $next_year = gmdate( 'Y', $local_timestamp );
991
992 if ( $next_month > 12 ) {
993 $next_month = 1;
994 ++$next_year;
995 }
996
997 $last_day = $this->calculate_days_in_month( $next_month, $next_year );
998 if ( $dayinmonth_AutoUpdate > $last_day ) {
999 $dayinmonth_AutoUpdate = $last_day;
1000 }
1001 $next_time = MainWP_System_Cron_Jobs::get_timestamp_from_hh_mm( $time_AutoUpdate );
1002 $hm = explode( ':', gmdate( 'H:i', $next_time ) );
1003 $next_run = mktime( intval( $hm[0] ), intval( $hm[1] ), 1, $next_month, $dayinmonth_AutoUpdate, $next_year );
1004 }
1005
1006 return $next_run;
1007 }
1008
1009
1010 /**
1011 * Method calculate_days_in_month().
1012 *
1013 * @param int $month The month.
1014 * @param int $year The year.
1015 */
1016 public function calculate_days_in_month( $month, $year ) {
1017 if ( function_exists( 'cal_days_in_month' ) ) {
1018 $max_d = cal_days_in_month( CAL_GREGORIAN, $month, $year );
1019 } else {
1020 $max_d = gmdate( 't', mktime( 0, 0, 0, $month, 1, $year ) );
1021 }
1022 return $max_d;
1023 }
1024
1025 /**
1026 * Method set_next_auto_updates_time()
1027 */
1028 public static function set_next_auto_updates_time() {
1029 $next_auto_updates = static::instance()->get_next_auto_updates_timestamp();
1030 if ( $next_auto_updates ) {
1031 MainWP_Utility::update_option( 'mainwp_automatic_update_next_run_timestamp', $next_auto_updates );
1032 }
1033 }
1034
1035
1036 /**
1037 * Method finished_auto_updates()
1038 */
1039 public function finished_auto_updates() {
1040 MainWP_Utility::update_option( 'mainwp_automatic_updates_is_running', 0 );
1041 MainWP_Utility::update_option( 'mainwp_automatic_updates_ready_to_send_notification', 1 );
1042 MainWP_Logger::instance()->log_events( 'auto-updates', 'Auto updates :: ready to send notification' );
1043 }
1044
1045
1046 /**
1047 * Method finished_site_auto_updates()
1048 *
1049 * @param object $website Is individual batch or not.
1050 */
1051 public function finished_site_auto_updates( $website ) {
1052 $websiteValues = array(
1053 'dtsAutomaticSync' => MainWP_Utility::get_timestamp(),
1054 );
1055 MainWP_DB::instance()->update_website_sync_values( $website->id, $websiteValues );
1056 }
1057
1058 /**
1059 * Method log_start_auto_updates()
1060 */
1061 public function log_start_auto_updates() {
1062
1063 // log last run.
1064 $last_run = get_option( 'mainwp_automatic_updates_recent_running' );
1065 if ( $last_run ) {
1066 $last_run = json_decode( $last_run );
1067 }
1068 if ( ! is_array( $last_run ) ) {
1069 $last_run = array();
1070 }
1071 if ( count( $last_run ) > 20 ) {
1072 array_shift( $last_run );
1073 }
1074
1075 $local_timestamp = MainWP_Utility::get_timestamp();
1076 $last_run[] = gmdate( 'Y-m-d H:i:s', $local_timestamp ); //phpcs:ignore -- local time.
1077 MainWP_Utility::update_option( 'mainwp_automatic_updates_recent_running', wp_json_encode( $last_run ) );
1078 }
1079 }
1080