[ Index ]

WordPress Cross Reference

title

Body

[close]

/wp-admin/includes/ -> class-wp-upgrader.php (source)

   1  <?php
   2  /**
   3   * A File upgrader class for WordPress.
   4   *
   5   * This set of classes are designed to be used to upgrade/install a local set of files on the filesystem via the Filesystem Abstraction classes.
   6   *
   7   * @link http://trac.wordpress.org/ticket/7875 consolidate plugin/theme/core upgrade/install functions
   8   *
   9   * @package WordPress
  10   * @subpackage Upgrader
  11   * @since 2.8.0
  12   */
  13  
  14  require  ABSPATH . 'wp-admin/includes/class-wp-upgrader-skins.php';
  15  
  16  /**
  17   * WordPress Upgrader class for Upgrading/Installing a local set of files via the Filesystem Abstraction classes from a Zip file.
  18   *
  19   * @package WordPress
  20   * @subpackage Upgrader
  21   * @since 2.8.0
  22   */
  23  class WP_Upgrader {
  24      var $strings = array();
  25      var $skin = null;
  26      var $result = array();
  27  
  28  	function __construct($skin = null) {
  29          if ( null == $skin )
  30              $this->skin = new WP_Upgrader_Skin();
  31          else
  32              $this->skin = $skin;
  33      }
  34  
  35  	function init() {
  36          $this->skin->set_upgrader($this);
  37          $this->generic_strings();
  38      }
  39  
  40  	function generic_strings() {
  41          $this->strings['bad_request'] = __('Invalid Data provided.');
  42          $this->strings['fs_unavailable'] = __('Could not access filesystem.');
  43          $this->strings['fs_error'] = __('Filesystem error.');
  44          $this->strings['fs_no_root_dir'] = __('Unable to locate WordPress Root directory.');
  45          $this->strings['fs_no_content_dir'] = __('Unable to locate WordPress Content directory (wp-content).');
  46          $this->strings['fs_no_plugins_dir'] = __('Unable to locate WordPress Plugin directory.');
  47          $this->strings['fs_no_themes_dir'] = __('Unable to locate WordPress Theme directory.');
  48          /* translators: %s: directory name */
  49          $this->strings['fs_no_folder'] = __('Unable to locate needed folder (%s).');
  50  
  51          $this->strings['download_failed'] = __('Download failed.');
  52          $this->strings['installing_package'] = __('Installing the latest version&#8230;');
  53          $this->strings['no_files'] = __('The package contains no files.');
  54          $this->strings['folder_exists'] = __('Destination folder already exists.');
  55          $this->strings['mkdir_failed'] = __('Could not create directory.');
  56          $this->strings['incompatible_archive'] = __('The package could not be installed.');
  57  
  58          $this->strings['maintenance_start'] = __('Enabling Maintenance mode&#8230;');
  59          $this->strings['maintenance_end'] = __('Disabling Maintenance mode&#8230;');
  60      }
  61  
  62  	function fs_connect( $directories = array() ) {
  63          global $wp_filesystem;
  64  
  65          if ( false === ($credentials = $this->skin->request_filesystem_credentials()) )
  66              return false;
  67  
  68          if ( ! WP_Filesystem($credentials) ) {
  69              $error = true;
  70              if ( is_object($wp_filesystem) && $wp_filesystem->errors->get_error_code() )
  71                  $error = $wp_filesystem->errors;
  72              $this->skin->request_filesystem_credentials($error); //Failed to connect, Error and request again
  73              return false;
  74          }
  75  
  76          if ( ! is_object($wp_filesystem) )
  77              return new WP_Error('fs_unavailable', $this->strings['fs_unavailable'] );
  78  
  79          if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
  80              return new WP_Error('fs_error', $this->strings['fs_error'], $wp_filesystem->errors);
  81  
  82          foreach ( (array)$directories as $dir ) {
  83              switch ( $dir ) {
  84                  case ABSPATH:
  85                      if ( ! $wp_filesystem->abspath() )
  86                          return new WP_Error('fs_no_root_dir', $this->strings['fs_no_root_dir']);
  87                      break;
  88                  case WP_CONTENT_DIR:
  89                      if ( ! $wp_filesystem->wp_content_dir() )
  90                          return new WP_Error('fs_no_content_dir', $this->strings['fs_no_content_dir']);
  91                      break;
  92                  case WP_PLUGIN_DIR:
  93                      if ( ! $wp_filesystem->wp_plugins_dir() )
  94                          return new WP_Error('fs_no_plugins_dir', $this->strings['fs_no_plugins_dir']);
  95                      break;
  96                  case get_theme_root():
  97                      if ( ! $wp_filesystem->wp_themes_dir() )
  98                          return new WP_Error('fs_no_themes_dir', $this->strings['fs_no_themes_dir']);
  99                      break;
 100                  default:
 101                      if ( ! $wp_filesystem->find_folder($dir) )
 102                          return new WP_Error( 'fs_no_folder', sprintf( $this->strings['fs_no_folder'], esc_html( basename( $dir ) ) ) );
 103                      break;
 104              }
 105          }
 106          return true;
 107      } //end fs_connect();
 108  
 109  	function download_package($package) {
 110  
 111          /**
 112           * Filter whether to return the package.
 113           *
 114           * @since 3.7.0
 115           *
 116           * @param bool    $reply   Whether to bail without returning the package. Default is false.
 117           * @param string  $package The package file name.
 118           * @param object  $this    The WP_Upgrader instance.
 119           */
 120          $reply = apply_filters( 'upgrader_pre_download', false, $package, $this );
 121          if ( false !== $reply )
 122              return $reply;
 123  
 124          if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package) ) //Local file or remote?
 125              return $package; //must be a local file..
 126  
 127          if ( empty($package) )
 128              return new WP_Error('no_package', $this->strings['no_package']);
 129  
 130          $this->skin->feedback('downloading_package', $package);
 131  
 132          $download_file = download_url($package);
 133  
 134          if ( is_wp_error($download_file) )
 135              return new WP_Error('download_failed', $this->strings['download_failed'], $download_file->get_error_message());
 136  
 137          return $download_file;
 138      }
 139  
 140  	function unpack_package($package, $delete_package = true) {
 141          global $wp_filesystem;
 142  
 143          $this->skin->feedback('unpack_package');
 144  
 145          $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
 146  
 147          //Clean up contents of upgrade directory beforehand.
 148          $upgrade_files = $wp_filesystem->dirlist($upgrade_folder);
 149          if ( !empty($upgrade_files) ) {
 150              foreach ( $upgrade_files as $file )
 151                  $wp_filesystem->delete($upgrade_folder . $file['name'], true);
 152          }
 153  
 154          //We need a working directory
 155          $working_dir = $upgrade_folder . basename($package, '.zip');
 156  
 157          // Clean up working directory
 158          if ( $wp_filesystem->is_dir($working_dir) )
 159              $wp_filesystem->delete($working_dir, true);
 160  
 161          // Unzip package to working directory
 162          $result = unzip_file( $package, $working_dir );
 163  
 164          // Once extracted, delete the package if required.
 165          if ( $delete_package )
 166              unlink($package);
 167  
 168          if ( is_wp_error($result) ) {
 169              $wp_filesystem->delete($working_dir, true);
 170              if ( 'incompatible_archive' == $result->get_error_code() ) {
 171                  return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], $result->get_error_data() );
 172              }
 173              return $result;
 174          }
 175  
 176          return $working_dir;
 177      }
 178  
 179  	function install_package( $args = array() ) {
 180          global $wp_filesystem, $wp_theme_directories;
 181  
 182          $defaults = array(
 183              'source' => '', // Please always pass this
 184              'destination' => '', // and this
 185              'clear_destination' => false,
 186              'clear_working' => false,
 187              'abort_if_destination_exists' => true,
 188              'hook_extra' => array()
 189          );
 190  
 191          $args = wp_parse_args($args, $defaults);
 192          extract($args);
 193  
 194          @set_time_limit( 300 );
 195  
 196          if ( empty($source) || empty($destination) )
 197              return new WP_Error('bad_request', $this->strings['bad_request']);
 198  
 199          $this->skin->feedback('installing_package');
 200  
 201          $res = apply_filters('upgrader_pre_install', true, $hook_extra);
 202          if ( is_wp_error($res) )
 203              return $res;
 204  
 205          //Retain the Original source and destinations
 206          $remote_source = $source;
 207          $local_destination = $destination;
 208  
 209          $source_files = array_keys( $wp_filesystem->dirlist($remote_source) );
 210          $remote_destination = $wp_filesystem->find_folder($local_destination);
 211  
 212          //Locate which directory to copy to the new folder, This is based on the actual folder holding the files.
 213          if ( 1 == count($source_files) && $wp_filesystem->is_dir( trailingslashit($source) . $source_files[0] . '/') ) //Only one folder? Then we want its contents.
 214              $source = trailingslashit($source) . trailingslashit($source_files[0]);
 215          elseif ( count($source_files) == 0 )
 216              return new WP_Error( 'incompatible_archive_empty', $this->strings['incompatible_archive'], $this->strings['no_files'] ); // There are no files?
 217          else //It's only a single file, the upgrader will use the foldername of this file as the destination folder. foldername is based on zip filename.
 218              $source = trailingslashit($source);
 219  
 220          //Hook ability to change the source file location..
 221          $source = apply_filters('upgrader_source_selection', $source, $remote_source, $this);
 222          if ( is_wp_error($source) )
 223              return $source;
 224  
 225          //Has the source location changed? If so, we need a new source_files list.
 226          if ( $source !== $remote_source )
 227              $source_files = array_keys( $wp_filesystem->dirlist($source) );
 228  
 229          // Protection against deleting files in any important base directories.
 230          // Theme_Upgrader & Plugin_Upgrader also trigger this, as they pass the destination directory (WP_PLUGIN_DIR / wp-content/themes)
 231          // intending to copy the directory into the directory, whilst they pass the source as the actual files to copy.
 232          $protected_directories = array( ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes' );
 233          if ( is_array( $wp_theme_directories ) )
 234              $protected_directories = array_merge( $protected_directories, $wp_theme_directories );
 235          if ( in_array( $destination, $protected_directories ) ) {
 236              $remote_destination = trailingslashit($remote_destination) . trailingslashit(basename($source));
 237              $destination = trailingslashit($destination) . trailingslashit(basename($source));
 238          }
 239  
 240          if ( $clear_destination ) {
 241              //We're going to clear the destination if there's something there
 242              $this->skin->feedback('remove_old');
 243              $removed = true;
 244              if ( $wp_filesystem->exists($remote_destination) )
 245                  $removed = $wp_filesystem->delete($remote_destination, true);
 246              $removed = apply_filters('upgrader_clear_destination', $removed, $local_destination, $remote_destination, $hook_extra);
 247  
 248              if ( is_wp_error($removed) )
 249                  return $removed;
 250              else if ( ! $removed )
 251                  return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']);
 252          } elseif ( $abort_if_destination_exists && $wp_filesystem->exists($remote_destination) ) {
 253              //If we're not clearing the destination folder and something exists there already, Bail.
 254              //But first check to see if there are actually any files in the folder.
 255              $_files = $wp_filesystem->dirlist($remote_destination);
 256              if ( ! empty($_files) ) {
 257                  $wp_filesystem->delete($remote_source, true); //Clear out the source files.
 258                  return new WP_Error('folder_exists', $this->strings['folder_exists'], $remote_destination );
 259              }
 260          }
 261  
 262          //Create destination if needed
 263          if ( !$wp_filesystem->exists($remote_destination) )
 264              if ( !$wp_filesystem->mkdir($remote_destination, FS_CHMOD_DIR) )
 265                  return new WP_Error( 'mkdir_failed_destination', $this->strings['mkdir_failed'], $remote_destination );
 266  
 267          // Copy new version of item into place.
 268          $result = copy_dir($source, $remote_destination);
 269          if ( is_wp_error($result) ) {
 270              if ( $clear_working )
 271                  $wp_filesystem->delete($remote_source, true);
 272              return $result;
 273          }
 274  
 275          //Clear the Working folder?
 276          if ( $clear_working )
 277              $wp_filesystem->delete($remote_source, true);
 278  
 279          $destination_name = basename( str_replace($local_destination, '', $destination) );
 280          if ( '.' == $destination_name )
 281              $destination_name = '';
 282  
 283          $this->result = compact('local_source', 'source', 'source_name', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination', 'delete_source_dir');
 284  
 285          $res = apply_filters('upgrader_post_install', true, $hook_extra, $this->result);
 286          if ( is_wp_error($res) ) {
 287              $this->result = $res;
 288              return $res;
 289          }
 290  
 291          //Bombard the calling function will all the info which we've just used.
 292          return $this->result;
 293      }
 294  
 295  	function run($options) {
 296  
 297          $defaults = array(
 298              'package' => '', // Please always pass this.
 299              'destination' => '', // And this
 300              'clear_destination' => false,
 301              'abort_if_destination_exists' => true, // Abort if the Destination directory exists, Pass clear_destination as false please
 302              'clear_working' => true,
 303              'is_multi' => false,
 304              'hook_extra' => array() // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
 305          );
 306  
 307          $options = wp_parse_args($options, $defaults);
 308          extract($options);
 309  
 310          if ( ! $is_multi ) // call $this->header separately if running multiple times
 311              $this->skin->header();
 312  
 313          // Connect to the Filesystem first.
 314          $res = $this->fs_connect( array(WP_CONTENT_DIR, $destination) );
 315          // Mainly for non-connected filesystem.
 316          if ( ! $res ) {
 317              if ( ! $is_multi )
 318                  $this->skin->footer();
 319              return false;
 320          }
 321  
 322          $this->skin->before();
 323  
 324          if ( is_wp_error($res) ) {
 325              $this->skin->error($res);
 326              $this->skin->after();
 327              if ( ! $is_multi )
 328                  $this->skin->footer();
 329              return $res;
 330          }
 331  
 332          //Download the package (Note, This just returns the filename of the file if the package is a local file)
 333          $download = $this->download_package( $package );
 334          if ( is_wp_error($download) ) {
 335              $this->skin->error($download);
 336              $this->skin->after();
 337              if ( ! $is_multi )
 338                  $this->skin->footer();
 339              return $download;
 340          }
 341  
 342          $delete_package = ($download != $package); // Do not delete a "local" file
 343  
 344          //Unzips the file into a temporary directory
 345          $working_dir = $this->unpack_package( $download, $delete_package );
 346          if ( is_wp_error($working_dir) ) {
 347              $this->skin->error($working_dir);
 348              $this->skin->after();
 349              if ( ! $is_multi )
 350                  $this->skin->footer();
 351              return $working_dir;
 352          }
 353  
 354          //With the given options, this installs it to the destination directory.
 355          $result = $this->install_package( array(
 356              'source' => $working_dir,
 357              'destination' => $destination,
 358              'clear_destination' => $clear_destination,
 359              'abort_if_destination_exists' => $abort_if_destination_exists,
 360              'clear_working' => $clear_working,
 361              'hook_extra' => $hook_extra
 362          ) );
 363  
 364          $this->skin->set_result($result);
 365          if ( is_wp_error($result) ) {
 366              $this->skin->error($result);
 367              $this->skin->feedback('process_failed');
 368          } else {
 369              //Install Succeeded
 370              $this->skin->feedback('process_success');
 371          }
 372  
 373          $this->skin->after();
 374  
 375          if ( ! $is_multi ) {
 376              do_action( 'upgrader_process_complete', $this, $hook_extra );
 377              $this->skin->footer();
 378          }
 379  
 380          return $result;
 381      }
 382  
 383  	function maintenance_mode($enable = false) {
 384          global $wp_filesystem;
 385          $file = $wp_filesystem->abspath() . '.maintenance';
 386          if ( $enable ) {
 387              $this->skin->feedback('maintenance_start');
 388              // Create maintenance file to signal that we are upgrading
 389              $maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
 390              $wp_filesystem->delete($file);
 391              $wp_filesystem->put_contents($file, $maintenance_string, FS_CHMOD_FILE);
 392          } else if ( !$enable && $wp_filesystem->exists($file) ) {
 393              $this->skin->feedback('maintenance_end');
 394              $wp_filesystem->delete($file);
 395          }
 396      }
 397  
 398  }
 399  
 400  /**
 401   * Plugin Upgrader class for WordPress Plugins, It is designed to upgrade/install plugins from a local zip, remote zip URL, or uploaded zip file.
 402   *
 403   * @package WordPress
 404   * @subpackage Upgrader
 405   * @since 2.8.0
 406   */
 407  class Plugin_Upgrader extends WP_Upgrader {
 408  
 409      var $result;
 410      var $bulk = false;
 411  
 412  	function upgrade_strings() {
 413          $this->strings['up_to_date'] = __('The plugin is at the latest version.');
 414          $this->strings['no_package'] = __('Update package not available.');
 415          $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
 416          $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
 417          $this->strings['remove_old'] = __('Removing the old version of the plugin&#8230;');
 418          $this->strings['remove_old_failed'] = __('Could not remove the old plugin.');
 419          $this->strings['process_failed'] = __('Plugin update failed.');
 420          $this->strings['process_success'] = __('Plugin updated successfully.');
 421      }
 422  
 423  	function install_strings() {
 424          $this->strings['no_package'] = __('Install package not available.');
 425          $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>&#8230;');
 426          $this->strings['unpack_package'] = __('Unpacking the package&#8230;');
 427          $this->strings['installing_package'] = __('Installing the plugin&#8230;');
 428          $this->strings['no_files'] = __('The plugin contains no files.');
 429          $this->strings['process_failed'] = __('Plugin install failed.');
 430          $this->strings['process_success'] = __('Plugin installed successfully.');
 431      }
 432  
 433  	function install( $package, $args = array() ) {
 434  
 435          $defaults = array(
 436              'clear_update_cache' => true,
 437          );
 438          $parsed_args = wp_parse_args( $args, $defaults );
 439  
 440          $this->init();
 441          $this->install_strings();
 442  
 443          add_filter('upgrader_source_selection', array($this, 'check_package') );
 444  
 445          $this->run( array(
 446              'package' => $package,
 447              'destination' => WP_PLUGIN_DIR,
 448              'clear_destination' => false, // Do not overwrite files.
 449              'clear_working' => true,
 450              'hook_extra' => array(
 451                  'type' => 'plugin',
 452                  'action' => 'install',
 453              )
 454          ) );
 455  
 456          remove_filter('upgrader_source_selection', array($this, 'check_package') );
 457  
 458          if ( ! $this->result || is_wp_error($this->result) )
 459              return $this->result;
 460  
 461          // Force refresh of plugin update information
 462          wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
 463  
 464          return true;
 465      }
 466  
 467  	function upgrade( $plugin, $args = array() ) {
 468  
 469          $defaults = array(
 470              'clear_update_cache' => true,
 471          );
 472          $parsed_args = wp_parse_args( $args, $defaults );
 473  
 474          $this->init();
 475          $this->upgrade_strings();
 476  
 477          $current = get_site_transient( 'update_plugins' );
 478          if ( !isset( $current->response[ $plugin ] ) ) {
 479              $this->skin->before();
 480              $this->skin->set_result(false);
 481              $this->skin->error('up_to_date');
 482              $this->skin->after();
 483              return false;
 484          }
 485  
 486          // Get the URL to the zip file
 487          $r = $current->response[ $plugin ];
 488  
 489          add_filter('upgrader_pre_install', array($this, 'deactivate_plugin_before_upgrade'), 10, 2);
 490          add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 10, 4);
 491          //'source_selection' => array($this, 'source_selection'), //there's a trac ticket to move up the directory for zip's which are made a bit differently, useful for non-.org plugins.
 492  
 493          $this->run( array(
 494              'package' => $r->package,
 495              'destination' => WP_PLUGIN_DIR,
 496              'clear_destination' => true,
 497              'clear_working' => true,
 498              'hook_extra' => array(
 499                  'plugin' => $plugin,
 500                  'type' => 'plugin',
 501                  'action' => 'update',
 502              ),
 503          ) );
 504  
 505          // Cleanup our hooks, in case something else does a upgrade on this connection.
 506          remove_filter('upgrader_pre_install', array($this, 'deactivate_plugin_before_upgrade'));
 507          remove_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'));
 508  
 509          if ( ! $this->result || is_wp_error($this->result) )
 510              return $this->result;
 511  
 512          // Force refresh of plugin update information
 513          wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
 514  
 515          return true;
 516      }
 517  
 518  	function bulk_upgrade( $plugins, $args = array() ) {
 519  
 520          $defaults = array(
 521              'clear_update_cache' => true,
 522          );
 523          $parsed_args = wp_parse_args( $args, $defaults );
 524  
 525          $this->init();
 526          $this->bulk = true;
 527          $this->upgrade_strings();
 528  
 529          $current = get_site_transient( 'update_plugins' );
 530  
 531          add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 10, 4);
 532  
 533          $this->skin->header();
 534  
 535          // Connect to the Filesystem first.
 536          $res = $this->fs_connect( array(WP_CONTENT_DIR, WP_PLUGIN_DIR) );
 537          if ( ! $res ) {
 538              $this->skin->footer();
 539              return false;
 540          }
 541  
 542          $this->skin->bulk_header();
 543  
 544          // Only start maintenance mode if:
 545          // - running Multisite and there are one or more plugins specified, OR
 546          // - a plugin with an update available is currently active.
 547          // @TODO: For multisite, maintenance mode should only kick in for individual sites if at all possible.
 548          $maintenance = ( is_multisite() && ! empty( $plugins ) );
 549          foreach ( $plugins as $plugin )
 550              $maintenance = $maintenance || ( is_plugin_active( $plugin ) && isset( $current->response[ $plugin] ) );
 551          if ( $maintenance )
 552              $this->maintenance_mode(true);
 553  
 554          $results = array();
 555  
 556          $this->update_count = count($plugins);
 557          $this->update_current = 0;
 558          foreach ( $plugins as $plugin ) {
 559              $this->update_current++;
 560              $this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true);
 561  
 562              if ( !isset( $current->response[ $plugin ] ) ) {
 563                  $this->skin->set_result(true);
 564                  $this->skin->before();
 565                  $this->skin->feedback('up_to_date');
 566                  $this->skin->after();
 567                  $results[$plugin] = true;
 568                  continue;
 569              }
 570  
 571              // Get the URL to the zip file
 572              $r = $current->response[ $plugin ];
 573  
 574              $this->skin->plugin_active = is_plugin_active($plugin);
 575  
 576              $result = $this->run( array(
 577                  'package' => $r->package,
 578                  'destination' => WP_PLUGIN_DIR,
 579                  'clear_destination' => true,
 580                  'clear_working' => true,
 581                  'is_multi' => true,
 582                  'hook_extra' => array(
 583                      'plugin' => $plugin
 584                  )
 585              ) );
 586  
 587              $results[$plugin] = $this->result;
 588  
 589              // Prevent credentials auth screen from displaying multiple times
 590              if ( false === $result )
 591                  break;
 592          } //end foreach $plugins
 593  
 594          $this->maintenance_mode(false);
 595  
 596          do_action( 'upgrader_process_complete', $this, array(
 597              'action' => 'update',
 598              'type' => 'plugin',
 599              'bulk' => true,
 600              'plugins' => $plugins,
 601          ) );
 602  
 603          $this->skin->bulk_footer();
 604  
 605          $this->skin->footer();
 606  
 607          // Cleanup our hooks, in case something else does a upgrade on this connection.
 608          remove_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'));
 609  
 610          // Force refresh of plugin update information
 611          wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
 612  
 613          return $results;
 614      }
 615  
 616  	function check_package($source) {
 617          global $wp_filesystem;
 618  
 619          if ( is_wp_error($source) )
 620              return $source;
 621  
 622          $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source);
 623          if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, lets not prevent installation.
 624              return $source;
 625  
 626          // Check the folder contains at least 1 valid plugin.
 627          $plugins_found = false;
 628          foreach ( glob( $working_directory . '*.php' ) as $file ) {
 629              $info = get_plugin_data($file, false, false);
 630              if ( !empty( $info['Name'] ) ) {
 631                  $plugins_found = true;
 632                  break;
 633              }
 634          }
 635  
 636          if ( ! $plugins_found )
 637              return new WP_Error( 'incompatible_archive_no_plugins', $this->strings['incompatible_archive'], __( 'No valid plugins were found.' ) );
 638  
 639          return $source;
 640      }
 641  
 642      //return plugin info.
 643  	function plugin_info() {
 644          if ( ! is_array($this->result) )
 645              return false;
 646          if ( empty($this->result['destination_name']) )
 647              return false;
 648  
 649          $plugin = get_plugins('/' . $this->result['destination_name']); //Ensure to pass with leading slash
 650          if ( empty($plugin) )
 651              return false;
 652  
 653          $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list
 654  
 655          return $this->result['destination_name'] . '/' . $pluginfiles[0];
 656      }
 657  
 658      //Hooked to pre_install
 659  	function deactivate_plugin_before_upgrade($return, $plugin) {
 660  
 661          if ( is_wp_error($return) ) //Bypass.
 662              return $return;
 663  
 664          // When in cron (background updates) don't deactivate the plugin, as we require a browser to reactivate it
 665          if ( defined( 'DOING_CRON' ) && DOING_CRON )
 666              return $return;
 667  
 668          $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : '';
 669          if ( empty($plugin) )
 670              return new WP_Error('bad_request', $this->strings['bad_request']);
 671  
 672          if ( is_plugin_active($plugin) ) {
 673              //Deactivate the plugin silently, Prevent deactivation hooks from running.
 674              deactivate_plugins($plugin, true);
 675          }
 676      }
 677  
 678      //Hooked to upgrade_clear_destination
 679  	function delete_old_plugin($removed, $local_destination, $remote_destination, $plugin) {
 680          global $wp_filesystem;
 681  
 682          if ( is_wp_error($removed) )
 683              return $removed; //Pass errors through.
 684  
 685          $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : '';
 686          if ( empty($plugin) )
 687              return new WP_Error('bad_request', $this->strings['bad_request']);
 688  
 689          $plugins_dir = $wp_filesystem->wp_plugins_dir();
 690          $this_plugin_dir = trailingslashit( dirname($plugins_dir . $plugin) );
 691  
 692          if ( ! $wp_filesystem->exists($this_plugin_dir) ) //If it's already vanished.
 693              return $removed;
 694  
 695          // If plugin is in its own directory, recursively delete the directory.
 696          if ( strpos($plugin, '/') && $this_plugin_dir != $plugins_dir ) //base check on if plugin includes directory separator AND that it's not the root plugin folder
 697              $deleted = $wp_filesystem->delete($this_plugin_dir, true);
 698          else
 699              $deleted = $wp_filesystem->delete($plugins_dir . $plugin);
 700  
 701          if ( ! $deleted )
 702              return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']);
 703  
 704          return true;
 705      }
 706  }
 707  
 708  /**
 709   * Theme Upgrader class for WordPress Themes, It is designed to upgrade/install themes from a local zip, remote zip URL, or uploaded zip file.
 710   *
 711   * @package WordPress
 712   * @subpackage Upgrader
 713   * @since 2.8.0
 714   */
 715  class Theme_Upgrader extends WP_Upgrader {
 716  
 717      var $result;
 718      var $bulk = false;
 719  
 720  	function upgrade_strings() {
 721          $this->strings['up_to_date'] = __('The theme is at the latest version.');
 722          $this->strings['no_package'] = __('Update package not available.');
 723          $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
 724          $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
 725          $this->strings['remove_old'] = __('Removing the old version of the theme&#8230;');
 726          $this->strings['remove_old_failed'] = __('Could not remove the old theme.');
 727          $this->strings['process_failed'] = __('Theme update failed.');
 728          $this->strings['process_success'] = __('Theme updated successfully.');
 729      }
 730  
 731  	function install_strings() {
 732          $this->strings['no_package'] = __('Install package not available.');
 733          $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>&#8230;');
 734          $this->strings['unpack_package'] = __('Unpacking the package&#8230;');
 735          $this->strings['installing_package'] = __('Installing the theme&#8230;');
 736          $this->strings['no_files'] = __('The theme contains no files.');
 737          $this->strings['process_failed'] = __('Theme install failed.');
 738          $this->strings['process_success'] = __('Theme installed successfully.');
 739          /* translators: 1: theme name, 2: version */
 740          $this->strings['process_success_specific'] = __('Successfully installed the theme <strong>%1$s %2$s</strong>.');
 741          $this->strings['parent_theme_search'] = __('This theme requires a parent theme. Checking if it is installed&#8230;');
 742          /* translators: 1: theme name, 2: version */
 743          $this->strings['parent_theme_prepare_install'] = __('Preparing to install <strong>%1$s %2$s</strong>&#8230;');
 744          /* translators: 1: theme name, 2: version */
 745          $this->strings['parent_theme_currently_installed'] = __('The parent theme, <strong>%1$s %2$s</strong>, is currently installed.');
 746          /* translators: 1: theme name, 2: version */
 747          $this->strings['parent_theme_install_success'] = __('Successfully installed the parent theme, <strong>%1$s %2$s</strong>.');
 748          $this->strings['parent_theme_not_found'] = __('<strong>The parent theme could not be found.</strong> You will need to install the parent theme, <strong>%s</strong>, before you can use this child theme.');
 749      }
 750  
 751  	function check_parent_theme_filter($install_result, $hook_extra, $child_result) {
 752          // Check to see if we need to install a parent theme
 753          $theme_info = $this->theme_info();
 754  
 755          if ( ! $theme_info->parent() )
 756              return $install_result;
 757  
 758          $this->skin->feedback( 'parent_theme_search' );
 759  
 760          if ( ! $theme_info->parent()->errors() ) {
 761              $this->skin->feedback( 'parent_theme_currently_installed', $theme_info->parent()->display('Name'), $theme_info->parent()->display('Version') );
 762              // We already have the theme, fall through.
 763              return $install_result;
 764          }
 765  
 766          // We don't have the parent theme, lets install it
 767          $api = themes_api('theme_information', array('slug' => $theme_info->get('Template'), 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth.
 768  
 769          if ( ! $api || is_wp_error($api) ) {
 770              $this->skin->feedback( 'parent_theme_not_found', $theme_info->get('Template') );
 771              // Don't show activate or preview actions after install
 772              add_filter('install_theme_complete_actions', array($this, 'hide_activate_preview_actions') );
 773              return $install_result;
 774          }
 775  
 776          // Backup required data we're going to override:
 777          $child_api = $this->skin->api;
 778          $child_success_message = $this->strings['process_success'];
 779  
 780          // Override them
 781          $this->skin->api = $api;
 782          $this->strings['process_success_specific'] = $this->strings['parent_theme_install_success'];//, $api->name, $api->version);
 783  
 784          $this->skin->feedback('parent_theme_prepare_install', $api->name, $api->version);
 785  
 786          add_filter('install_theme_complete_actions', '__return_false', 999); // Don't show any actions after installing the theme.
 787  
 788          // Install the parent theme
 789          $parent_result = $this->run( array(
 790              'package' => $api->download_link,
 791              'destination' => get_theme_root(),
 792              'clear_destination' => false, //Do not overwrite files.
 793              'clear_working' => true
 794          ) );
 795  
 796          if ( is_wp_error($parent_result) )
 797              add_filter('install_theme_complete_actions', array($this, 'hide_activate_preview_actions') );
 798  
 799          // Start cleaning up after the parents installation
 800          remove_filter('install_theme_complete_actions', '__return_false', 999);
 801  
 802          // Reset child's result and data
 803          $this->result = $child_result;
 804          $this->skin->api = $child_api;
 805          $this->strings['process_success'] = $child_success_message;
 806  
 807          return $install_result;
 808      }
 809  
 810  	function hide_activate_preview_actions($actions) {
 811          unset($actions['activate'], $actions['preview']);
 812          return $actions;
 813      }
 814  
 815  	function install( $package, $args = array() ) {
 816  
 817          $defaults = array(
 818              'clear_update_cache' => true,
 819          );
 820          $parsed_args = wp_parse_args( $args, $defaults );
 821  
 822          $this->init();
 823          $this->install_strings();
 824  
 825          add_filter('upgrader_source_selection', array($this, 'check_package') );
 826          add_filter('upgrader_post_install', array($this, 'check_parent_theme_filter'), 10, 3);
 827  
 828          $this->run( array(
 829              'package' => $package,
 830              'destination' => get_theme_root(),
 831              'clear_destination' => false, //Do not overwrite files.
 832              'clear_working' => true,
 833              'hook_extra' => array(
 834                  'type' => 'theme',
 835                  'action' => 'install',
 836              ),
 837          ) );
 838  
 839          remove_filter('upgrader_source_selection', array($this, 'check_package') );
 840          remove_filter('upgrader_post_install', array($this, 'check_parent_theme_filter'));
 841  
 842          if ( ! $this->result || is_wp_error($this->result) )
 843              return $this->result;
 844  
 845          // Refresh the Theme Update information
 846          wp_clean_themes_cache( $parsed_args['clear_update_cache'] );
 847  
 848          return true;
 849      }
 850  
 851  	function upgrade( $theme, $args = array() ) {
 852  
 853          $defaults = array(
 854              'clear_update_cache' => true,
 855          );
 856          $parsed_args = wp_parse_args( $args, $defaults );
 857  
 858          $this->init();
 859          $this->upgrade_strings();
 860  
 861          // Is an update available?
 862          $current = get_site_transient( 'update_themes' );
 863          if ( !isset( $current->response[ $theme ] ) ) {
 864              $this->skin->before();
 865              $this->skin->set_result(false);
 866              $this->skin->error('up_to_date');
 867              $this->skin->after();
 868              return false;
 869          }
 870  
 871          $r = $current->response[ $theme ];
 872  
 873          add_filter('upgrader_pre_install', array($this, 'current_before'), 10, 2);
 874          add_filter('upgrader_post_install', array($this, 'current_after'), 10, 2);
 875          add_filter('upgrader_clear_destination', array($this, 'delete_old_theme'), 10, 4);
 876  
 877          $this->run( array(
 878              'package' => $r['package'],
 879              'destination' => get_theme_root( $theme ),
 880              'clear_destination' => true,
 881              'clear_working' => true,
 882              'hook_extra' => array(
 883                  'theme' => $theme,
 884                  'type' => 'theme',
 885                  'action' => 'update',
 886              ),
 887          ) );
 888  
 889          remove_filter('upgrader_pre_install', array($this, 'current_before'));
 890          remove_filter('upgrader_post_install', array($this, 'current_after'));
 891          remove_filter('upgrader_clear_destination', array($this, 'delete_old_theme'));
 892  
 893          if ( ! $this->result || is_wp_error($this->result) )
 894              return $this->result;
 895  
 896          wp_clean_themes_cache( $parsed_args['clear_update_cache'] );
 897  
 898          return true;
 899      }
 900  
 901  	function bulk_upgrade( $themes, $args = array() ) {
 902  
 903          $defaults = array(
 904              'clear_update_cache' => true,
 905          );
 906          $parsed_args = wp_parse_args( $args, $defaults );
 907  
 908          $this->init();
 909          $this->bulk = true;
 910          $this->upgrade_strings();
 911  
 912          $current = get_site_transient( 'update_themes' );
 913  
 914          add_filter('upgrader_pre_install', array($this, 'current_before'), 10, 2);
 915          add_filter('upgrader_post_install', array($this, 'current_after'), 10, 2);
 916          add_filter('upgrader_clear_destination', array($this, 'delete_old_theme'), 10, 4);
 917  
 918          $this->skin->header();
 919  
 920          // Connect to the Filesystem first.
 921          $res = $this->fs_connect( array(WP_CONTENT_DIR) );
 922          if ( ! $res ) {
 923              $this->skin->footer();
 924              return false;
 925          }
 926  
 927          $this->skin->bulk_header();
 928  
 929          // Only start maintenance mode if:
 930          // - running Multisite and there are one or more themes specified, OR
 931          // - a theme with an update available is currently in use.
 932          // @TODO: For multisite, maintenance mode should only kick in for individual sites if at all possible.
 933          $maintenance = ( is_multisite() && ! empty( $themes ) );
 934          foreach ( $themes as $theme )
 935              $maintenance = $maintenance || $theme == get_stylesheet() || $theme == get_template();
 936          if ( $maintenance )
 937              $this->maintenance_mode(true);
 938  
 939          $results = array();
 940  
 941          $this->update_count = count($themes);
 942          $this->update_current = 0;
 943          foreach ( $themes as $theme ) {
 944              $this->update_current++;
 945  
 946              $this->skin->theme_info = $this->theme_info($theme);
 947  
 948              if ( !isset( $current->response[ $theme ] ) ) {
 949                  $this->skin->set_result(true);
 950                  $this->skin->before();
 951                  $this->skin->feedback('up_to_date');
 952                  $this->skin->after();
 953                  $results[$theme] = true;
 954                  continue;
 955              }
 956  
 957              // Get the URL to the zip file
 958              $r = $current->response[ $theme ];
 959  
 960              $result = $this->run( array(
 961                  'package' => $r['package'],
 962                  'destination' => get_theme_root( $theme ),
 963                  'clear_destination' => true,
 964                  'clear_working' => true,
 965                  'hook_extra' => array(
 966                      'theme' => $theme
 967                  ),
 968              ) );
 969  
 970              $results[$theme] = $this->result;
 971  
 972              // Prevent credentials auth screen from displaying multiple times
 973              if ( false === $result )
 974                  break;
 975          } //end foreach $plugins
 976  
 977          $this->maintenance_mode(false);
 978  
 979          do_action( 'upgrader_process_complete', $this, array(
 980              'action' => 'update',
 981              'type' => 'theme',
 982              'bulk' => true,
 983              'themes' => $themes,
 984          ) );
 985  
 986          $this->skin->bulk_footer();
 987  
 988          $this->skin->footer();
 989  
 990          // Cleanup our hooks, in case something else does a upgrade on this connection.
 991          remove_filter('upgrader_pre_install', array($this, 'current_before'));
 992          remove_filter('upgrader_post_install', array($this, 'current_after'));
 993          remove_filter('upgrader_clear_destination', array($this, 'delete_old_theme'));
 994  
 995          // Refresh the Theme Update information
 996          wp_clean_themes_cache( $parsed_args['clear_update_cache'] );
 997  
 998          return $results;
 999      }
1000  
1001  	function check_package($source) {
1002          global $wp_filesystem;
1003  
1004          if ( is_wp_error($source) )
1005              return $source;
1006  
1007          // Check the folder contains a valid theme
1008          $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source);
1009          if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, lets not prevent installation.
1010              return $source;
1011  
1012          // A proper archive should have a style.css file in the single subdirectory
1013          if ( ! file_exists( $working_directory . 'style.css' ) )
1014              return new WP_Error( 'incompatible_archive_theme_no_style', $this->strings['incompatible_archive'], __( 'The theme is missing the <code>style.css</code> stylesheet.' ) );
1015  
1016          $info = get_file_data( $working_directory . 'style.css', array( 'Name' => 'Theme Name', 'Template' => 'Template' ) );
1017  
1018          if ( empty( $info['Name'] ) )
1019              return new WP_Error( 'incompatible_archive_theme_no_name', $this->strings['incompatible_archive'], __( "The <code>style.css</code> stylesheet doesn't contain a valid theme header." ) );
1020  
1021          // If it's not a child theme, it must have at least an index.php to be legit.
1022          if ( empty( $info['Template'] ) && ! file_exists( $working_directory . 'index.php' ) )
1023              return new WP_Error( 'incompatible_archive_theme_no_index', $this->strings['incompatible_archive'], __( 'The theme is missing the <code>index.php</code> file.' ) );
1024  
1025          return $source;
1026      }
1027  
1028  	function current_before($return, $theme) {
1029  
1030          if ( is_wp_error($return) )
1031              return $return;
1032  
1033          $theme = isset($theme['theme']) ? $theme['theme'] : '';
1034  
1035          if ( $theme != get_stylesheet() ) //If not current
1036              return $return;
1037          //Change to maintenance mode now.
1038          if ( ! $this->bulk )
1039              $this->maintenance_mode(true);
1040  
1041          return $return;
1042      }
1043  
1044  	function current_after($return, $theme) {
1045          if ( is_wp_error($return) )
1046              return $return;
1047  
1048          $theme = isset($theme['theme']) ? $theme['theme'] : '';
1049  
1050          if ( $theme != get_stylesheet() ) // If not current
1051              return $return;
1052  
1053          // Ensure stylesheet name hasn't changed after the upgrade:
1054          if ( $theme == get_stylesheet() && $theme != $this->result['destination_name'] ) {
1055              wp_clean_themes_cache();
1056              $stylesheet = $this->result['destination_name'];
1057              switch_theme( $stylesheet );
1058          }
1059  
1060          //Time to remove maintenance mode
1061          if ( ! $this->bulk )
1062              $this->maintenance_mode(false);
1063          return $return;
1064      }
1065  
1066  	function delete_old_theme( $removed, $local_destination, $remote_destination, $theme ) {
1067          global $wp_filesystem;
1068  
1069          if ( is_wp_error( $removed ) )
1070              return $removed; // Pass errors through.
1071  
1072          if ( ! isset( $theme['theme'] ) )
1073              return $removed;
1074  
1075          $theme = $theme['theme'];
1076          $themes_dir = trailingslashit( $wp_filesystem->wp_themes_dir( $theme ) );
1077          if ( $wp_filesystem->exists( $themes_dir . $theme ) ) {
1078              if ( ! $wp_filesystem->delete( $themes_dir . $theme, true ) )
1079                  return false;
1080          }
1081  
1082          return true;
1083      }
1084  
1085  	function theme_info($theme = null) {
1086  
1087          if ( empty($theme) ) {
1088              if ( !empty($this->result['destination_name']) )
1089                  $theme = $this->result['destination_name'];
1090              else
1091                  return false;
1092          }
1093          return wp_get_theme( $theme );
1094      }
1095  
1096  }
1097  
1098  add_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
1099  
1100  /**
1101   * Language pack upgrader, for updating translations of plugins, themes, and core.
1102   *
1103   * @package WordPress
1104   * @subpackage Upgrader
1105   * @since 3.7.0
1106   */
1107  class Language_Pack_Upgrader extends WP_Upgrader {
1108  
1109      var $result;
1110      var $bulk = true;
1111  
1112  	static function async_upgrade( $upgrader = false ) {
1113          // Avoid recursion.
1114          if ( $upgrader && $upgrader instanceof Language_Pack_Upgrader )
1115              return;
1116  
1117          // Nothing to do?
1118          $language_updates = wp_get_translation_updates();
1119          if ( ! $language_updates )
1120              return;
1121  
1122          $skin = new Language_Pack_Upgrader_Skin( array(
1123              'skip_header_footer' => true,
1124          ) );
1125  
1126          $lp_upgrader = new Language_Pack_Upgrader( $skin );
1127          $lp_upgrader->upgrade();
1128      }
1129  
1130  	function upgrade_strings() {
1131          $this->strings['starting_upgrade'] = __( 'Some of your translations need updating. Sit tight for a few more seconds while we update them as well.' );
1132          $this->strings['up_to_date'] = __( 'The translation is up to date.' ); // We need to silently skip this case
1133          $this->strings['no_package'] = __( 'Update package not available.' );
1134          $this->strings['downloading_package'] = __( 'Downloading translation from <span class="code">%s</span>&#8230;' );
1135          $this->strings['unpack_package'] = __( 'Unpacking the update&#8230;' );
1136          $this->strings['process_failed'] = __( 'Translation update failed.' );
1137          $this->strings['process_success'] = __( 'Translation updated successfully.' );
1138      }
1139  
1140  	function upgrade( $update = false, $args = array() ) {
1141          if ( $update )
1142              $update = array( $update );
1143          $results = $this->bulk_upgrade( $update, $args );
1144          return $results[0];
1145      }
1146  
1147  	function bulk_upgrade( $language_updates = array(), $args = array() ) {
1148          global $wp_filesystem;
1149  
1150          $defaults = array(
1151              'clear_update_cache' => true,
1152          );
1153          $parsed_args = wp_parse_args( $args, $defaults );
1154  
1155          $this->init();
1156          $this->upgrade_strings();
1157  
1158          if ( ! $language_updates )
1159              $language_updates = wp_get_translation_updates();
1160  
1161          if ( empty( $language_updates ) ) {
1162              $this->skin->header();
1163              $this->skin->before();
1164              $this->skin->set_result( true );
1165              $this->skin->feedback( 'up_to_date' );
1166              $this->skin->after();
1167              $this->skin->bulk_footer();
1168              $this->skin->footer();
1169              return true;
1170          }
1171  
1172          if ( 'upgrader_process_complete' == current_filter() )
1173              $this->skin->feedback( 'starting_upgrade' );
1174  
1175          add_filter( 'upgrader_source_selection', array( &$this, 'check_package' ), 10, 3 );
1176  
1177          $this->skin->header();
1178  
1179          // Connect to the Filesystem first.
1180          $res = $this->fs_connect( array( WP_CONTENT_DIR, WP_LANG_DIR ) );
1181          if ( ! $res ) {
1182              $this->skin->footer();
1183              return false;
1184          }
1185  
1186          $results = array();
1187  
1188          $this->update_count = count( $language_updates );
1189          $this->update_current = 0;
1190  
1191          // The filesystem's mkdir() is not recursive. Make sure WP_LANG_DIR exists,
1192          // as we then may need to create a /plugins or /themes directory inside of it.
1193          $remote_destination = $wp_filesystem->find_folder( WP_LANG_DIR );
1194          if ( ! $wp_filesystem->exists( $remote_destination ) )
1195              if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) )
1196                  return new WP_Error( 'mkdir_failed_lang_dir', $this->strings['mkdir_failed'], $remote_destination );
1197  
1198          foreach ( $language_updates as $language_update ) {
1199  
1200              $this->skin->language_update = $language_update;
1201  
1202              $destination = WP_LANG_DIR;
1203              if ( 'plugin' == $language_update->type )
1204                  $destination .= '/plugins';
1205              elseif ( 'theme' == $language_update->type )
1206                  $destination .= '/themes';
1207  
1208              $this->update_current++;
1209  
1210              $options = array(
1211                  'package' => $language_update->package,
1212                  'destination' => $destination,
1213                  'clear_destination' => false,
1214                  'abort_if_destination_exists' => false, // We expect the destination to exist.
1215                  'clear_working' => true,
1216                  'is_multi' => true,
1217                  'hook_extra' => array(
1218                      'language_update_type' => $language_update->type,
1219                      'language_update' => $language_update,
1220                  )
1221              );
1222  
1223              $result = $this->run( $options );
1224  
1225              $results[] = $this->result;
1226  
1227              // Prevent credentials auth screen from displaying multiple times.
1228              if ( false === $result )
1229                  break;
1230          }
1231  
1232          $this->skin->bulk_footer();
1233  
1234          $this->skin->footer();
1235  
1236          // Clean up our hooks, in case something else does an upgrade on this connection.
1237          remove_filter( 'upgrader_source_selection', array( &$this, 'check_package' ), 10, 2 );
1238  
1239          if ( $parsed_args['clear_update_cache'] ) {
1240              wp_clean_themes_cache( true );
1241              wp_clean_plugins_cache( true );
1242              delete_site_transient( 'update_core' );
1243          }
1244  
1245          return $results;
1246      }
1247  
1248  	function check_package( $source, $remote_source ) {
1249          global $wp_filesystem;
1250  
1251          if ( is_wp_error( $source ) )
1252              return $source;
1253  
1254          // Check that the folder contains a valid language.
1255          $files = $wp_filesystem->dirlist( $remote_source );
1256  
1257          // Check to see if a .po and .mo exist in the folder.
1258          $po = $mo = false;
1259          foreach ( (array) $files as $file => $filedata ) {
1260              if ( '.po' == substr( $file, -3 ) )
1261                  $po = true;
1262              elseif ( '.mo' == substr( $file, -3 ) )
1263                  $mo = true;
1264          }
1265  
1266          if ( ! $mo || ! $po )
1267              return new WP_Error( 'incompatible_archive_pomo', $this->strings['incompatible_archive'],
1268                  __( 'The language pack is missing either the <code>.po</code> or <code>.mo</code> files.' ) );
1269  
1270          return $source;
1271      }
1272  
1273  	function get_name_for_update( $update ) {
1274          switch ( $update->type ) {
1275              case 'core':
1276                  return 'WordPress'; // Not translated
1277                  break;
1278              case 'theme':
1279                  $theme = wp_get_theme( $update->slug );
1280                  if ( $theme->exists() )
1281                      return $theme->Get( 'Name' );
1282                  break;
1283              case 'plugin':
1284                  $plugin_data = get_plugins( '/' . $update->slug );
1285                  $plugin_data = array_shift( $plugin_data );
1286                  if ( $plugin_data )
1287                      return $plugin_data['Name'];
1288                  break;
1289          }
1290          return '';
1291      }
1292  
1293  }
1294  
1295  /**
1296   * Core Upgrader class for WordPress. It allows for WordPress to upgrade itself in combination with the wp-admin/includes/update-core.php file
1297   *
1298   * @package WordPress
1299   * @subpackage Upgrader
1300   * @since 2.8.0
1301   */
1302  class Core_Upgrader extends WP_Upgrader {
1303  
1304  	function upgrade_strings() {
1305          $this->strings['up_to_date'] = __('WordPress is at the latest version.');
1306          $this->strings['no_package'] = __('Update package not available.');
1307          $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
1308          $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
1309          $this->strings['copy_failed'] = __('Could not copy files.');
1310          $this->strings['copy_failed_space'] = __('Could not copy files. You may have run out of disk space.' );
1311          $this->strings['start_rollback'] = __( 'Attempting to roll back to previous version.' );
1312          $this->strings['rollback_was_required'] = __( 'Due to an error during updating, WordPress has rolled back to your previous version.' );
1313      }
1314  
1315  	function upgrade( $current, $args = array() ) {
1316          global $wp_filesystem;
1317  
1318          include  ABSPATH . WPINC . '/version.php'; // $wp_version;
1319  
1320          $start_time = time();
1321  
1322          $defaults = array(
1323              'pre_check_md5'    => true,
1324              'attempt_rollback' => false,
1325              'do_rollback'      => false,
1326          );
1327          $parsed_args = wp_parse_args( $args, $defaults );
1328  
1329          $this->init();
1330          $this->upgrade_strings();
1331  
1332          // Is an update available?
1333          if ( !isset( $current->response ) || $current->response == 'latest' )
1334              return new WP_Error('up_to_date', $this->strings['up_to_date']);
1335  
1336          $res = $this->fs_connect( array(ABSPATH, WP_CONTENT_DIR) );
1337          if ( ! $res || is_wp_error( $res ) ) {
1338              return $res;
1339          }
1340  
1341          $wp_dir = trailingslashit($wp_filesystem->abspath());
1342  
1343          $partial = true;
1344          if ( $parsed_args['do_rollback'] )
1345              $partial = false;
1346          elseif ( $parsed_args['pre_check_md5'] && ! $this->check_files() )
1347              $partial = false;
1348  
1349          // If partial update is returned from the API, use that, unless we're doing a reinstall.
1350          // If we cross the new_bundled version number, then use the new_bundled zip.
1351          // Don't though if the constant is set to skip bundled items.
1352          // If the API returns a no_content zip, go with it. Finally, default to the full zip.
1353          if ( $parsed_args['do_rollback'] && $current->packages->rollback )
1354              $to_download = 'rollback';
1355          elseif ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version && $partial )
1356              $to_download = 'partial';
1357          elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' )
1358              && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) )
1359              $to_download = 'new_bundled';
1360          elseif ( $current->packages->no_content )
1361              $to_download = 'no_content';
1362          else
1363              $to_download = 'full';
1364  
1365          $download = $this->download_package( $current->packages->$to_download );
1366          if ( is_wp_error($download) )
1367              return $download;
1368  
1369          $working_dir = $this->unpack_package( $download );
1370          if ( is_wp_error($working_dir) )
1371              return $working_dir;
1372  
1373          // Copy update-core.php from the new version into place.
1374          if ( !$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true) ) {
1375              $wp_filesystem->delete($working_dir, true);
1376              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' );
1377          }
1378          $wp_filesystem->chmod($wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE);
1379  
1380          require_once ( ABSPATH . 'wp-admin/includes/update-core.php' );
1381  
1382          if ( ! function_exists( 'update_core' ) )
1383              return new WP_Error( 'copy_failed_space', $this->strings['copy_failed_space'] );
1384  
1385          $result = update_core( $working_dir, $wp_dir );
1386  
1387          // In the event of an issue, we may be able to roll back.
1388          if ( $parsed_args['attempt_rollback'] && $current->packages->rollback && ! $parsed_args['do_rollback'] ) {
1389              $try_rollback = false;
1390              if ( is_wp_error( $result ) ) {
1391                  $error_code = $result->get_error_code();
1392                  // Not all errors are equal. These codes are critical: copy_failed__copy_dir,
1393                  // mkdir_failed__copy_dir, copy_failed__copy_dir_retry, and disk_full.
1394                  // do_rollback allows for update_core() to trigger a rollback if needed.
1395                  if ( false !== strpos( $error_code, 'do_rollback' ) )
1396                      $try_rollback = true;
1397                  elseif ( false !== strpos( $error_code, '__copy_dir' ) )
1398                      $try_rollback = true;
1399                  elseif ( 'disk_full' === $error_code )
1400                      $try_rollback = true;
1401              }
1402  
1403              if ( $try_rollback ) {
1404                  apply_filters( 'update_feedback', $result );
1405                  apply_filters( 'update_feedback', $this->strings['start_rollback'] );
1406  
1407                  $rollback_result = $this->upgrade( $current, array_merge( $parsed_args, array( 'do_rollback' => true ) ) );
1408  
1409                  $original_result = $result;
1410                  $result = new WP_Error( 'rollback_was_required', $this->strings['rollback_was_required'], (object) array( 'update' => $original_result, 'rollback' => $rollback_result ) );
1411              }
1412          }
1413  
1414          do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'core' ) );
1415  
1416          // Clear the current updates
1417          delete_site_transient( 'update_core' );
1418  
1419          if ( ! $parsed_args['do_rollback'] ) {
1420              $stats = array(
1421                  'update_type'      => $current->response,
1422                  'success'          => true,
1423                  'fs_method'        => $wp_filesystem->method,
1424                  'fs_method_forced' => defined( 'FS_METHOD' ) || has_filter( 'filesystem_method' ),
1425                  'time_taken'       => time() - $start_time,
1426                  'reported'         => $wp_version,
1427                  'attempted'        => $current->version,
1428              );
1429  
1430              if ( is_wp_error( $result ) ) {
1431                  $stats['success'] = false;
1432                  // Did a rollback occur?
1433                  if ( ! empty( $try_rollback ) ) {
1434                      $stats['error_code'] = $original_result->get_error_code();
1435                      $stats['error_data'] = $original_result->get_error_data();
1436                      // Was the rollback successful? If not, collect its error too.
1437                      $stats['rollback'] = ! is_wp_error( $rollback_result );
1438                      if ( is_wp_error( $rollback_result ) ) {
1439                          $stats['rollback_code'] = $rollback_result->get_error_code();
1440                          $stats['rollback_data'] = $rollback_result->get_error_data();
1441                      }
1442                  } else {
1443                      $stats['error_code'] = $result->get_error_code();
1444                      $stats['error_data'] = $result->get_error_data();
1445                  }
1446              }
1447  
1448              wp_version_check( $stats );
1449          }
1450  
1451          return $result;
1452      }
1453  
1454      // Determines if this WordPress Core version should update to $offered_ver or not
1455  	static function should_update_to_version( $offered_ver /* x.y.z */ ) {
1456          include  ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
1457  
1458          $current_branch = implode( '.', array_slice( preg_split( '/[.-]/', $wp_version  ), 0, 2 ) ); // x.y
1459          $new_branch     = implode( '.', array_slice( preg_split( '/[.-]/', $offered_ver ), 0, 2 ) ); // x.y
1460          $current_is_development_version = (bool) strpos( $wp_version, '-' );
1461  
1462          // Defaults:
1463          $upgrade_dev   = true;
1464          $upgrade_minor = true;
1465          $upgrade_major = false;
1466  
1467          // WP_AUTO_UPDATE_CORE = true (all), 'minor', false.
1468          if ( defined( 'WP_AUTO_UPDATE_CORE' ) ) {
1469              if ( false === WP_AUTO_UPDATE_CORE ) {
1470                  // Defaults to turned off, unless a filter allows it
1471                  $upgrade_dev = $upgrade_minor = $upgrade_major = false;
1472              } elseif ( true === WP_AUTO_UPDATE_CORE ) {
1473                  // ALL updates for core
1474                  $upgrade_dev = $upgrade_minor = $upgrade_major = true;
1475              } elseif ( 'minor' === WP_AUTO_UPDATE_CORE ) {
1476                  // Only minor updates for core
1477                  $upgrade_dev = $upgrade_major = false;
1478                  $upgrade_minor = true;
1479              }
1480          }
1481  
1482          // 1: If we're already on that version, not much point in updating?
1483          if ( $offered_ver == $wp_version )
1484              return false;
1485  
1486          // 2: If we're running a newer version, that's a nope
1487          if ( version_compare( $wp_version, $offered_ver, '>' ) )
1488              return false;
1489  
1490          $failure_data = get_site_option( 'auto_core_update_failed' );
1491          if ( $failure_data ) {
1492              // If this was a critical update failure, cannot update.
1493              if ( ! empty( $failure_data['critical'] ) )
1494                  return false;
1495  
1496              // Don't claim we can update on update-core.php if we have a non-critical failure logged.
1497              if ( $wp_version == $failure_data['current'] && false !== strpos( $offered_ver, '.1.next.minor' ) )
1498                  return false;
1499  
1500              // Cannot update if we're retrying the same A to B update that caused a non-critical failure.
1501              // Some non-critical failures do allow retries, like download_failed.
1502              // 3.7.1 => 3.7.2 resulted in files_not_writable, if we are still on 3.7.1 and still trying to update to 3.7.2.
1503              if ( empty( $failure_data['retry'] ) && $wp_version == $failure_data['current'] && $offered_ver == $failure_data['attempted'] )
1504                  return false;
1505          }
1506  
1507          // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2
1508          if ( $current_is_development_version ) {
1509              if ( ! apply_filters( 'allow_dev_auto_core_updates', $upgrade_dev ) )
1510                  return false;
1511              // else fall through to minor + major branches below
1512          }
1513  
1514          // 4: Minor In-branch updates (3.7.0 -> 3.7.1 -> 3.7.2 -> 3.7.4)
1515          if ( $current_branch == $new_branch )
1516              return apply_filters( 'allow_minor_auto_core_updates', $upgrade_minor );
1517  
1518          // 5: Major version updates (3.7.0 -> 3.8.0 -> 3.9.1)
1519          if ( version_compare( $new_branch, $current_branch, '>' ) )
1520              return apply_filters( 'allow_major_auto_core_updates', $upgrade_major );
1521  
1522          // If we're not sure, we don't want it
1523          return false;
1524      }
1525  
1526  	function check_files() {
1527          global $wp_version, $wp_local_package;
1528  
1529          $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' );
1530  
1531          if ( ! is_array( $checksums ) )
1532              return false;
1533  
1534          foreach ( $checksums as $file => $checksum ) {
1535              // Skip files which get updated
1536              if ( 'wp-content' == substr( $file, 0, 10 ) )
1537                  continue;
1538              if ( ! file_exists( ABSPATH . $file ) || md5_file( ABSPATH . $file ) !== $checksum )
1539                  return false;
1540          }
1541  
1542          return true;
1543      }
1544  }
1545  
1546  /**
1547   * Upgrade Skin helper for File uploads. This class handles the upload process and passes it as if it's a local file to the Upgrade/Installer functions.
1548   *
1549   * @package WordPress
1550   * @subpackage Upgrader
1551   * @since 2.8.0
1552   */
1553  class File_Upload_Upgrader {
1554      var $package;
1555      var $filename;
1556      var $id = 0;
1557  
1558  	function __construct($form, $urlholder) {
1559  
1560          if ( empty($_FILES[$form]['name']) && empty($_GET[$urlholder]) )
1561              wp_die(__('Please select a file'));
1562  
1563          //Handle a newly uploaded file, Else assume it's already been uploaded
1564          if ( ! empty($_FILES) ) {
1565              $overrides = array( 'test_form' => false, 'test_type' => false );
1566              $file = wp_handle_upload( $_FILES[$form], $overrides );
1567  
1568              if ( isset( $file['error'] ) )
1569                  wp_die( $file['error'] );
1570  
1571              $this->filename = $_FILES[$form]['name'];
1572              $this->package = $file['file'];
1573  
1574              // Construct the object array
1575              $object = array(
1576                  'post_title' => $this->filename,
1577                  'post_content' => $file['url'],
1578                  'post_mime_type' => $file['type'],
1579                  'guid' => $file['url'],
1580                  'context' => 'upgrader',
1581                  'post_status' => 'private'
1582              );
1583  
1584              // Save the data
1585              $this->id = wp_insert_attachment( $object, $file['file'] );
1586  
1587              // schedule a cleanup for 2 hours from now in case of failed install
1588              wp_schedule_single_event( time() + 7200, 'upgrader_scheduled_cleanup', array( $this->id ) );
1589  
1590          } elseif ( is_numeric( $_GET[$urlholder] ) ) {
1591              // Numeric Package = previously uploaded file, see above.
1592              $this->id = (int) $_GET[$urlholder];
1593              $attachment = get_post( $this->id );
1594              if ( empty($attachment) )
1595                  wp_die(__('Please select a file'));
1596  
1597              $this->filename = $attachment->post_title;
1598              $this->package = get_attached_file( $attachment->ID );
1599          } else {
1600              // Else, It's set to something, Back compat for plugins using the old (pre-3.3) File_Uploader handler.
1601              if ( ! ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) )
1602                  wp_die( $uploads['error'] );
1603  
1604              $this->filename = $_GET[$urlholder];
1605              $this->package = $uploads['basedir'] . '/' . $this->filename;
1606          }
1607      }
1608  
1609  	function cleanup() {
1610          if ( $this->id )
1611              wp_delete_attachment( $this->id );
1612  
1613          elseif ( file_exists( $this->package ) )
1614              return @unlink( $this->package );
1615  
1616          return true;
1617      }
1618  }
1619  
1620  /**
1621   * The WordPress automatic background updater.
1622   *
1623   * @package WordPress
1624   * @subpackage Upgrader
1625   * @since 3.7.0
1626   */
1627  class WP_Automatic_Updater {
1628  
1629      /**
1630       * Tracks update results during processing.
1631       *
1632       * @var array
1633       */
1634      protected $update_results = array();
1635  
1636      /**
1637       * Whether the entire automatic updater is disabled.
1638       *
1639       * @since 3.7.0
1640       */
1641  	public function is_disabled() {
1642          // Background updates are disabled if you don't want file changes.
1643          if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS )
1644              return true;
1645  
1646          if ( defined( 'WP_INSTALLING' ) )
1647              return true;
1648  
1649          // More fine grained control can be done through the WP_AUTO_UPDATE_CORE constant and filters.
1650          $disabled = defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED;
1651  
1652          /**
1653           * Filter whether to entirely disable background updates.
1654           *
1655           * There are more fine-grained filters and controls for selective disabling.
1656           * This filter parallels the AUTOMATIC_UPDATER_DISABLED constant in name.
1657           *
1658           * This also disables update notification emails. That may change in the future.
1659           *
1660           * @since 3.7.0
1661           * @param bool $disabled Whether the updater should be disabled.
1662           */
1663          return apply_filters( 'automatic_updater_disabled', $disabled );
1664      }
1665  
1666      /**
1667       * Check for version control checkouts.
1668       *
1669       * Checks for Subversion, Git, Mercurial, and Bazaar. It recursively looks up the
1670       * filesystem to the top of the drive, erring on the side of detecting a VCS
1671       * checkout somewhere.
1672       *
1673       * ABSPATH is always checked in addition to whatever $context is (which may be the
1674       * wp-content directory, for example). The underlying assumption is that if you are
1675       * using version control *anywhere*, then you should be making decisions for
1676       * how things get updated.
1677       *
1678       * @since 3.7.0
1679       *
1680       * @param string $context The filesystem path to check, in addition to ABSPATH.
1681       */
1682  	public function is_vcs_checkout( $context ) {
1683          $context_dirs = array( untrailingslashit( $context ) );
1684          if ( $context !== ABSPATH )
1685              $context_dirs[] = untrailingslashit( ABSPATH );
1686  
1687          $vcs_dirs = array( '.svn', '.git', '.hg', '.bzr' );
1688          $check_dirs = array();
1689  
1690          foreach ( $context_dirs as $context_dir ) {
1691              // Walk up from $context_dir to the root.
1692              do {
1693                  $check_dirs[] = $context_dir;
1694  
1695                  // Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here.
1696                  if ( $context_dir == dirname( $context_dir ) )
1697                      break;
1698  
1699              // Continue one level at a time.
1700              } while ( $context_dir = dirname( $context_dir ) );
1701          }
1702  
1703          $check_dirs = array_unique( $check_dirs );
1704  
1705          // Search all directories we've found for evidence of version control.
1706          foreach ( $vcs_dirs as $vcs_dir ) {
1707              foreach ( $check_dirs as $check_dir ) {
1708                  if ( $checkout = @is_dir( rtrim( $check_dir, '\\/' ) . "/$vcs_dir" ) )
1709                      break 2;
1710              }
1711          }
1712  
1713          /**
1714           * Filter whether the automatic updater should consider a filesystem location to be potentially
1715           * managed by a version control system.
1716           *
1717           * @since 3.7.0
1718           *
1719           * @param bool $checkout  Whether a VCS checkout was discovered at $context or ABSPATH, or anywhere higher.
1720           * @param string $context The filesystem context (a path) against which filesystem status should be checked.
1721           */
1722          return apply_filters( 'automatic_updates_is_vcs_checkout', $checkout, $context );
1723      }
1724  
1725      /**
1726       * Tests to see if we can and should update a specific item.
1727       *
1728       * @since 3.7.0
1729       *
1730       * @param string $type    The type of update being checked: 'core', 'theme', 'plugin', 'translation'.
1731       * @param object $item    The update offer.
1732       * @param string $context The filesystem context (a path) against which filesystem access and status
1733       *                        should be checked.
1734       */
1735  	public function should_update( $type, $item, $context ) {
1736          // Used to see if WP_Filesystem is set up to allow unattended updates.
1737          $skin = new Automatic_Upgrader_Skin;
1738  
1739          if ( $this->is_disabled() )
1740              return false;
1741  
1742          // If we can't do an auto core update, we may still be able to email the user.
1743          if ( ! $skin->request_filesystem_credentials( false, $context ) || $this->is_vcs_checkout( $context ) ) {
1744              if ( 'core' == $type )
1745                  $this->send_core_update_notification_email( $item );
1746              return false;
1747          }
1748  
1749          // Next up, is this an item we can update?
1750          if ( 'core' == $type )
1751              $update = Core_Upgrader::should_update_to_version( $item->current );
1752          else
1753              $update = ! empty( $item->autoupdate );
1754  
1755          /**
1756           * Filter whether to automatically update core, a plugin, a theme, or a language.
1757           *
1758           * The dynamic portion of the hook name, $type, refers to the type of update
1759           * being checked. Can be 'core', 'theme', 'plugin', or 'translation'.
1760           *
1761           * Generally speaking, plugins, themes, and major core versions are not updated by default,
1762           * while translations and minor and development versions for core are updated by default.
1763           *
1764           * See the filters allow_dev_auto_core_updates, allow_minor_auto_core_updates, and
1765           * allow_major_auto_core_updates more straightforward filters to adjust core updates.
1766           *
1767           * @since 3.7.0
1768           *
1769           * @param bool   $update Whether to update.
1770           * @param object $item   The update offer.
1771           */
1772          $update = apply_filters( 'auto_update_' . $type, $update, $item );
1773  
1774          if ( ! $update ) {
1775              if ( 'core' == $type )
1776                  $this->send_core_update_notification_email( $item );
1777              return false;
1778          }
1779  
1780          // If it's a core update, are we actually compatible with its requirements?
1781          if ( 'core' == $type ) {
1782              global $wpdb;
1783  
1784              $php_compat = version_compare( phpversion(), $item->php_version, '>=' );
1785              if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) )
1786                  $mysql_compat = true;
1787              else
1788                  $mysql_compat = version_compare( $wpdb->db_version(), $item->mysql_version, '>=' );
1789  
1790              if ( ! $php_compat || ! $mysql_compat )
1791                  return false;
1792          }
1793  
1794          return true;
1795      }
1796  
1797      /**
1798       * Notifies an administrator of a core update.
1799       *
1800       * @since 3.7.0
1801       *
1802       * @param object $item The update offer.
1803       */
1804  	protected function send_core_update_notification_email( $item ) {
1805          $notify   = true;
1806          $notified = get_site_option( 'auto_core_update_notified' );
1807  
1808          // Don't notify if we've already notified the same email address of the same version.
1809          if ( $notified && $notified['email'] == get_site_option( 'admin_email' ) && $notified['version'] == $item->current )
1810              return false;
1811  
1812          // See if we need to notify users of a core update.
1813          $notify = ! empty( $item->notify_email );
1814  
1815          /**
1816           * Whether to notify the site administrator of a new core update.
1817           *
1818           * By default, administrators are notified when the update offer received from WordPress.org
1819           * sets a particular flag. This allows for discretion in if and when to notify.
1820           *
1821           * This filter only fires once per release -- if the same email address was already
1822           * notified of the same new version, we won't repeatedly email the administrator.
1823           *
1824           * This filter is also used on about.php to check if a plugin has disabled these notifications.
1825           *
1826           * @since 3.7.0
1827           *
1828           * @param bool $notify Whether the site administrator is notified.
1829           * @param object $item The update offer.
1830           */
1831          if ( ! apply_filters( 'send_core_update_notification_email', $notify, $item ) )
1832              return false;
1833  
1834          $this->send_email( 'manual', $item );
1835          return true;
1836      }
1837  
1838      /**
1839       * Update an item, if appropriate.
1840       *
1841       * @since 3.7.0
1842       *
1843       * @param string $type The type of update being checked: 'core', 'theme', 'plugin', 'translation'.
1844       * @param object $item The update offer.
1845       */
1846  	public function update( $type, $item ) {
1847          $skin = new Automatic_Upgrader_Skin;
1848  
1849          switch ( $type ) {
1850              case 'core':
1851                  // The Core upgrader doesn't use the Upgrader's skin during the actual main part of the upgrade, instead, firing a filter.
1852                  add_filter( 'update_feedback', array( $skin, 'feedback' ) );
1853                  $upgrader = new Core_Upgrader( $skin );
1854                  $context  = ABSPATH;
1855                  break;
1856              case 'plugin':
1857                  $upgrader = new Plugin_Upgrader( $skin );
1858                  $context  = WP_PLUGIN_DIR; // We don't support custom Plugin directories, or updates for WPMU_PLUGIN_DIR
1859                  break;
1860              case 'theme':
1861                  $upgrader = new Theme_Upgrader( $skin );
1862                  $context  = get_theme_root( $item );
1863                  break;
1864              case 'translation':
1865                  $upgrader = new Language_Pack_Upgrader( $skin );
1866                  $context  = WP_CONTENT_DIR; // WP_LANG_DIR;
1867                  break;
1868          }
1869  
1870          // Determine whether we can and should perform this update.
1871          if ( ! $this->should_update( $type, $item, $context ) )
1872              return false;
1873  
1874          switch ( $type ) {
1875              case 'core':
1876                  $skin->feedback( __( 'Updating to WordPress %s' ), $item->version );
1877                  $item_name = sprintf( __( 'WordPress %s' ), $item->version );
1878                  break;
1879              case 'theme':
1880                  $theme = wp_get_theme( $item );
1881                  $item_name = $theme->Get( 'Name' );
1882                  $skin->feedback( __( 'Updating theme: %s' ), $item_name );
1883                  break;
1884              case 'plugin':
1885                  $plugin_data = get_plugin_data( $context . '/' . $item );
1886                  $item_name = $plugin_data['Name'];
1887                  $skin->feedback( __( 'Updating plugin: %s' ), $item_name );
1888                  break;
1889              case 'translation':
1890                  $language_item_name = $upgrader->get_name_for_update( $item );
1891                  $item_name = sprintf( __( 'Translations for %s' ), $language_item_name );
1892                  $skin->feedback( sprintf( __( 'Updating translations for %1$s (%2$s)&#8230;' ), $language_item_name, $item->language ) );
1893                  break;
1894          }
1895  
1896          // Boom, This sites about to get a whole new splash of paint!
1897          $upgrade_result = $upgrader->upgrade( $item, array(
1898              'clear_update_cache' => false,
1899              'pre_check_md5'      => false, /* always use partial builds if possible for core updates */
1900              'attempt_rollback'   => true, /* only available for core updates */
1901          ) );
1902  
1903          // if the filesystem is unavailable, false is returned.
1904          if ( false === $upgrade_result ) {
1905              $upgrade_result = new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) );
1906          }
1907  
1908          // Core doesn't output this, so lets append it so we don't get confused
1909          if ( 'core' == $type ) {
1910              if ( is_wp_error( $upgrade_result ) ) {
1911                  $skin->error( __( 'Installation Failed' ), $upgrade_result );
1912              } else {
1913                  $skin->feedback( __( 'WordPress updated successfully' ) );
1914              }
1915          }
1916  
1917          $this->update_results[ $type ][] = (object) array(
1918              'item'     => $item,
1919              'result'   => $upgrade_result,
1920              'name'     => $item_name,
1921              'messages' => $skin->get_upgrade_messages()
1922          );
1923  
1924          return $upgrade_result;
1925      }
1926  
1927      /**
1928       * Kicks off the background update process, looping through all pending updates.
1929       *
1930       * @since 3.7.0
1931       */
1932  	public function run() {
1933          global $wpdb, $wp_version;
1934  
1935          if ( $this->is_disabled() )
1936              return;
1937  
1938          if ( ! is_main_network() || ! is_main_site() )
1939              return;
1940  
1941          $lock_name = 'auto_updater.lock';
1942  
1943          // Try to lock
1944          $lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) );
1945  
1946          if ( ! $lock_result ) {
1947              $lock_result = get_option( $lock_name );
1948  
1949              // If we couldn't create a lock, and there isn't a lock, bail
1950              if ( ! $lock_result )
1951                  return;
1952  
1953              // Check to see if the lock is still valid
1954              if ( $lock_result > ( time() - HOUR_IN_SECONDS ) )
1955                  return;
1956          }
1957  
1958          // Update the lock, as by this point we've definately got a lock, just need to fire the actions
1959          update_option( $lock_name, time() );
1960  
1961          // Don't automatically run these thins, as we'll handle it ourselves
1962          remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
1963          remove_action( 'upgrader_process_complete', 'wp_version_check' );
1964          remove_action( 'upgrader_process_complete', 'wp_update_plugins' );
1965          remove_action( 'upgrader_process_complete', 'wp_update_themes' );
1966  
1967          // Next, Plugins
1968          wp_update_plugins(); // Check for Plugin updates
1969          $plugin_updates = get_site_transient( 'update_plugins' );
1970          if ( $plugin_updates && !empty( $plugin_updates->response ) ) {
1971              foreach ( array_keys( $plugin_updates->response ) as $plugin ) {
1972                  $this->update( 'plugin', $plugin );
1973              }
1974              // Force refresh of plugin update information
1975              wp_clean_plugins_cache();
1976          }
1977  
1978          // Next, those themes we all love
1979          wp_update_themes();  // Check for Theme updates
1980          $theme_updates = get_site_transient( 'update_themes' );
1981          if ( $theme_updates && !empty( $theme_updates->response ) ) {
1982              foreach ( array_keys( $theme_updates->response ) as $theme ) {
1983                  $this->update( 'theme', $theme );
1984              }
1985              // Force refresh of theme update information
1986              wp_clean_themes_cache();
1987          }
1988  
1989          // Next, Process any core update
1990          wp_version_check(); // Check for Core updates
1991          $core_update = find_core_auto_update();
1992  
1993          if ( $core_update )
1994              $this->update( 'core', $core_update );
1995  
1996          // Clean up, and check for any pending translations
1997          // (Core_Upgrader checks for core updates)
1998          wp_update_themes();  // Check for Theme updates
1999          wp_update_plugins(); // Check for Plugin updates
2000  
2001          // Finally, Process any new translations
2002          $language_updates = wp_get_translation_updates();
2003          if ( $language_updates ) {
2004              foreach ( $language_updates as $update ) {
2005                  $this->update( 'translation', $update );
2006              }
2007  
2008              // Clear existing caches
2009              wp_clean_plugins_cache();
2010              wp_clean_themes_cache();
2011              delete_site_transient( 'update_core' );
2012  
2013              wp_version_check();  // check for Core updates
2014              wp_update_themes();  // Check for Theme updates
2015              wp_update_plugins(); // Check for Plugin updates
2016          }
2017  
2018          // Send debugging email to all development installs.
2019          if ( ! empty( $this->update_results ) ) {
2020              $development_version = false !== strpos( $wp_version, '-' );
2021              /**
2022               * Filter whether to send a debugging email for each automatic background update.
2023               *
2024               * @since 3.7.0
2025               * @param bool $development_version By default, emails are sent if the install is a development version.
2026               *                                  Return false to avoid the email.
2027               */
2028              if ( apply_filters( 'automatic_updates_send_debug_email', $development_version ) )
2029                  $this->send_debug_email();
2030  
2031              if ( ! empty( $this->update_results['core'] ) )
2032                  $this->after_core_update( $this->update_results['core'][0] );
2033  
2034              /**
2035                * Action triggered after all automatic updates have run.
2036                *
2037                * @since 3.8.0
2038                *
2039                * @param array $update_results The results of all attempted updates.
2040                */
2041              do_action( 'automatic_updates_complete', $this->update_results );
2042          }
2043  
2044          // Clear the lock
2045          delete_option( $lock_name );
2046      }
2047  
2048      /**
2049       * If we tried to perform a core update, check if we should send an email,
2050       * and if we need to avoid processing future updates.
2051       *
2052       * @param object $update_result The result of the core update. Includes the update offer and result.
2053       */
2054  	protected function after_core_update( $update_result ) {
2055          global $wp_version;
2056  
2057          $core_update = $update_result->item;
2058          $result      = $update_result->result;
2059  
2060          if ( ! is_wp_error( $result ) ) {
2061              $this->send_email( 'success', $core_update );
2062              return;
2063          }
2064  
2065          $error_code = $result->get_error_code();
2066  
2067          // Any of these WP_Error codes are critical failures, as in they occurred after we started to copy core files.
2068          // We should not try to perform a background update again until there is a successful one-click update performed by the user.
2069          $critical = false;
2070          if ( $error_code === 'disk_full' || false !== strpos( $error_code, '__copy_dir' ) ) {
2071              $critical = true;
2072          } elseif ( $error_code === 'rollback_was_required' && is_wp_error( $result->get_error_data()->rollback ) ) {
2073              // A rollback is only critical if it failed too.
2074              $critical = true;
2075              $rollback_result = $result->get_error_data()->rollback;
2076          } elseif ( false !== strpos( $error_code, 'do_rollback' ) ) {
2077              $critical = true;
2078          }
2079  
2080          if ( $critical ) {
2081              $critical_data = array(
2082                  'attempted'  => $core_update->current,
2083                  'current'    => $wp_version,
2084                  'error_code' => $error_code,
2085                  'error_data' => $result->get_error_data(),
2086                  'timestamp'  => time(),
2087                  'critical'   => true,
2088              );
2089              if ( isset( $rollback_result ) ) {
2090                  $critical_data['rollback_code'] = $rollback_result->get_error_code();
2091                  $critical_data['rollback_data'] = $rollback_result->get_error_data();
2092              }
2093              update_site_option( 'auto_core_update_failed', $critical_data );
2094              $this->send_email( 'critical', $core_update, $result );
2095              return;
2096          }
2097  
2098          /*
2099           * Any other WP_Error code (like download_failed or files_not_writable) occurs before
2100           * we tried to copy over core files. Thus, the failures are early and graceful.
2101           *
2102           * We should avoid trying to perform a background update again for the same version.
2103           * But we can try again if another version is released.
2104           *
2105           * For certain 'transient' failures, like download_failed, we should allow retries.
2106           * In fact, let's schedule a special update for an hour from now. (It's possible
2107           * the issue could actually be on WordPress.org's side.) If that one fails, then email.
2108           */
2109          $send = true;
2110            $transient_failures = array( 'incompatible_archive', 'download_failed', 'insane_distro' );
2111            if ( in_array( $error_code, $transient_failures ) && ! get_site_option( 'auto_core_update_failed' ) ) {
2112                wp_schedule_single_event( time() + HOUR_IN_SECONDS, 'wp_maybe_auto_update' );
2113                $send = false;
2114            }
2115  
2116            $n = get_site_option( 'auto_core_update_notified' );
2117          // Don't notify if we've already notified the same email address of the same version of the same notification type.
2118          if ( $n && 'fail' == $n['type'] && $n['email'] == get_site_option( 'admin_email' ) && $n['version'] == $core_update->current )
2119              $send = false;
2120  
2121          update_site_option( 'auto_core_update_failed', array(
2122              'attempted'  => $core_update->current,
2123              'current'    => $wp_version,
2124              'error_code' => $error_code,
2125              'error_data' => $result->get_error_data(),
2126              'timestamp'  => time(),
2127              'retry'      => in_array( $error_code, $transient_failures ),
2128          ) );
2129  
2130          if ( $send )
2131              $this->send_email( 'fail', $core_update, $result );
2132      }
2133  
2134      /**
2135       * Sends an email upon the completion or failure of a background core update.
2136       *
2137       * @since 3.7.0
2138       *
2139       * @param string $type        The type of email to send. Can be one of 'success', 'fail', 'manual', 'critical'.
2140       * @param object $core_update The update offer that was attempted.
2141       * @param mixed  $result      Optional. The result for the core update. Can be WP_Error.
2142       */
2143  	protected function send_email( $type, $core_update, $result = null ) {
2144          update_site_option( 'auto_core_update_notified', array(
2145              'type'      => $type,
2146              'email'     => get_site_option( 'admin_email' ),
2147              'version'   => $core_update->current,
2148              'timestamp' => time(),
2149          ) );
2150  
2151          $next_user_core_update = get_preferred_from_update_core();
2152          // If the update transient is empty, use the update we just performed
2153          if ( ! $next_user_core_update )
2154              $next_user_core_update = $core_update;
2155          $newer_version_available = ( 'upgrade' == $next_user_core_update->response && version_compare( $next_user_core_update->version, $core_update->version, '>' ) );
2156  
2157          /**
2158           * Filter whether to send an email following an automatic background core update.
2159           *
2160           * @since 3.7.0
2161           *
2162           * @param bool   $send        Whether to send the email. Default true.
2163           * @param string $type        The type of email to send. Can be one of 'success', 'fail', 'critical'.
2164           * @param object $core_update The update offer that was attempted.
2165           * @param mixed  $result      The result for the core update. Can be WP_Error.
2166           */
2167          if ( 'manual' !== $type && ! apply_filters( 'auto_core_update_send_email', true, $type, $core_update, $result ) )
2168              return;
2169  
2170          switch ( $type ) {
2171              case 'success' : // We updated.
2172                  /* translators: 1: Site name, 2: WordPress version number. */
2173                  $subject = __( '[%1$s] Your site has updated to WordPress %2$s' );
2174                  break;
2175  
2176              case 'fail' :   // We tried to update but couldn't.
2177              case 'manual' : // We can't update (and made no attempt).
2178                  /* translators: 1: Site name, 2: WordPress version number. */
2179                  $subject = __( '[%1$s] WordPress %2$s is available. Please update!' );
2180                  break;
2181  
2182              case 'critical' : // We tried to update, started to copy files, then things went wrong.
2183                  /* translators: 1: Site name. */
2184                  $subject = __( '[%1$s] URGENT: Your site may be down due to a failed update' );
2185                  break;
2186  
2187              default :
2188                  return;
2189          }
2190  
2191          // If the auto update is not to the latest version, say that the current version of WP is available instead.
2192          $version = 'success' === $type ? $core_update->current : $next_user_core_update->current;
2193          $subject = sprintf( $subject, wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), $version );
2194  
2195          $body = '';
2196  
2197          switch ( $type ) {
2198              case 'success' :
2199                  $body .= sprintf( __( 'Howdy! Your site at %1$s has been updated automatically to WordPress %2$s.' ), home_url(), $core_update->current );
2200                  $body .= "\n\n";
2201                  if ( ! $newer_version_available )
2202                      $body .= __( 'No further action is needed on your part.' ) . ' ';
2203  
2204                  // Can only reference the About screen if their update was successful.
2205                  list( $about_version ) = explode( '-', $core_update->current, 2 );
2206                  $body .= sprintf( __( "For more on version %s, see the About WordPress screen:" ), $about_version );
2207                  $body .= "\n" . admin_url( 'about.php' );
2208  
2209                  if ( $newer_version_available ) {
2210                      $body .= "\n\n" . sprintf( __( 'WordPress %s is also now available.' ), $next_user_core_update->current ) . ' ';
2211                      $body .= __( 'Updating is easy and only takes a few moments:' );
2212                      $body .= "\n" . network_admin_url( 'update-core.php' );
2213                  }
2214  
2215                  break;
2216  
2217              case 'fail' :
2218              case 'manual' :
2219                  $body .= sprintf( __( 'Please update your site at %1$s to WordPress %2$s.' ), home_url(), $next_user_core_update->current );
2220  
2221                  $body .= "\n\n";
2222  
2223                  // Don't show this message if there is a newer version available.
2224                  // Potential for confusion, and also not useful for them to know at this point.
2225                  if ( 'fail' == $type && ! $newer_version_available )
2226                      $body .= __( 'We tried but were unable to update your site automatically.' ) . ' ';
2227  
2228                  $body .= __( 'Updating is easy and only takes a few moments:' );
2229                  $body .= "\n" . network_admin_url( 'update-core.php' );
2230                  break;
2231  
2232              case 'critical' :
2233                  if ( $newer_version_available )
2234                      $body .= sprintf( __( 'Your site at %1$s experienced a critical failure while trying to update WordPress to version %2$s.' ), home_url(), $core_update->current );
2235                  else
2236                      $body .= sprintf( __( 'Your site at %1$s experienced a critical failure while trying to update to the latest version of WordPress, %2$s.' ), home_url(), $core_update->current );
2237  
2238                  $body .= "\n\n" . __( "This means your site may be offline or broken. Don't panic; this can be fixed." );
2239  
2240                  $body .= "\n\n" . __( "Please check out your site now. It's possible that everything is working. If it says you need to update, you should do so:" );
2241                  $body .= "\n" . network_admin_url( 'update-core.php' );
2242                  break;
2243          }
2244  
2245          // Updates are important!
2246          if ( $type != 'success' || $newer_version_available )
2247              $body .= "\n\n" . __( 'Keeping your site updated is important for security. It also makes the internet a safer place for you and your readers.' );
2248  
2249          // Add a note about the support forums to all emails.
2250          $body .= "\n\n" . __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' );
2251          $body .= "\n" . __( 'http://wordpress.org/support/' );
2252  
2253          // If things are successful and we're now on the latest, mention plugins and themes if any are out of date.
2254          if ( $type == 'success' && ! $newer_version_available && ( get_plugin_updates() || get_theme_updates() ) ) {
2255              $body .= "\n\n" . __( 'You also have some plugins or themes with updates available. Update them now:' );
2256              $body .= "\n" . network_admin_url();
2257          }
2258  
2259          $body .= "\n\n" . __( 'The WordPress Team' ) . "\n";
2260  
2261          if ( 'critical' == $type && is_wp_error( $result ) ) {
2262              $body .= "\n***\n\n";
2263              $body .= sprintf( __( 'Your site was running version %s.' ), $GLOBALS['wp_version'] );
2264              $body .= ' ' . __( 'We have some data that describes the error your site encountered.' );
2265              $body .= ' ' . __( 'Your hosting company, support forum volunteers, or a friendly developer may be able to use this information to help you:' );
2266  
2267              // If we had a rollback and we're still critical, then the rollback failed too.
2268              // Loop through all errors (the main WP_Error, the update result, the rollback result) for code, data, etc.
2269              if ( 'rollback_was_required' == $result->get_error_code() )
2270                  $errors = array( $result, $result->get_error_data()->update, $result->get_error_data()->rollback );
2271              else
2272                  $errors = array( $result );
2273  
2274              foreach ( $errors as $error ) {
2275                  if ( ! is_wp_error( $error ) )
2276                      continue;
2277                  $error_code = $error->get_error_code();
2278                  $body .= "\n\n" . sprintf( __( "Error code: %s" ), $error_code );
2279                  if ( 'rollback_was_required' == $error_code )
2280                      continue;
2281                  if ( $error->get_error_message() )
2282                      $body .= "\n" . $error->get_error_message();
2283                  $error_data = $error->get_error_data();
2284                  if ( $error_data )
2285                      $body .= "\n" . implode( ', ', (array) $error_data );
2286              }
2287              $body .= "\n";
2288          }
2289  
2290          $to  = get_site_option( 'admin_email' );
2291          $headers = '';
2292  
2293          $email = compact( 'to', 'subject', 'body', 'headers' );
2294          /**
2295           * Filter the email sent following an automatic background core update.
2296           *
2297           * @since 3.7.0
2298           *
2299           * @param array $email {
2300           *     Array of email arguments that will be passed to wp_mail().
2301           *
2302           *     @type string $to      The email recipient. An array of emails can be returned, as handled by wp_mail().
2303           *     @type string $subject The email's subject.
2304           *     @type string $body    The email message body.
2305           *     @type string $headers Any email headers, defaults to no headers.
2306           * }
2307           * @param string $type        The type of email being sent. Can be one of 'success', 'fail', 'manual', 'critical'.
2308           * @param object $core_update The update offer that was attempted.
2309           * @param mixed  $result      The result for the core update. Can be WP_Error.
2310           */
2311          $email = apply_filters( 'auto_core_update_email', $email, $type, $core_update, $result );
2312  
2313          wp_mail( $email['to'], $email['subject'], $email['body'], $email['headers'] );
2314      }
2315  
2316      /**
2317       * Prepares and sends an email of a full log of background update results, useful for debugging and geekery.
2318       *
2319       * @since 3.7.0
2320       */
2321  	protected function send_debug_email() {
2322          $update_count = 0;
2323          foreach ( $this->update_results as $type => $updates )
2324              $update_count += count( $updates );
2325  
2326          $body = array();
2327          $failures = 0;
2328  
2329          $body[] = sprintf( __( 'WordPress site: %s' ), network_home_url( '/' ) );
2330  
2331          // Core
2332          if ( isset( $this->update_results['core'] ) ) {
2333              $result = $this->update_results['core'][0];
2334              if ( $result->result && ! is_wp_error( $result->result ) ) {
2335                  $body[] = sprintf( __( 'SUCCESS: WordPress was successfully updated to %s' ), $result->name );
2336              } else {
2337                  $body[] = sprintf( __( 'FAILED: WordPress failed to update to %s' ), $result->name );
2338                  $failures++;
2339              }
2340              $body[] = '';
2341          }
2342  
2343          // Plugins, Themes, Translations
2344          foreach ( array( 'plugin', 'theme', 'translation' ) as $type ) {
2345              if ( ! isset( $this->update_results[ $type ] ) )
2346                  continue;
2347              $success_items = wp_list_filter( $this->update_results[ $type ], array( 'result' => true ) );
2348              if ( $success_items ) {
2349                  $messages = array(
2350                      'plugin'      => __( 'The following plugins were successfully updated:' ),
2351                      'theme'       => __( 'The following themes were successfully updated:' ),
2352                      'translation' => __( 'The following translations were successfully updated:' ),
2353                  );
2354  
2355                  $body[] = $messages[ $type ];
2356                  foreach ( wp_list_pluck( $success_items, 'name' ) as $name ) {
2357                      $body[] = ' * ' . sprintf( __( 'SUCCESS: %s' ), $name );
2358                  }
2359              }
2360              if ( $success_items != $this->update_results[ $type ] ) {
2361                  // Failed updates
2362                  $messages = array(
2363                      'plugin'      => __( 'The following plugins failed to update:' ),
2364                      'theme'       => __( 'The following themes failed to update:' ),
2365                      'translation' => __( 'The following translations failed to update:' ),
2366                  );
2367  
2368                  $body[] = $messages[ $type ];
2369                  foreach ( $this->update_results[ $type ] as $item ) {
2370                      if ( ! $item->result || is_wp_error( $item->result ) ) {
2371                          $body[] = ' * ' . sprintf( __( 'FAILED: %s' ), $item->name );
2372                          $failures++;
2373                      }
2374                  }
2375              }
2376              $body[] = '';
2377          }
2378  
2379          $site_title = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES );
2380          if ( $failures ) {
2381              $body[] = __( "
2382  BETA TESTING?
2383  =============
2384  
2385  This debugging email is sent when you are using a development version of WordPress.
2386  
2387  If you think these failures might be due to a bug in WordPress, could you report it?
2388   * Open a thread in the support forums: http://wordpress.org/support/forum/alphabeta
2389   * Or, if you're comfortable writing a bug report: http://core.trac.wordpress.org/
2390  
2391  Thanks! -- The WordPress Team" );
2392  
2393              $subject = sprintf( __( '[%s] There were failures during background updates' ), $site_title );
2394          } else {
2395              $subject = sprintf( __( '[%s] Background updates have finished' ), $site_title );
2396          }
2397  
2398          $body[] = __( 'UPDATE LOG' );
2399          $body[] = '==========';
2400          $body[] = '';
2401  
2402          foreach ( array( 'core', 'plugin', 'theme', 'translation' ) as $type ) {
2403              if ( ! isset( $this->update_results[ $type ] ) )
2404                  continue;
2405              foreach ( $this->update_results[ $type ] as $update ) {
2406                  $body[] = $update->name;
2407                  $body[] = str_repeat( '-', strlen( $update->name ) );
2408                  foreach ( $update->messages as $message )
2409                      $body[] = "  " . html_entity_decode( str_replace( '&#8230;', '...', $message ) );
2410                  if ( is_wp_error( $update->result ) ) {
2411                      $results = array( 'update' => $update->result );
2412                      // If we rolled back, we want to know an error that occurred then too.
2413                      if ( 'rollback_was_required' === $update->result->get_error_code() )
2414                          $results = (array) $update->result->get_error_data();
2415                      foreach ( $results as $result_type => $result ) {
2416                          if ( ! is_wp_error( $result ) )
2417                              continue;
2418  
2419                          if ( 'rollback' === $result_type ) {
2420                              /* translators: 1: Error code, 2: Error message. */
2421                              $body[] = '  ' . sprintf( __( 'Rollback Error: [%1$s] %2$s' ), $result->get_error_code(), $result->get_error_message() );
2422                          } else {
2423                              /* translators: 1: Error code, 2: Error message. */
2424                              $body[] = '  ' . sprintf( __( 'Error: [%1$s] %2$s' ), $result->get_error_code(), $result->get_error_message() );
2425                          }
2426  
2427                          if ( $result->get_error_data() )
2428                              $body[] = '         ' . implode( ', ', (array) $result->get_error_data() );
2429                      }
2430                  }
2431                  $body[] = '';
2432              }
2433          }
2434  
2435          $email = array(
2436              'to'      => get_site_option( 'admin_email' ),
2437              'subject' => $subject,
2438              'body'    => implode( "\n", $body ),
2439              'headers' => ''
2440          );
2441  
2442          /**
2443           * Filter the debug email that can be sent following an automatic background core update.
2444           *
2445           * @since 3.8.0
2446           *
2447           * @param array $email {
2448           *     Array of email arguments that will be passed to wp_mail().
2449           *
2450           *     @type string $to      The email recipient. An array of emails can be returned,
2451           *                           as handled by wp_mail().
2452           *     @type string $subject Email subject.
2453           *     @type string $body    Email message body.
2454           *     @type string $headers Any email headers. Default empty.
2455           * }
2456           * @param int   $failures The number of failures encountered while upgrading.
2457           * @param mixed $results  The results of all attempted updates.
2458           */
2459          $email = apply_filters( 'automatic_updates_debug_email', $email, $failures, $this->update_results );
2460  
2461          wp_mail( $email['to'], $email['subject'], $email['body'], $email['headers'] );
2462      }
2463  }


Generated: Tue Mar 25 01:41:18 2014 WordPress honlapkészítés: online1.hu