PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / team-updraft / lib-central / central / modules / updates.php

updates.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at vendor/team-updraft/lib-central/central/modules/updates.php

1,029 lines 35.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
4
5 class UpdraftCentral_Updates_Commands extends UpdraftCentral_Commands {
6
7 public function do_updates($updates) {
8
9 if (!is_array($updates)) $this->_generic_error_response('invalid_data');
10
11 if (!empty($updates['plugins']) && !current_user_can('update_plugins')) return $this->_generic_error_response('updates_permission_denied', 'update_plugins');
12
13 if (!empty($updates['themes']) && !current_user_can('update_themes')) return $this->_generic_error_response('updates_permission_denied', 'update_themes');
14
15 if (!empty($updates['core']) && !current_user_can('update_core')) return $this->_generic_error_response('updates_permission_denied', 'update_core');
16
17 if (!empty($updates['translations']) && !$this->user_can_update_translations()) return $this->_generic_error_response('updates_permission_denied', 'update_translations');
18
19 $this->_admin_include('plugin.php', 'update.php', 'file.php', 'template.php');
20 $this->_frontend_include('update.php');
21
22 if (!empty($updates['meta']) && isset($updates['meta']['filesystem_credentials'])) {
23 parse_str($updates['meta']['filesystem_credentials'], $filesystem_credentials);
24 if (is_array($filesystem_credentials)) {
25 foreach ($filesystem_credentials as $key => $value) {
26 // Put them into $_POST, which is where request_filesystem_credentials() checks for them.
27 $_POST[$key] = $value;
28 }
29 }
30 }
31
32 $plugins = empty($updates['plugins']) ? array() : $updates['plugins'];
33 $plugin_updates = array();
34 foreach ($plugins as $plugin_info) {
35 $plugin_updates[] = $this->_update_plugin($plugin_info['plugin'], $plugin_info['slug']);
36 }
37
38 $themes = empty($updates['themes']) ? array() : $updates['themes'];
39 $theme_updates = array();
40 foreach ($themes as $theme_info) {
41 $theme = $theme_info['theme'];
42 $theme_updates[] = $this->_update_theme($theme);
43 }
44
45 $cores = empty($updates['core']) ? array() : $updates['core'];
46 $core_updates = array();
47 foreach ($cores as $core) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- We dont use $core but we need the AS in the foreach so it needs to stay
48 $core_updates[] = $this->_update_core(null);
49 // Only one (and always we go to the latest version) - i.e. we ignore the passed parameters
50 break;
51 }
52
53 $translation_updates = array();
54 if (!empty($updates['translations'])) {
55 $translation_updates[] = $this->_update_translation();
56 }
57
58 return $this->_response(array(
59 'plugins' => $plugin_updates,
60 'themes' => $theme_updates,
61 'core' => $core_updates,
62 'translations' => $translation_updates,
63 ));
64
65 }
66
67 /**
68 * Updates a plugin. A facade method that exposes a private updates
69 * feature for other modules to consume.
70 *
71 * @param string $plugin Specific plugin to be updated
72 * @param string $slug Unique key passed for updates
73 *
74 * @return array
75 */
76 public function update_plugin($plugin, $slug) {
77 return $this->_update_plugin($plugin, $slug);
78 }
79
80 /**
81 * Updates a theme. A facade method that exposes a private updates
82 * feature for other modules to consume.
83 *
84 * @param string $theme Specific theme to be updated
85 *
86 * @return array
87 */
88 public function update_theme($theme) {
89 return $this->_update_theme($theme);
90 }
91
92 /**
93 * Gets available updates for a certain entity (e.g. plugin or theme). A facade method that
94 * exposes a private updates feature for other modules to consume.
95 *
96 * @param string $entity The name of the entity that this request is intended for (e.g. themes or plugins)
97 *
98 * @return array
99 */
100 public function get_item_updates($entity) {
101 $updates = array();
102 switch ($entity) {
103 case 'themes':
104 wp_update_themes();
105 $updates = $this->maybe_add_third_party_items(get_theme_updates(), 'theme');
106 break;
107 case 'plugins':
108 wp_update_plugins();
109 $updates = $this->maybe_add_third_party_items(get_plugin_updates(), 'plugin');
110 break;
111 }
112
113 return $updates;
114 }
115
116 /**
117 * Mostly from wp_ajax_update_plugin() in wp-admin/includes/ajax-actions.php (WP 4.5.2)
118 * Code-formatting style has been retained from the original, for ease of comparison/updating
119 *
120 * @param string $plugin Specific plugin to be updated
121 * @param string $slug Unique key passed for updates
122 * @return array
123 */
124 private function _update_plugin($plugin, $slug) {
125
126 $status = array(
127 'update' => 'plugin',
128 'plugin' => $plugin,
129 'slug' => sanitize_key($slug),
130 'oldVersion' => '',
131 'newVersion' => '',
132 );
133
134 if (false !== strpos($plugin, '..') || false !== strpos($plugin, ':') || !preg_match('#^[^\/]#i', $plugin)) {
135 $status['error'] = 'not_found';
136 return $status;
137 }
138
139 $plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin);
140 if (!isset($plugin_data['Name']) || !isset($plugin_data['Author']) || ('' == $plugin_data['Name'] && '' == $plugin_data['Author'])) {
141 $status['error'] = 'not_found';
142 return $status;
143 }
144
145 if ($plugin_data['Version']) {
146 $status['oldVersion'] = $plugin_data['Version'];
147 }
148
149 if (!current_user_can('update_plugins')) {
150 $status['error'] = 'updates_permission_denied';
151 return $status;
152 }
153
154 include_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
155
156 wp_update_plugins();
157
158 // WP < 3.7
159 if (!class_exists('Automatic_Upgrader_Skin')) include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/classes/class-automatic-upgrader-skin.php');
160
161 $skin = new Automatic_Upgrader_Skin();
162 $upgrader = new Plugin_Upgrader($skin);
163 $result = $upgrader->bulk_upgrade(array($plugin));
164
165 if (is_array($result) && empty($result[$plugin]) && is_wp_error($skin->result)) {
166 $result = $skin->result;
167 }
168
169 $status['messages'] = $upgrader->skin->get_upgrade_messages();
170
171 if (is_array($result) && !empty($result[$plugin])) {
172 $plugin_update_data = current($result);
173
174 /*
175 * If the `update_plugins` site transient is empty (e.g. when you update
176 * two plugins in quick succession before the transient repopulates),
177 * this may be the return.
178 *
179 * Preferably something can be done to ensure `update_plugins` isn't empty.
180 * For now, surface some sort of error here.
181 */
182 if (true === $plugin_update_data) {
183 $status['error'] = 'update_failed';
184 return $status;
185 }
186
187 if (is_wp_error($result[$plugin])) {
188 $status['error'] = $result[$plugin]->get_error_code();
189 $status['error_message'] = $result[$plugin]->get_error_message();
190 return $status;
191 }
192
193 $plugin_data = get_plugins('/' . $result[$plugin]['destination_name']);
194 $plugin_data = reset($plugin_data);
195
196 if ($plugin_data['Version']) {
197 $status['newVersion'] = $plugin_data['Version'];
198 }
199 return $status;
200
201 } elseif (is_wp_error($result)) {
202 $status['error'] = $result->get_error_code();
203 $status['error_message'] = $result->get_error_message();
204 return $status;
205
206 } elseif (is_bool($result) && !$result) {
207 $status['error'] = 'unable_to_connect_to_filesystem';
208
209 global $wp_filesystem;
210
211 // Pass through the error from WP_Filesystem if one was raised
212 if (isset($wp_filesystem->errors) && is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
213 $status['error'] = $wp_filesystem->errors->get_error_code();
214 $status['error_message'] = $wp_filesystem->errors->get_error_message();
215 }
216
217 return $status;
218
219 } else {
220 // An unhandled error occurred
221 $status['error'] = 'update_failed';
222 return $status;
223 }
224 }
225
226 /**
227 * Adapted from _update_theme (above)
228 *
229 * @param string $core
230 * @return array
231 */
232 private function _update_core($core) {
233
234 global $wp_filesystem;
235
236 $status = array(
237 'update' => 'core',
238 'core' => $core,
239 'oldVersion' => '',
240 'newVersion' => '',
241 );
242
243 // THis is included so we can get $wp_version
244 include(ABSPATH.WPINC.'/version.php');
245
246 $status['oldVersion'] = $wp_version;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
247
248 if (!current_user_can('update_core')) {
249 $status['error'] = 'updates_permission_denied';
250 return $status;
251 }
252
253 include_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
254
255 wp_version_check();
256
257 $locale = get_locale();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused variable is for future use.
258
259 $core_update_key = false;
260 $core_update_latest_version = false;
261
262 $get_core_updates = get_core_updates();
263
264 // THis is included so we can get $wp_version
265 @include(ABSPATH.WPINC.'/version.php');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
266
267 foreach ($get_core_updates as $k => $core_update) {
268 if (isset($core_update->version) && version_compare($core_update->version, $wp_version, '>') && version_compare($core_update->version, $core_update_latest_version, '>')) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
269 $core_update_latest_version = $core_update->version;
270 $core_update_key = $k;
271 }
272 }
273
274 if (false === $core_update_key) {
275 $status['error'] = 'no_update_found';
276 return $status;
277 }
278
279 $update = $get_core_updates[$core_update_key];
280
281 // WP < 3.7
282 if (!class_exists('Automatic_Upgrader_Skin')) include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/classes/class-automatic-upgrader-skin.php');
283
284 $skin = new Automatic_Upgrader_Skin();
285 $upgrader = new Core_Upgrader($skin);
286
287 $result = $upgrader->upgrade($update);
288
289 $status['messages'] = $upgrader->skin->get_upgrade_messages();
290
291 if (is_wp_error($result)) {
292 $status['error'] = $result->get_error_code();
293 $status['error_message'] = $result->get_error_message();
294 return $status;
295
296 } elseif (is_bool($result) && !$result) {
297 $status['error'] = 'unable_to_connect_to_filesystem';
298
299 // Pass through the error from WP_Filesystem if one was raised
300 if (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
301 $status['error'] = $wp_filesystem->errors->get_error_code();
302 $status['error_message'] = $wp_filesystem->errors->get_error_message();
303 }
304
305 return $status;
306
307
308 } elseif (preg_match('/^[0-9]/', $result)) {
309
310 $status['newVersion'] = $result;
311
312 return $status;
313
314 } else {
315 // An unhandled error occurred
316 $status['error'] = 'update_failed';
317 return $status;
318 }
319
320 }
321
322 private function _update_theme($theme) {
323
324 global $wp_filesystem;
325
326 $status = array(
327 'update' => 'theme',
328 'theme' => $theme,
329 'oldVersion' => '',
330 'newVersion' => '',
331 );
332
333 if (false !== strpos($theme, '/') || false !== strpos($theme, '\\')) {
334 $status['error'] = 'not_found';
335 return $status;
336 }
337
338 $theme_version = $this->get_theme_version($theme);
339 if (false === $theme_version) {
340 $status['error'] = 'not_found';
341 return $status;
342 }
343 $status['oldVersion'] = $theme_version;
344
345 if (!current_user_can('update_themes')) {
346 $status['error'] = 'updates_permission_denied';
347 return $status;
348 }
349
350 include_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
351
352 wp_update_themes();
353
354 // WP < 3.7
355 if (!class_exists('Automatic_Upgrader_Skin')) include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/classes/class-automatic-upgrader-skin.php');
356
357 $skin = new Automatic_Upgrader_Skin();
358 $upgrader = new Theme_Upgrader($skin);
359 $upgrader->init();
360 $result = $upgrader->bulk_upgrade(array($theme));
361
362 if (is_array($result) && empty($result[$theme]) && is_wp_error($skin->result)) {
363 $result = $skin->result;
364 }
365
366 $status['messages'] = $upgrader->skin->get_upgrade_messages();
367
368 if (is_array($result) && !empty($result[$theme])) {
369 $theme_update_data = current($result);
370
371 /*
372 * If the `update_themes` site transient is empty (e.g. when you update
373 * two plugins in quick succession before the transient repopulates),
374 * this may be the return.
375 *
376 * Preferably something can be done to ensure `update_themes` isn't empty.
377 * For now, surface some sort of error here.
378 */
379 if (true === $theme_update_data) {
380 $status['error'] = 'update_failed';
381 return $status;
382 }
383
384 $new_theme_version = $this->get_theme_version($theme);
385 if (false === $new_theme_version) {
386 $status['error'] = 'update_failed';
387 return $status;
388 }
389
390 $status['newVersion'] = $new_theme_version;
391
392 return $status;
393
394 } elseif (is_wp_error($result)) {
395 $status['error'] = $result->get_error_code();
396 $status['error_message'] = $result->get_error_message();
397 return $status;
398
399 } elseif (is_bool($result) && !$result) {
400 $status['error'] = 'unable_to_connect_to_filesystem';
401
402 // Pass through the error from WP_Filesystem if one was raised
403 if (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
404 $status['error'] = $wp_filesystem->errors->get_error_code();
405 $status['error_message'] = $wp_filesystem->errors->get_error_message();
406 }
407
408 return $status;
409
410 } else {
411 // An unhandled error occurred
412 $status['error'] = 'update_failed';
413 return $status;
414 }
415
416 }
417
418 /**
419 * Updates available translations for this website
420 *
421 * @return Array
422 */
423 private function _update_translation() {
424 global $wp_filesystem;
425
426 $status = array();
427
428 include_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
429 if (!class_exists('Automatic_Upgrader_Skin')) include_once(UPDRAFTCENTRAL_CLIENT_DIR.'/classes/class-automatic-upgrader-skin.php');
430
431 $skin = new Automatic_Upgrader_Skin();
432 $upgrader = new Language_Pack_Upgrader($skin);
433 $result = $upgrader->bulk_upgrade();
434
435 if (is_array($result) && !empty($result)) {
436 $status['success'] = true;
437 } elseif (is_wp_error($result)) {
438 $status['error'] = $result->get_error_code();
439 $status['error_message'] = $result->get_error_message();
440 } elseif (is_bool($result) && !$result) {
441 $status['error'] = 'unable_to_connect_to_filesystem';
442
443 // Pass through the error from WP_Filesystem if one was raised
444 if (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
445 $status['error'] = $wp_filesystem->errors->get_error_code();
446 $status['error_message'] = $wp_filesystem->errors->get_error_message();
447 }
448 } elseif (is_bool($result) && $result) {
449 $status['error'] = 'up_to_date';
450 } else {
451 // An unhandled error occurred
452 $status['error'] = 'update_failed';
453 }
454
455 return $status;
456 }
457
458 private function get_theme_version($theme) {
459
460 if (function_exists('wp_get_theme')) {
461 // Since WP 3.4.0
462 $theme = wp_get_theme($theme);
463
464 if (is_a($theme, 'WP_Theme')) {
465 return $theme->Version;
466 } else {
467 return false;
468 }
469
470 } else {
471 $theme_data = get_theme_data(WP_CONTENT_DIR . '/themes/'.$theme.'/style.css');
472
473 if (isset($theme_data['Version'])) {
474 return $theme_data['Version'];
475 } else {
476 return false;
477 }
478 }
479 }
480
481 /**
482 * Adding third-party plugins/theme for UDC automatic updates, for some updaters which store their information when the transient is set, instead of (like most) when it is fetched
483 *
484 * @param Array $items A collection of plugins or themes for updates
485 * @param String $type A string indicating which type of collection to process (e.g. 'plugin' or 'theme')
486 * @return Array An updated collection of plugins or themes for updates
487 */
488 private function maybe_add_third_party_items($items, $type) {
489
490 // Here we're preparing a dummy transient object that will be pass to the filter
491 // and gets populated by those plugins or themes that hooked into the "pre_set_site_transient_*" filter.
492 //
493 // We're setting some default properties so that plugins and themes won't be able to bypass populating them,
494 // because most of the plugins and themes updater scripts checks whether or not these properties are set and
495 // non-empty or passed the 12 hour period (where WordPress re-starts the process of checking updates for
496 // these plugins and themes), otherwise, they bypass populating the update/upgrade info for these items.
497 $transient = (object) array(
498 'last_checked' => time() - (13 * 3600), /* Making sure that we passed the 12 hour period check */
499 'checked' => array('default' => 'none'),
500 'response' => array('default' => 'none')
501 );
502
503 // Most of the premium plugin developers are hooking into the "pre_set_site_transient_update_plugins" and
504 // "pre_set_site_transient_update_themes" filters if they want their plugins or themes to support automatic
505 // updates. Thus, we're making sure here that if for some reason, those plugins or themes didn't get through
506 // and added to the "update_plugins" or "update_themes" transients when calling the get_site_transient('update_plugins')
507 // or get_site_transient('update_themes') we add them here manually.
508 $filters = apply_filters("pre_set_site_transient_update_{$type}s", $transient, "update_{$type}s");
509
510
511 $all_items = array();
512 switch ($type) {
513 case 'plugin':
514 $all_items = get_plugins();
515 break;
516 case 'theme':
517 $this->_frontend_include('theme.php');
518 if (function_exists('wp_get_themes')) {
519 $themes = wp_get_themes();
520 if (!empty($themes)) {
521 // We make sure that the return key matched the previous
522 // key from "get_themes", otherwise, no updates will be found
523 // even if it does have one. "get_themes" returns the name of the
524 // theme as the key while "wp_get_themes" returns the slug.
525 foreach ($themes as $theme) {
526 $all_items[$theme->Name] = $theme;
527 }
528 }
529 } else {
530 $all_items = get_themes();
531 }
532 break;
533 default:
534 break;
535 }
536
537
538 if (!empty($all_items)) {
539 $all_items = (array) $all_items;
540 foreach ($all_items as $key => $data) {
541 if (!isset($items[$key]) && isset($filters->response[$key])) {
542
543 $update_info = ('plugin' === $type) ? $filters->response[$key] : $data;
544
545 // If "package" is empty, it means that this plugin or theme does not support automatic updates
546 // currently, since the "package" field is the one holding the download link of these plugins/themes
547 // and WordPress is using this field to download the latest version of these items.
548 //
549 // Most of the time, this "package" field is not empty, but for premium plugins/themes this can be
550 // conditional, only then if the user provides a legit access or api key can this field be populated or available.
551 //
552 // We set this variable to "false" by default, as plugins/themes hosted in wordpress.org always sets this
553 // to the downloadable zip file of the plugin/theme.
554 //
555 // N.B. We only add premium plugins/themes that has this "package" field set and non-empty, otherwise, it
556 // does not support automatic updates as explained above.
557 $is_package_empty = false;
558
559 if (is_object($update_info)) {
560 if (!isset($update_info->package) || empty($update_info->package)) {
561 $is_package_empty = true;
562 }
563
564 } elseif (is_array($update_info)) {
565 if (!isset($update_info['package']) || empty($update_info['package'])) {
566 $is_package_empty = true;
567 }
568 }
569
570 // Add this plugin/theme to the current updates collection
571 if (!$is_package_empty) {
572 $items[$key] = ('plugin' === $type) ? (object) $data : $this->get_theme_info($key);
573 $items[$key]->update = $update_info;
574 }
575
576 }
577 }
578 }
579
580 return $this->prep_items_for_updates($items, $type);
581 }
582
583 /**
584 * Extracts theme's data or information
585 *
586 * @param string $theme A string representing a theme's name or slug.
587 * @return object|boolean If successful, an object containing the theme data or information, "false" otherwise.
588 */
589 private function get_theme_info($theme) {
590
591 if (function_exists('wp_get_theme')) {
592 $theme = wp_get_theme($theme);
593 if (is_a($theme, 'WP_Theme')) {
594 return $theme;
595 }
596 } else {
597 $theme_data = get_theme_data(WP_CONTENT_DIR.'/themes/'.$theme.'/style.css');
598 if (isset($theme_data['Version'])) {
599 if (!isset($theme_data['ThemeURI'])) $theme_data['ThemeURI'] = $theme_data['URI'];
600 return (object) $theme_data;
601 }
602 }
603
604 return false;
605 }
606
607 /**
608 * Fix items for update with missing "plugin" or "theme" field if applicable
609 *
610 * @param Array $items A collection of plugins or themes for updates
611 * @param String $type A string indicating which type of collection to process (e.g. 'plugin' or 'theme')
612 * @return Array An updated collection of plugins or themes for updates
613 */
614 private function prep_items_for_updates($items, $type) {
615
616 foreach ($items as $key => $data) {
617 $update_info = $data->update;
618
619 // Some plugins and/or themes does not adhere to the standard WordPress updates meta
620 // properties/fields. Thus, missing some fields such as "plugin" or "theme"
621 // in their update information results in "Automatic updates is unavailable for this item"
622 // in UDC since we're using these fields to process the updates.
623 //
624 // As a workaround, we're filling these missing fields in order to solve the above issue
625 // in case the developer of these plugins/themes forgot to include them.
626 if (is_object($update_info)) {
627 $update_info = (array) $update_info;
628 if (!isset($update_info[$type])) {
629 $update_info[$type] = $key;
630 }
631
632 $update_info = (object) $update_info;
633
634 } elseif (is_array($update_info)) {
635 if (!isset($update_info[$type])) {
636 $update_info[$type] = $key;
637 }
638 }
639
640 // Re-assign the updated info to the original "update" property
641 $items[$key]->update = $update_info;
642 }
643
644 return $items;
645 }
646
647 /**
648 * Custom validation for translation permission. Since the 'install_languages' capability insn't available until 4.9
649 * therefore, we wrapped the validation check in this block to support older version of WP.
650 *
651 * @return Boolean
652 */
653 private function user_can_update_translations() {
654 global $updraftcentral_main;
655 $wp_version = $updraftcentral_main->get_wordpress_version();
656
657 if (version_compare($wp_version, '4.9', '<')) {
658 if (current_user_can('update_core') || current_user_can('update_plugins') || current_user_can('update_themes')) return true;
659 } else {
660 if (current_user_can('install_languages')) return true;
661 }
662
663 return false;
664 }
665
666 /**
667 * Checks basic WP and PHP compatibility for plugins and themes
668 *
669 * @param string $type The type of the entity to check (e.g. 'plugin' or 'theme')
670 * @param array $info Data or information to check
671 * @return array
672 */
673 private function is_compatible($type, $info) {
674 global $updraftcentral_main;
675 $wp_version = $updraftcentral_main->get_wordpress_version();
676
677 $is_compatible = null;
678 $message = '';
679
680 if (isset($info['update'])) {
681
682 // Check for WP Compatibility based from the update information
683 if (!empty($info['update']['requires'])) {
684 if (version_compare($wp_version, $info['update']['requires'], '<')) {
685 $is_compatible = false;
686
687 /* translators: %s: Plugin/theme type */
688 $message1 = sprintf(
689 __('The latest update for this %s is not compatible with the WordPress version installed on the remote site.', 'updraftplus'),
690 $type
691 );
692
693 /* translators: 1: Plugin/theme type, 2: Required WordPress version */
694 $message2 = sprintf(
695 __('The minimum WordPress version supported by this %1$s is %2$s.', 'updraftplus'),
696 $type,
697 $info['update']['requires']
698 );
699
700 $message = esc_attr($message1 . ' ' . $message2);
701 } else {
702 $is_compatible = true;
703 }
704 }
705
706 // Check for PHP Compatibility based from the update information
707 if (!empty($info['update']['requires_php'])) {
708 if (version_compare(PHP_VERSION, $info['update']['requires_php'], '<')) {
709 $is_compatible = false;
710
711 /* translators: %s: Plugin/theme type */
712 $message1 = sprintf(
713 __('The latest update for this %s is not compatible with the PHP version installed on the remote site.', 'updraftplus'),
714 $type
715 );
716
717 /* translators: 1: Plugin/theme type, 2: Required PHP version */
718 $message2 = sprintf(
719 __('The minimum PHP version supported by this %1$s is %2$s.', 'updraftplus'),
720 $type,
721 $info['update']['requires_php']
722 );
723
724 $message = esc_attr($message1 . ' ' . $message2);
725 } else {
726 $is_compatible = true;
727 }
728 }
729
730 // Check whether Plugin/Theme has been tested based from the update information
731 if (!empty($info['update']['tested'])) {
732 if (version_compare($wp_version, $info['update']['tested'], '>')) {
733 $is_compatible = false;
734 // translators: %s: Plugin/theme type
735 $message = esc_attr(sprintf(__('The latest update for this %s has not been tested with the WordPress version installed on the remote site and may have compatibility issues when used.', 'updraftplus'), $type));
736 } else {
737 $is_compatible = true;
738 }
739 }
740 }
741
742 if (is_null($is_compatible)) {
743 $is_compatible = false;
744 $message = esc_attr(sprintf(__('This % does not provide information to allow determining whether the latest version is compatible with your WordPress or PHP installation.', 'updraftplus'), $type).' '.__('If installing, then proceed with caution by first doing a backup.', 'updraftplus'));
745 }
746
747 return array(
748 'compatible' => $is_compatible,
749 'compatible_message' => $message,
750 );
751 }
752
753 /**
754 * Retrieve icons for plugin and screenshot for theme
755 *
756 * @param string $type The type of the entity to process (e.g. 'plugin' or 'theme')
757 * @param string $slug The entity slug
758 * @return string
759 */
760 private function get_icons_screenshot($type, $slug) {
761 if (!in_array($type, array('plugin', 'theme'))) return '';
762
763 if ('plugin' == $type) {
764 if (!function_exists('plugins_api') && file_exists(ABSPATH.'wp-admin/includes/plugin-install.php')) {
765 include_once(ABSPATH.'wp-admin/includes/plugin-install.php');
766 }
767
768 // We make sure that the function now exists before we use it because
769 // the definition of this function maybe located in other places given
770 // the varying versions and changes to the WordPress platform.
771 if (function_exists('plugins_api')) {
772 $api = plugins_api('plugin_information', array(
773 'slug' => $slug,
774 'fields' => array('icons' => true),
775 ));
776
777 if (!is_wp_error($api) && property_exists($api, 'icons')) {
778 return $api->icons;
779 }
780 }
781
782 } elseif ('theme' == $type) {
783 if (!function_exists('themes_api') && file_exists(ABSPATH.'wp-admin/includes/theme.php')) {
784 include_once(ABSPATH.'wp-admin/includes/theme.php');
785 }
786
787 // We make sure that the function now exists before we use it because
788 // the definition of this function maybe located in other places given
789 // the varying versions and changes to the WordPress platform.
790 if (function_exists('themes_api')) {
791 $api = themes_api('theme_information', array(
792 'slug' => $slug,
793 'fields' => array('screenshot_url' => true),
794 ));
795
796 if (!is_wp_error($api) && property_exists($api, 'screenshot_url')) {
797 return $api->screenshot_url;
798 }
799 }
800 }
801
802 return '';
803 }
804
805 public function get_updates($options) {
806
807 // Forcing Elegant Themes (Divi) updates component to load if it exist.
808 if (function_exists('et_register_updates_component')) et_register_updates_component();
809
810 if (!current_user_can('update_plugins') && !current_user_can('update_themes') && !current_user_can('update_core')) return $this->_generic_error_response('updates_permission_denied');
811
812 $this->_admin_include('plugin.php', 'update.php', 'file.php', 'template.php');
813 $this->_frontend_include('update.php');
814
815 if (!is_array($options)) $options = array();
816
817 // Normalise it
818 $plugin_updates = array();
819 if (current_user_can('update_plugins')) {
820
821 // Detect if refresh needed
822 $transient = get_site_transient('update_plugins');
823 if (!empty($options['force_refresh']) || false === $transient) {
824 delete_site_transient('update_plugins');
825 wp_update_plugins();
826 }
827
828 $get_plugin_updates = $this->maybe_add_third_party_items(get_plugin_updates(), 'plugin');
829 if (is_array($get_plugin_updates)) {
830 foreach ($get_plugin_updates as $update) {
831
832 // For some reason, some 3rd-party (premium) plugins are returning the same version
833 // with that of the currently installed version in WordPress. Thus, we're making sure here to
834 // only return those items for update that has new versions greater than the currently installed version.
835 if (version_compare($update->Version, $update->update->new_version, '>=')) continue;
836
837 $info = array(
838 'name' => $update->Name,
839 'plugin_uri' => $update->PluginURI,
840 'version' => $update->Version,
841 'description' => $update->Description,
842 'author' => $update->Author,
843 'author_uri' => $update->AuthorURI,
844 'title' => $update->Title,
845 'author_name' => $update->AuthorName,
846 'update' => array(
847 // With Affiliates-WP, if you have not connected, this is null.
848 'plugin' => isset($update->update->plugin) ? $update->update->plugin : null,
849 'slug' => $update->update->slug,
850 'new_version' => $update->update->new_version,
851 'package' => $update->update->package,
852 'tested' => isset($update->update->tested) ? $update->update->tested : null,
853 'compatibility' => isset($update->update->compatibility) ? (array) $update->update->compatibility : null,
854 'sections' => isset($update->update->sections) ? (array) $update->update->sections : null,
855 'requires' => isset($update->update->requires) ? $update->update->requires : null,
856 'requires_php' => isset($update->update->requires_php) ? $update->update->requires_php : null,
857 'icons' => isset($update->update->icons) ? $update->update->icons : $this->get_icons_screenshot('plugin', $update->update->slug),
858 ),
859 );
860
861 // Check for compatibility and merge result into info
862 $result = $this->is_compatible('plugin', $info);
863 $plugin_updates[] = array_merge($info, $result);
864 }
865 }
866 }
867
868 $theme_updates = array();
869 if (current_user_can('update_themes')) {
870
871 // Detect if refresh needed
872 $transient = get_site_transient('update_themes');
873 if (!empty($options['force_refresh']) || false === $transient) {
874 delete_site_transient('update_themes');
875 wp_update_themes();
876 }
877 $get_theme_updates = $this->maybe_add_third_party_items(get_theme_updates(), 'theme');
878 if (is_array($get_theme_updates)) {
879 foreach ($get_theme_updates as $update) {
880
881 // We're making sure here to only return those items for update that has new
882 // versions greater than the currently installed version.
883 if (version_compare($update->Version, $update->update['new_version'], '>=')) continue;
884
885 $name = $update->Name;
886 $theme_name = !empty($name) ? $name : $update->update['theme'];
887
888 $info = array(
889 'name' => $theme_name,
890 'theme_uri' => $update->ThemeURI,
891 'version' => $update->Version,
892 'description' => $update->Description,
893 'author' => $update->Author,
894 'author_uri' => $update->AuthorURI,
895 'update' => array(
896 'theme' => $update->update['theme'],
897 'new_version' => $update->update['new_version'],
898 'package' => $update->update['package'],
899 'url' => $update->update['url'],
900 'tested' => isset($update->update['tested']) ? $update->update['tested'] : null,
901 'requires' => $update->update['requires'],
902 'requires_php' => $update->update['requires_php'],
903 'screenshot_url' => isset($update->update['screenshot_url']) ? $update->update['screenshot_url'] : $this->get_icons_screenshot('theme', $update->update['theme']),
904 ),
905 );
906
907 // Check for compatibility and merge result into info
908 $result = $this->is_compatible('theme', $info);
909 $theme_updates[] = array_merge($info, $result);
910 }
911 }
912 }
913
914 $core_updates = array();
915 if (current_user_can('update_core')) {
916
917 // Detect if refresh needed
918 $transient = get_site_transient('update_core');
919 if (!empty($options['force_refresh']) || false === $transient) {
920 // The next line is only needed for older WP versions - otherwise, the parameter to wp_version_check forces a check.
921 delete_site_transient('update_core');
922 wp_version_check(array(), true);
923 }
924
925 $get_core_updates = get_core_updates();
926
927 if (is_array($get_core_updates)) {
928
929 $core_update_key = false;
930 $core_update_latest_version = false;
931
932 // THis is included so we can get $wp_version
933 @include(ABSPATH.WPINC.'/version.php');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
934
935 foreach ($get_core_updates as $k => $core_update) {
936 if (isset($core_update->version) && version_compare($core_update->version, $wp_version, '>') && version_compare($core_update->version, $core_update_latest_version, '>')) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
937 $core_update_latest_version = $core_update->version;
938 $core_update_key = $k;
939 }
940 }
941
942 if (false !== $core_update_key) {
943
944 $update = $get_core_updates[$core_update_key];
945
946 global $wpdb;
947
948 $mysql_version = $wpdb->db_version();
949
950 $is_mysql = (file_exists(WP_CONTENT_DIR . '/db.php') && empty($wpdb->is_mysql)) ? false : true;
951
952 // We're making sure here to only return those items for update that has new
953 // versions greater than the currently installed version.
954 if (version_compare($wp_version, $update->version, '<')) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
955 $core_updates[] = array(
956 'download' => $update->download,
957 'version' => $update->version,
958 'php_version' => $update->php_version,
959 'mysql_version' => $update->mysql_version,
960 'installed' => array(
961 'version' => $wp_version,// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
962 'mysql' => $mysql_version,
963 'php' => PHP_VERSION,
964 'is_mysql' => $is_mysql,
965 ),
966 'sufficient' => array(
967 'mysql' => version_compare($mysql_version, $update->mysql_version, '>='),
968 'php' => version_compare(PHP_VERSION, $update->php_version, '>='),
969 ),
970 );
971 }
972
973 }
974 }
975
976 }
977
978 $translation_updates = array();
979 if (function_exists('wp_get_translation_updates') && $this->user_can_update_translations()) {
980 $translations = wp_get_translation_updates();
981
982 $translation_updates = array(
983 'items' => $translations
984 );
985 }
986
987 // Do we need to ask the user for filesystem credentials?
988 $request_filesystem_credentials = array();
989 $check_fs = array(
990 'plugins' => WP_PLUGIN_DIR,
991 'themes' => WP_CONTENT_DIR.'/themes',
992 'core' => untrailingslashit(ABSPATH)
993 );
994
995 if (!empty($translation_updates)) {
996 // 'en_US' don't usually have the "languages" folder, thus, we
997 // check if there's a need to ask for filesystem credentials for that
998 // folder if it exists, most especially for locale other than 'en_US'.
999 $language_dir = WP_CONTENT_DIR.'/languages';
1000 if ('en_US' !== get_locale() && is_dir($language_dir)) {
1001 $check_fs['translations'] = $language_dir;
1002 }
1003 }
1004
1005 foreach ($check_fs as $entity => $dir) {
1006 $filesystem_method = get_filesystem_method(array(), $dir);
1007 ob_start();
1008 $filesystem_credentials_are_stored = request_filesystem_credentials(site_url());
1009 $filesystem_form = strip_tags(ob_get_contents(), '<div><h2><p><input><label><fieldset><legend><span><em>');
1010 ob_end_clean();
1011 $request_filesystem_credentials[$entity] = ('direct' != $filesystem_method && !$filesystem_credentials_are_stored);
1012 }
1013
1014 $automatic_backups = (class_exists('UpdraftPlus_Options') && class_exists('UpdraftPlus_Addon_Autobackup') && UpdraftPlus_Options::get_updraft_option('updraft_autobackup_default')) ? true : false;
1015
1016 return $this->_response(array(
1017 'plugins' => $plugin_updates,
1018 'themes' => $theme_updates,
1019 'core' => $core_updates,
1020 'translations' => $translation_updates,
1021 'meta' => array(
1022 'request_filesystem_credentials' => $request_filesystem_credentials,
1023 'filesystem_form' => $filesystem_form,
1024 'automatic_backups' => $automatic_backups
1025 ),
1026 ));
1027 }
1028 }
1029