/**
  * 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');
 }