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.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 5.2 All 156 releases
mainwp / class / class-mainwp-cron-jobs-batch.php

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

563 lines 24.1 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_Batch
17 *
18 * @package MainWP\Dashboard
19 */
20 class MainWP_Cron_Jobs_Batch { // 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 * Protected variable to hold User extension.
32 *
33 * @var mixed Default null.
34 */
35 protected $userExtension = null;
36
37 /**
38 * MainWP Cron Instance.
39 *
40 * @return self $instance
41 */
42 public static function instance() {
43 if ( null === static::$instance ) {
44 static::$instance = new self();
45 }
46
47 return static::$instance;
48 }
49
50 /**
51 * Constructor.
52 *
53 * Run each time the class is called.
54 */
55 public function __construct() {
56 if ( null === $this->userExtension ) {
57 $this->userExtension = MainWP_DB_Common::instance()->get_user_extension();
58 }
59 }
60
61
62 /**
63 * Method check_to_run_batch_updates()
64 *
65 * @return mixed results.
66 */
67 public function check_to_run_batch_updates() {
68 $batch_updates_running = get_option( 'mainwp_batch_updates_is_running', 0 );
69 $batch_individual_updates_running = get_option( 'mainwp_batch_individual_updates_is_running', 0 );
70
71 $local_timestamp = MainWP_Utility::get_timestamp();
72
73 if ( $batch_updates_running ) {
74 // check timeout.
75 $start_time = get_option( 'mainwp_batch_updates_start_time', 0 );
76 if ( ! empty( $start_time ) && $local_timestamp > $start_time + 4 * HOUR_IN_SECONDS ) {
77 $batch_updates_running = 0;
78 MainWP_Utility::update_option( 'mainwp_batch_updates_is_running', 0 ); // stop.
79 }
80 }
81
82 if ( $batch_individual_updates_running ) {
83 // check timeout.
84 $start_time = get_option( 'mainwp_batch_updates_individual_start_time', 0 );
85 if ( ! empty( $start_time ) && $local_timestamp > $start_time + 3 * HOUR_IN_SECONDS ) {
86 $batch_individual_updates_running = 0;
87 MainWP_Utility::update_option( 'mainwp_batch_individual_updates_is_running', 0 ); // stop.
88 }
89 }
90
91 // a batch updates running so wait to finish to run auto updates check.
92 if ( $batch_updates_running || $batch_individual_updates_running ) {
93
94 return true;
95 }
96 return false;
97 }
98
99
100 /**
101 * Method handle_cron_batch_updates()
102 *
103 * MainWP Cron batch Update
104 *
105 * This Cron Checks to see if Automatic Daily Updates need to be performed.
106 *
107 * @return mixed result.
108 */
109 public function handle_cron_batch_updates() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity -- NOSONAR Current complexity is the only way to achieve desired results, pull request solutions appreciated.
110
111 $batch_updates_running = get_option( 'mainwp_batch_updates_is_running', 0 );
112 $batch_individual_updates_running = get_option( 'mainwp_batch_individual_updates_is_running', 0 );
113
114 if ( ! $batch_updates_running && ! $batch_individual_updates_running ) {
115 return;
116 }
117
118 $decodedIgnoredCores = ! empty( $this->userExtension->ignored_wp_upgrades ) ? json_decode( $this->userExtension->ignored_wp_upgrades, true ) : array();
119 $decodedIgnoredPlugins = ! empty( $this->userExtension->ignored_plugins ) ? json_decode( $this->userExtension->ignored_plugins, true ) : array();
120 $decodedIgnoredThemes = ! empty( $this->userExtension->ignored_themes ) ? json_decode( $this->userExtension->ignored_themes, true ) : array();
121
122 if ( ! is_array( $decodedIgnoredCores ) ) {
123 $decodedIgnoredCores = array();
124 }
125
126 if ( ! is_array( $decodedIgnoredPlugins ) ) {
127 $decodedIgnoredPlugins = array();
128 }
129 if ( ! is_array( $decodedIgnoredThemes ) ) {
130 $decodedIgnoredThemes = array();
131 }
132
133 $sites_limit = apply_filters( 'mainwp_cron_bulk_update_sites_limit', 3 );
134 $items_limit = apply_filters( 'mainwp_cron_bulk_update_items_limit', 3 );
135
136 $is_individual_batch = false;
137 $websites = array();
138
139 if ( $batch_updates_running ) {
140 $start_time = get_option( 'mainwp_batch_updates_start_time', 0 );
141 $websites = MainWP_Auto_Updates_DB::instance()->get_websites_to_continue_updates( $sites_limit, $start_time, true, true );
142 if ( empty( $websites ) ) {
143 $websites = array();
144 }
145 MainWP_Logger::instance()->log_update_check( 'Batch updates found [websites=' . count( $websites ) . ']' );
146
147 if ( empty( $websites ) ) { // not found general batch updates.
148 $this->finished_batch_updates();
149 }
150 }
151
152 // if empty general batch updates, check individaul batch updates.
153 if ( empty( $websites ) && $batch_individual_updates_running ) {
154 $start_time = get_option( 'mainwp_batch_updates_individual_start_time', 0 );
155 $websites = MainWP_Auto_Updates_DB::instance()->get_websites_to_continue_individual_updates( $sites_limit, $start_time );
156 if ( empty( $websites ) ) {
157 $websites = array();
158 }
159 MainWP_Logger::instance()->log_update_check( 'Batch individual updates found [' . count( $websites ) . ' websites]' );
160
161 if ( empty( $websites ) ) {
162 $this->finished_batch_updates( true );
163 return;
164 }
165 $is_individual_batch = true;
166 }
167
168 foreach ( $websites as $website ) {
169 $updated_status = MainWP_DB::instance()->get_json_website_option( $website, 'bulk_updates_info' );
170 if ( ! is_array( $updated_status ) ) {
171 $updated_status = array();
172 }
173 if ( ! isset( $updated_status['updates_processed'] ) ) {
174 $updated_status['updates_processed'] = array(
175 'wp' => array(),
176 'plugins' => array(),
177 'themes' => array(),
178 );
179 }
180 $pluginsToUpdateNow = array();
181 $themesToUpdateNow = array();
182
183 $coreToUpdate = MainWP_DB::instance()->get_json_website_option( $website, 'bulk_wp_upgrades' );
184 $pluginsToUpdate = MainWP_DB::instance()->get_json_website_option( $website, 'bulk_plugin_upgrades' );
185 $themesToUpdate = MainWP_DB::instance()->get_json_website_option( $website, 'bulk_theme_upgrades' );
186
187 // check ignored settings again.
188 if ( $website->is_ignoreCoreUpdates ) {
189 $coreToUpdate = array();
190 MainWP_DB::instance()->update_website_option( $website, 'bulk_wp_upgrades', wp_json_encode( array() ) );
191 }
192
193 if ( $website->is_ignorePluginUpdates ) {
194 $pluginsToUpdate = array();
195 MainWP_DB::instance()->update_website_option( $website, 'bulk_plugin_upgrades', wp_json_encode( array() ) );
196 }
197
198 if ( $website->is_ignoreThemeUpdates ) {
199 $themesToUpdate = array();
200 MainWP_DB::instance()->update_website_option( $website, 'bulk_theme_upgrades', wp_json_encode( array() ) );
201 }
202
203 if ( ! is_array( $coreToUpdate ) ) {
204 $coreToUpdate = array();
205 }
206
207 if ( ! is_array( $pluginsToUpdate ) ) {
208 $pluginsToUpdate = array();
209 }
210
211 if ( ! is_array( $themesToUpdate ) ) {
212 $themesToUpdate = array();
213 }
214
215 $websiteDecodedIgnoredPlugins = json_decode( $website->ignored_plugins, true );
216 if ( ! is_array( $websiteDecodedIgnoredPlugins ) ) {
217 $websiteDecodedIgnoredPlugins = array();
218 }
219
220 $websiteDecodedIgnoredThemes = json_decode( $website->ignored_themes, true );
221 if ( ! is_array( $websiteDecodedIgnoredThemes ) ) {
222 $websiteDecodedIgnoredThemes = array();
223 }
224
225 $websiteDecodedIgnoredCores = ! empty( $website->ignored_wp_upgrades ) ? json_decode( $website->ignored_wp_upgrades, true ) : array();
226 if ( ! is_array( $websiteDecodedIgnoredCores ) ) {
227 $websiteDecodedIgnoredCores = array();
228 }
229
230 $count_processed_now = 0;
231
232 foreach ( $pluginsToUpdate as $slug => $info ) {
233 if ( ! is_array( $info ) ) {
234 continue;
235 }
236 if ( ! isset( $updated_status['updates_processed']['plugins'][ $slug ] ) ) {
237 $ignored = MainWP_Common_Functions::instance()->is_ignored_updates( $info, $decodedIgnoredPlugins, 'plugin' ) || MainWP_Common_Functions::instance()->is_ignored_updates( $info, $websiteDecodedIgnoredPlugins, 'plugin' );
238 if ( $ignored ) {
239 $info['ignored'] = 1;
240 }
241 $updated_status['updates_processed']['plugins'][ $slug ] = $info;
242
243 if ( ! $ignored ) {
244 ++$count_processed_now;
245 $pluginsToUpdateNow[] = $slug;
246 if ( $count_processed_now >= $items_limit ) {
247 break;
248 }
249 }
250 }
251 }
252
253 if ( ! empty( $pluginsToUpdateNow ) ) {
254 MainWP_DB::instance()->update_website_option( $website, 'bulk_updates_info', wp_json_encode( $updated_status ) );
255 try {
256 MainWP_Logger::instance()->log_update_check( 'Batch updates plugins [websiteid=' . $website->id . '] :: [slugs=' . urldecode( implode( ',', $pluginsToUpdateNow ) ) . ']' );
257 /**
258 * Action: mainwp_before_plugin_theme_translation_update
259 *
260 * Fires before plugin/theme/translation update actions.
261 *
262 * @since 4.1
263 */
264 do_action( 'mainwp_before_plugin_theme_translation_update', 'plugin', implode( ',', $pluginsToUpdateNow ), $website );
265 $information = MainWP_Connect::fetch_url_authed(
266 $website,
267 'upgradeplugintheme',
268 array(
269 'type' => 'plugin',
270 'list' => urldecode( implode( ',', $pluginsToUpdateNow ) ),
271 )
272 );
273 $upgrades = '';
274 if ( is_array( $information ) && isset( $information['upgrades'] ) && is_array( $information['upgrades'] ) ) {
275 $upgrades = wp_json_encode( $information['upgrades'], true ); // phpcs:ignore -- logging.
276 }
277 MainWP_Logger::instance()->log_update_check( 'Batch updates plugins [upgrades result=' . $upgrades . ']' );
278
279 /**
280 * Action: mainwp_after_plugin_theme_translation_update
281 *
282 * Fires before plugin/theme/translation update actions.
283 *
284 * @since 4.1
285 */
286 do_action( 'mainwp_after_plugin_theme_translation_update', $information, 'plugin', implode( ',', $pluginsToUpdateNow ), $website );
287 } catch ( \Exception $e ) {
288 // error.
289 }
290 }
291
292 // batch processing limits.
293 if ( $count_processed_now < $items_limit ) {
294 foreach ( $themesToUpdate as $slug => $info ) {
295 if ( ! is_array( $info ) ) {
296 continue;
297 }
298 if ( ! isset( $updated_status['updates_processed']['themes'][ $slug ] ) ) {
299 $ignored = MainWP_Common_Functions::instance()->is_ignored_updates( $info, $decodedIgnoredThemes, 'theme' ) || MainWP_Common_Functions::instance()->is_ignored_updates( $info, $websiteDecodedIgnoredThemes, 'theme' );
300 if ( $ignored ) {
301 $info['ignored'] = 1;
302 }
303 $updated_status['updates_processed']['themes'][ $slug ] = $info;
304 if ( ! $ignored ) {
305 ++$count_processed_now;
306 $themesToUpdateNow[] = $slug;
307 if ( $count_processed_now >= $items_limit ) {
308 break;
309 }
310 }
311 }
312 }
313
314 if ( ! empty( $themesToUpdateNow ) ) {
315 MainWP_DB::instance()->update_website_option( $website, 'bulk_updates_info', wp_json_encode( $updated_status ) );
316 MainWP_Logger::instance()->log_update_check( 'Batch updates themes [websiteid=' . $website->id . '] :: [slugs=' . implode( ',', $themesToUpdateNow ) . ']' );
317 /**
318 * Action: mainwp_before_plugin_theme_translation_update
319 *
320 * Fires before plugin/theme/translation update actions.
321 *
322 * @since 4.1
323 */
324 do_action( 'mainwp_before_plugin_theme_translation_update', 'theme', implode( ',', $themesToUpdateNow ), $website );
325
326 try {
327
328 $information = MainWP_Connect::fetch_url_authed(
329 $website,
330 'upgradeplugintheme',
331 array(
332 'type' => 'theme',
333 'list' => urldecode( implode( ',', $themesToUpdateNow ) ),
334 )
335 );
336 } catch ( \Exception $e ) {
337 // ok.
338 }
339
340 /**
341 * Action: mainwp_after_plugin_theme_translation_update
342 *
343 * Fires before plugin/theme/translation update actions.
344 *
345 * @since 4.1
346 */
347 do_action( 'mainwp_after_plugin_theme_translation_update', $information, 'theme', implode( ',', $themesToUpdateNow ), $website );
348 }
349 }
350
351 // batch processing limits.
352 if ( $count_processed_now < $items_limit && ! empty( $coreToUpdate ) ) {
353
354 $info = $coreToUpdate;
355
356 $ignored = MainWP_Common_Functions::instance()->is_ignored_updates( $coreToUpdate, $decodedIgnoredCores, 'core' ) || MainWP_Common_Functions::instance()->is_ignored_updates( $coreToUpdate, $websiteDecodedIgnoredCores, 'core' );
357
358 if ( $ignored ) {
359 $info['ignored'] = 1;
360 }
361
362 $updated_status['updates_processed']['wp'] = $info;
363
364 // Clear previous errors before processing.
365 if ( isset( $updated_status['wp']['error'] ) ) {
366 unset( $updated_status['wp']['error'] );
367 }
368
369 if ( isset( $updated_status['wp']['lasttime_error'] ) ) {
370 unset( $updated_status['wp']['lasttime_error'] );
371 }
372
373 if ( ! $ignored ) {
374 ++$count_processed_now;
375 MainWP_DB::instance()->update_website_option( $website, 'bulk_updates_info', wp_json_encode( $updated_status ) );
376 MainWP_Logger::instance()->log_update_check( 'Batch updates core [websiteid=' . $website->id . ']' );
377 try {
378 MainWP_Connect::fetch_url_authed( $website, 'upgrade' );
379 } catch ( \Exception $e ) {
380 $updated_status['wp']['error'] = $e->getMessage();
381 $updated_status['wp']['lasttime_error'] = time();
382 MainWP_DB::instance()->update_website_option( $website, 'bulk_updates_info', wp_json_encode( $updated_status ) );
383 }
384 }
385 }
386 MainWP_Logger::instance()->log_update_check( 'Batch updates now [websiteid=' . $website->id . '] :: [update now count=' . $count_processed_now . ']' );
387
388 if ( $count_processed_now < $items_limit ) {
389 $this->finished_site_batch_updates( $website, $is_individual_batch );
390 }
391 }
392 }
393
394 /**
395 * Method finished_batch_updates()
396 *
397 * @param bool $individual_batch Is individual batch or not.
398 */
399 public function finished_batch_updates( $individual_batch = false ) {
400 if ( $individual_batch ) {
401 MainWP_Logger::instance()->log_update_check( 'Batch individual updates finished' );
402 MainWP_Utility::update_option( 'mainwp_batch_individual_updates_is_running', 0 ); // individual batch updates done.
403 } else {
404 MainWP_Logger::instance()->log_update_check( 'Batch updates finished' );
405 MainWP_Utility::update_option( 'mainwp_batch_updates_is_running', 0 ); // general batch updates done.
406 }
407 }
408
409
410 /**
411 * Method finished_site_batch_updates()
412 *
413 * @param object $website Is individual batch or not.
414 * @param bool $individual_batch Is individual batch or not.
415 */
416 public function finished_site_batch_updates( $website, $individual_batch = false ) {
417 if ( $individual_batch ) {
418 MainWP_DB::instance()->update_website_option( $website, 'batch_individual_queue_time', 0 ); // individual batch site items done.
419 } else {
420 $websiteValues = array(
421 'dtsAutomaticSync' => MainWP_Utility::get_timestamp(),
422 );
423 MainWP_DB::instance()->update_website_sync_values( $website->id, $websiteValues );
424 }
425 }
426
427 /**
428 * Method prepare_bulk_updates().
429 *
430 * @param object $website website.
431 */
432 public function prepare_bulk_updates( $website ) { //phpcs:ignore -- NOSONAR - complex.
433
434 $decodedIgnoredCores = ! empty( $this->userExtension->ignored_wp_upgrades ) ? json_decode( $this->userExtension->ignored_wp_upgrades, true ) : array();
435 $decodedIgnoredPlugins = ! empty( $this->userExtension->ignored_plugins ) ? json_decode( $this->userExtension->ignored_plugins, true ) : array();
436 $decodedIgnoredThemes = ! empty( $this->userExtension->ignored_themes ) ? json_decode( $this->userExtension->ignored_themes, true ) : array();
437
438 if ( ! is_array( $decodedIgnoredCores ) ) {
439 $decodedIgnoredCores = array();
440 }
441
442 if ( ! is_array( $decodedIgnoredPlugins ) ) {
443 $decodedIgnoredPlugins = array();
444 }
445
446 if ( ! is_array( $decodedIgnoredThemes ) ) {
447 $decodedIgnoredThemes = array();
448 }
449
450 $coreToUpdate = array();
451 $pluginsToUpdate = array();
452 $themesToUpdate = array();
453
454 $websiteDecodedIgnoredCores = ! empty( $website->ignored_wp_upgrades ) ? json_decode( $website->ignored_wp_upgrades, true ) : array();
455 $websiteDecodedIgnoredPlugins = json_decode( $website->ignored_plugins, true );
456 $websiteDecodedIgnoredThemes = json_decode( $website->ignored_themes, true );
457
458 if ( ! is_array( $websiteDecodedIgnoredCores ) ) {
459 $websiteDecodedIgnoredCores = array();
460 }
461
462 if ( ! is_array( $websiteDecodedIgnoredPlugins ) ) {
463 $websiteDecodedIgnoredPlugins = array();
464 }
465
466 if ( ! is_array( $websiteDecodedIgnoredThemes ) ) {
467 $websiteDecodedIgnoredThemes = array();
468 }
469
470 $websiteCoreUpgrades = ! empty( $website->wp_upgrades ) ? json_decode( $website->wp_upgrades, true ) : array();
471 if ( ! is_array( $websiteCoreUpgrades ) ) {
472 $websiteCoreUpgrades = array();
473 }
474
475 if ( isset( $websiteCoreUpgrades['current'] ) && ! $website->is_ignoreCoreUpdates && ! MainWP_Common_Functions::instance()->is_ignored_updates( $websiteCoreUpgrades, $websiteDecodedIgnoredCores, 'core' ) && ! MainWP_Common_Functions::instance()->is_ignored_updates( $websiteCoreUpgrades, $decodedIgnoredCores, 'core' ) ) {
476 $item = array(
477 'current' => $websiteCoreUpgrades['current'],
478 'new_version' => $websiteCoreUpgrades['new'],
479 );
480 $coreToUpdate[] = $item;
481 }
482
483 $websitePlugins = json_decode( $website->plugin_upgrades, true );
484 $websiteThemes = json_decode( $website->theme_upgrades, true );
485 $decodedPremiumUpgrades = ! empty( $website->premium_upgrades ) ? json_decode( $website->premium_upgrades, true ) : array();
486
487 if ( is_array( $decodedPremiumUpgrades ) ) {
488 foreach ( $decodedPremiumUpgrades as $slug => $premiumUpgrade ) {
489 if ( 'plugin' === $premiumUpgrade['type'] ) {
490 if ( ! is_array( $websitePlugins ) ) {
491 $websitePlugins = array();
492 }
493 $websitePlugins[ $slug ] = $premiumUpgrade;
494 } elseif ( 'theme' === $premiumUpgrade['type'] ) {
495 if ( ! is_array( $websiteThemes ) ) {
496 $websiteThemes = array();
497 }
498 $websiteThemes[ $slug ] = $premiumUpgrade;
499 }
500 }
501 }
502
503 foreach ( $websitePlugins as $pluginSlug => $pluginInfo ) {
504 if ( $website->is_ignorePluginUpdates ) {
505 continue;
506 }
507 if ( MainWP_Common_Functions::instance()->is_ignored_updates( $pluginInfo, $decodedIgnoredPlugins, 'plugin' ) || MainWP_Common_Functions::instance()->is_ignored_updates( $pluginInfo, $websiteDecodedIgnoredPlugins, 'plugin' ) ) {
508 continue;
509 }
510
511 $change_log = '';
512 if ( isset( $pluginInfo['update']['url'] ) && ( false !== strpos( $pluginInfo['update']['url'], 'wordpress.org/plugins' ) ) ) {
513 $change_log = $pluginInfo['update']['url'];
514 if ( substr( $change_log, - 1 ) !== '/' ) {
515 $change_log .= '/';
516 }
517 $change_log .= '#developers';
518 }
519
520 $item = array(
521 'slug' => $pluginSlug,
522 'plugin' => $pluginInfo['Name'],
523 'current' => $pluginInfo['Version'],
524 'new_version' => $pluginInfo['update']['new_version'],
525 'change_log' => $change_log,
526 );
527
528 $pluginsToUpdate[ $pluginSlug ] = $item;
529 }
530
531 foreach ( $websiteThemes as $themeSlug => $themeInfo ) {
532 if ( $website->is_ignoreThemeUpdates ) {
533 continue;
534 }
535 if ( MainWP_Common_Functions::instance()->is_ignored_updates( $themeInfo, $decodedIgnoredThemes, 'theme' ) || MainWP_Common_Functions::instance()->is_ignored_updates( $themeInfo, $websiteDecodedIgnoredThemes, 'theme' ) ) {
536 continue;
537 }
538 $item = array(
539 'slug' => $themeSlug,
540 'theme' => $themeInfo['Name'],
541 'current' => $themeInfo['Version'],
542 'new_version' => $themeInfo['update']['new_version'],
543 );
544 $themesToUpdate[ $themeSlug ] = $item;
545 }
546
547 MainWP_DB::instance()->update_website_option( $website, 'bulk_wp_upgrades', wp_json_encode( $coreToUpdate ) );
548 MainWP_DB::instance()->update_website_option( $website, 'bulk_plugin_upgrades', wp_json_encode( $pluginsToUpdate ) );
549 MainWP_DB::instance()->update_website_option( $website, 'bulk_theme_upgrades', wp_json_encode( $themesToUpdate ) );
550 $total_updates = count( $coreToUpdate ) + count( $pluginsToUpdate ) + count( $themesToUpdate );
551 MainWP_DB::instance()->update_website_option(
552 $website,
553 'bulk_updates_info',
554 wp_json_encode(
555 array(
556 'total' => $total_updates,
557 'start_time' => MainWP_Utility::get_timestamp(),
558 )
559 )
560 );
561 }
562 }
563