/** * Upgrade WordPress core. * * @since 2.8.0 * @access public * * @global WP_Filesystem_Base $wp_filesystem Subclass * @global callable $_wp_filesystem_direct_method * * @param object $current Response object for whether WordPress is current. * @param array $args { * Optional. Arguments for upgrading WordPress core. Default empty array. * * @type bool $pre_check_md5 Whether to check the file checksums before * attempting the upgrade. Default true. * @type bool $attempt_rollback Whether to attempt to rollback the chances if * there is a problem. Default false. * @type bool $do_rollback Whether to perform this "upgrade" as a rollback. * Default false. * } * @return null|false|WP_Error False or WP_Error on failure, null on success. */ public function upgrade($current, $args = array()) { global $wp_filesystem; include ABSPATH . WPINC . '/version.php'; // $wp_version; $start_time = time(); $defaults = array('pre_check_md5' => true, 'attempt_rollback' => false, 'do_rollback' => false, 'allow_relaxed_file_ownership' => false); $parsed_args = wp_parse_args($args, $defaults); $this->init(); $this->upgrade_strings(); // Is an update available? if (!isset($current->response) || $current->response == 'latest') { return new WP_Error('up_to_date', $this->strings['up_to_date']); } $res = $this->fs_connect(array(ABSPATH, WP_CONTENT_DIR), $parsed_args['allow_relaxed_file_ownership']); if (!$res || is_wp_error($res)) { return $res; } $wp_dir = trailingslashit($wp_filesystem->abspath()); $partial = true; if ($parsed_args['do_rollback']) { $partial = false; } elseif ($parsed_args['pre_check_md5'] && !$this->check_files()) { $partial = false; } /* * If partial update is returned from the API, use that, unless we're doing * a reinstall. If we cross the new_bundled version number, then use * the new_bundled zip. Don't though if the constant is set to skip bundled items. * If the API returns a no_content zip, go with it. Finally, default to the full zip. */ if ($parsed_args['do_rollback'] && $current->packages->rollback) { $to_download = 'rollback'; } elseif ($current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version && $partial) { $to_download = 'partial'; } elseif ($current->packages->new_bundled && version_compare($wp_version, $current->new_bundled, '<') && (!defined('CORE_UPGRADE_SKIP_NEW_BUNDLED') || !CORE_UPGRADE_SKIP_NEW_BUNDLED)) { $to_download = 'new_bundled'; } elseif ($current->packages->no_content) { $to_download = 'no_content'; } else { $to_download = 'full'; } // Lock to prevent multiple Core Updates occuring $lock = WP_Upgrader::create_lock('core_updater', 15 * MINUTE_IN_SECONDS); if (!$lock) { return new WP_Error('locked', $this->strings['locked']); } $download = $this->download_package($current->packages->{$to_download}); if (is_wp_error($download)) { WP_Upgrader::release_lock('core_updater'); return $download; } $working_dir = $this->unpack_package($download); if (is_wp_error($working_dir)) { WP_Upgrader::release_lock('core_updater'); return $working_dir; } // Copy update-core.php from the new version into place. if (!$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true)) { $wp_filesystem->delete($working_dir, true); WP_Upgrader::release_lock('core_updater'); return new WP_Error('copy_failed_for_update_core_file', __('The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.'), 'wp-admin/includes/update-core.php'); } $wp_filesystem->chmod($wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE); require_once ABSPATH . 'wp-admin/includes/update-core.php'; if (!function_exists('update_core')) { WP_Upgrader::release_lock('core_updater'); return new WP_Error('copy_failed_space', $this->strings['copy_failed_space']); } $result = update_core($working_dir, $wp_dir); // In the event of an issue, we may be able to roll back. if ($parsed_args['attempt_rollback'] && $current->packages->rollback && !$parsed_args['do_rollback']) { $try_rollback = false; if (is_wp_error($result)) { $error_code = $result->get_error_code(); /* * Not all errors are equal. These codes are critical: copy_failed__copy_dir, * mkdir_failed__copy_dir, copy_failed__copy_dir_retry, and disk_full. * do_rollback allows for update_core() to trigger a rollback if needed. */ if (false !== strpos($error_code, 'do_rollback')) { $try_rollback = true; } elseif (false !== strpos($error_code, '__copy_dir')) { $try_rollback = true; } elseif ('disk_full' === $error_code) { $try_rollback = true; } } if ($try_rollback) { /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters('update_feedback', $result); /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters('update_feedback', $this->strings['start_rollback']); $rollback_result = $this->upgrade($current, array_merge($parsed_args, array('do_rollback' => true))); $original_result = $result; $result = new WP_Error('rollback_was_required', $this->strings['rollback_was_required'], (object) array('update' => $original_result, 'rollback' => $rollback_result)); } } /** This action is documented in wp-admin/includes/class-wp-upgrader.php */ do_action('upgrader_process_complete', $this, array('action' => 'update', 'type' => 'core')); // Clear the current updates delete_site_transient('update_core'); if (!$parsed_args['do_rollback']) { $stats = array('update_type' => $current->response, 'success' => true, 'fs_method' => $wp_filesystem->method, 'fs_method_forced' => defined('FS_METHOD') || has_filter('filesystem_method'), 'fs_method_direct' => !empty($GLOBALS['_wp_filesystem_direct_method']) ? $GLOBALS['_wp_filesystem_direct_method'] : '', 'time_taken' => time() - $start_time, 'reported' => $wp_version, 'attempted' => $current->version); if (is_wp_error($result)) { $stats['success'] = false; // Did a rollback occur? if (!empty($try_rollback)) { $stats['error_code'] = $original_result->get_error_code(); $stats['error_data'] = $original_result->get_error_data(); // Was the rollback successful? If not, collect its error too. $stats['rollback'] = !is_wp_error($rollback_result); if (is_wp_error($rollback_result)) { $stats['rollback_code'] = $rollback_result->get_error_code(); $stats['rollback_data'] = $rollback_result->get_error_data(); } } else { $stats['error_code'] = $result->get_error_code(); $stats['error_data'] = $result->get_error_data(); } } wp_version_check($stats); } WP_Upgrader::release_lock('core_updater'); return $result; }
/** * Creates a lock using WordPress options. * * @since 4.5.0 * @access public * @static * * @param string $lock_name The name of this unique lock. * @param int $release_timeout Optional. The duration in seconds to respect an existing lock. * Default: 1 hour. * @return bool False if a lock couldn't be created or if the lock is no longer valid. True otherwise. */ public static function create_lock($lock_name, $release_timeout = null) { global $wpdb; if (!$release_timeout) { $release_timeout = HOUR_IN_SECONDS; } $lock_option = $lock_name . '.lock'; // Try to lock. $lock_result = $wpdb->query($wpdb->prepare("INSERT IGNORE INTO `{$wpdb->options}` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_option, time())); if (!$lock_result) { $lock_result = get_option($lock_option); // If a lock couldn't be created, and there isn't a lock, bail. if (!$lock_result) { return false; } // Check to see if the lock is still valid. If not, bail. if ($lock_result > time() - $release_timeout) { return false; } // There must exist an expired lock, clear it and re-gain it. WP_Upgrader::release_lock($lock_name); return WP_Upgrader::create_lock($lock_name, $release_timeout); } // Update the lock, as by this point we've definitely got a lock, just need to fire the actions. update_option($lock_option, time()); return true; }
/** * Kicks off the background update process, looping through all pending updates. * * @since 3.7.0 * @access public * * @global wpdb $wpdb * @global string $wp_version */ public function run() { global $wpdb, $wp_version; if ($this->is_disabled()) { return; } if (!is_main_network() || !is_main_site()) { return; } if (!WP_Upgrader::create_lock('auto_updater')) { return; } // Don't automatically run these thins, as we'll handle it ourselves remove_action('upgrader_process_complete', array('Language_Pack_Upgrader', 'async_upgrade'), 20); remove_action('upgrader_process_complete', 'wp_version_check'); remove_action('upgrader_process_complete', 'wp_update_plugins'); remove_action('upgrader_process_complete', 'wp_update_themes'); // Next, Plugins wp_update_plugins(); // Check for Plugin updates $plugin_updates = get_site_transient('update_plugins'); if ($plugin_updates && !empty($plugin_updates->response)) { foreach ($plugin_updates->response as $plugin) { $this->update('plugin', $plugin); } // Force refresh of plugin update information wp_clean_plugins_cache(); } // Next, those themes we all love wp_update_themes(); // Check for Theme updates $theme_updates = get_site_transient('update_themes'); if ($theme_updates && !empty($theme_updates->response)) { foreach ($theme_updates->response as $theme) { $this->update('theme', (object) $theme); } // Force refresh of theme update information wp_clean_themes_cache(); } // Next, Process any core update wp_version_check(); // Check for Core updates $core_update = find_core_auto_update(); if ($core_update) { $this->update('core', $core_update); } // Clean up, and check for any pending translations // (Core_Upgrader checks for core updates) $theme_stats = array(); if (isset($this->update_results['theme'])) { foreach ($this->update_results['theme'] as $upgrade) { $theme_stats[$upgrade->item->theme] = true === $upgrade->result; } } wp_update_themes($theme_stats); // Check for Theme updates $plugin_stats = array(); if (isset($this->update_results['plugin'])) { foreach ($this->update_results['plugin'] as $upgrade) { $plugin_stats[$upgrade->item->plugin] = true === $upgrade->result; } } wp_update_plugins($plugin_stats); // Check for Plugin updates // Finally, Process any new translations $language_updates = wp_get_translation_updates(); if ($language_updates) { foreach ($language_updates as $update) { $this->update('translation', $update); } // Clear existing caches wp_clean_update_cache(); wp_version_check(); // check for Core updates wp_update_themes(); // Check for Theme updates wp_update_plugins(); // Check for Plugin updates } // Send debugging email to all development installs. if (!empty($this->update_results)) { $development_version = false !== strpos($wp_version, '-'); /** * Filter whether to send a debugging email for each automatic background update. * * @since 3.7.0 * * @param bool $development_version By default, emails are sent if the * install is a development version. * Return false to avoid the email. */ if (apply_filters('automatic_updates_send_debug_email', $development_version)) { $this->send_debug_email(); } if (!empty($this->update_results['core'])) { $this->after_core_update($this->update_results['core'][0]); } /** * Fires after all automatic updates have run. * * @since 3.8.0 * * @param array $update_results The results of all attempted updates. */ do_action('automatic_updates_complete', $this->update_results); } WP_Upgrader::release_lock('auto_updater'); }