Make WordPress Core

Ticket #34676: 34676.2.class-seperation-and-docs.diff

File 34676.2.class-seperation-and-docs.diff, 136.2 KB (added by jipmoors, 7 years ago)

One class per file, docs improved

  • src/wp-admin/includes/ajax-actions.php

     
    30873087
    30883088        check_ajax_referer( 'updates' );
    30893089
    3090         include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
     3090        require_once( ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php' );
     3091        require_once( ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php' );
    30913092
    30923093        wp_update_plugins();
    30933094
  • src/wp-admin/includes/class-wp-upgrader-skins.php

     
    88 */
    99
    1010/**
    11  * Generic Skin for the WordPress Upgrader classes. This skin is designed to be extended for specific purposes.
     11 * Classes moved to seperate files
    1212 *
    13  * @package WordPress
    14  * @subpackage Upgrader
    15  * @since 2.8.0
     13 * @since 4.5.0
    1614 */
    17 class WP_Upgrader_Skin {
     15require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader-skin.php';
    1816
    19         public $upgrader;
    20         public $done_header = false;
    21         public $done_footer = false;
    22         public $result = false;
    23         public $options = array();
     17require_once ABSPATH . 'wp-admin/includes/class-plugin-installer-skin.php';
     18require_once ABSPATH . 'wp-admin/includes/class-theme-installer-skin.php';
    2419
    25         /**
    26          *
    27          * @param array $args
    28          */
    29         public function __construct($args = array()) {
    30                 $defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false );
    31                 $this->options = wp_parse_args($args, $defaults);
    32         }
     20require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader-skin.php';
     21require_once ABSPATH . 'wp-admin/includes/class-theme-upgrader-skin.php';
     22require_once ABSPATH . 'wp-admin/includes/class-language-pack-upgrader-skin.php';
     23require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php';
    3324
    34         /**
    35          * @param WP_Upgrader $upgrader
    36          */
    37         public function set_upgrader(&$upgrader) {
    38                 if ( is_object($upgrader) )
    39                         $this->upgrader =& $upgrader;
    40                 $this->add_strings();
    41         }
    42 
    43         /**
    44          * @access public
    45          */
    46         public function add_strings() {
    47         }
    48 
    49         /**
    50          *
    51          * @param string|false|WP_Error $result
    52          */
    53         public function set_result($result) {
    54                 $this->result = $result;
    55         }
    56 
    57         /**
    58          *
    59          * @param bool   $error
    60          * @param string $context
    61          * @param bool   $allow_relaxed_file_ownership
    62          * @return type
    63          */
    64         public function request_filesystem_credentials( $error = false, $context = false, $allow_relaxed_file_ownership = false ) {
    65                 $url = $this->options['url'];
    66                 if ( ! $context ) {
    67                         $context = $this->options['context'];
    68                 }
    69                 if ( !empty($this->options['nonce']) ) {
    70                         $url = wp_nonce_url($url, $this->options['nonce']);
    71                 }
    72 
    73                 $extra_fields = array();
    74 
    75                 return request_filesystem_credentials( $url, '', $error, $context, $extra_fields, $allow_relaxed_file_ownership );
    76         }
    77 
    78         /**
    79          * @access public
    80          */
    81         public function header() {
    82                 if ( $this->done_header ) {
    83                         return;
    84                 }
    85                 $this->done_header = true;
    86                 echo '<div class="wrap">';
    87                 echo '<h1>' . $this->options['title'] . '</h1>';
    88         }
    89 
    90         /**
    91          * @access public
    92          */
    93         public function footer() {
    94                 if ( $this->done_footer ) {
    95                         return;
    96                 }
    97                 $this->done_footer = true;
    98                 echo '</div>';
    99         }
    100 
    101         /**
    102          *
    103          * @param string|WP_Error $errors
    104          */
    105         public function error($errors) {
    106                 if ( ! $this->done_header )
    107                         $this->header();
    108                 if ( is_string($errors) ) {
    109                         $this->feedback($errors);
    110                 } elseif ( is_wp_error($errors) && $errors->get_error_code() ) {
    111                         foreach ( $errors->get_error_messages() as $message ) {
    112                                 if ( $errors->get_error_data() && is_string( $errors->get_error_data() ) )
    113                                         $this->feedback($message . ' ' . esc_html( strip_tags( $errors->get_error_data() ) ) );
    114                                 else
    115                                         $this->feedback($message);
    116                         }
    117                 }
    118         }
    119 
    120         /**
    121          *
    122          * @param string $string
    123          */
    124         public function feedback($string) {
    125                 if ( isset( $this->upgrader->strings[$string] ) )
    126                         $string = $this->upgrader->strings[$string];
    127 
    128                 if ( strpos($string, '%') !== false ) {
    129                         $args = func_get_args();
    130                         $args = array_splice($args, 1);
    131                         if ( $args ) {
    132                                 $args = array_map( 'strip_tags', $args );
    133                                 $args = array_map( 'esc_html', $args );
    134                                 $string = vsprintf($string, $args);
    135                         }
    136                 }
    137                 if ( empty($string) )
    138                         return;
    139                 show_message($string);
    140         }
    141 
    142         /**
    143          * @access public
    144          */
    145         public function before() {}
    146 
    147         /**
    148          * @access public
    149          */
    150         public function after() {}
    151 
    152         /**
    153          * Output JavaScript that calls function to decrement the update counts.
    154          *
    155          * @since 3.9.0
    156          *
    157          * @param string $type Type of update count to decrement. Likely values include 'plugin',
    158          *                     'theme', 'translation', etc.
    159          */
    160         protected function decrement_update_count( $type ) {
    161                 if ( ! $this->result || is_wp_error( $this->result ) || 'up_to_date' === $this->result ) {
    162                         return;
    163                 }
    164 
    165                 if ( defined( 'IFRAME_REQUEST' ) ) {
    166                         echo '<script type="text/javascript">
    167                                         if ( window.postMessage && JSON ) {
    168                                                 window.parent.postMessage( JSON.stringify( { action: "decrementUpdateCount", upgradeType: "' . $type . '" } ), window.location.protocol + "//" + window.location.hostname );
    169                                         }
    170                                 </script>';
    171                 } else {
    172                         echo '<script type="text/javascript">
    173                                         (function( wp ) {
    174                                                 if ( wp && wp.updates.decrementCount ) {
    175                                                         wp.updates.decrementCount( "' . $type . '" );
    176                                                 }
    177                                         })( window.wp );
    178                                 </script>';
    179                 }
    180         }
    181 
    182         /**
    183          * @access public
    184          */
    185         public function bulk_header() {}
    186 
    187         /**
    188          * @access public
    189          */
    190         public function bulk_footer() {}
    191 }
    192 
    193 /**
    194  * Plugin Upgrader Skin for WordPress Plugin Upgrades.
    195  *
    196  * @package WordPress
    197  * @subpackage Upgrader
    198  * @since 2.8.0
    199  */
    200 class Plugin_Upgrader_Skin extends WP_Upgrader_Skin {
    201         public $plugin = '';
    202         public $plugin_active = false;
    203         public $plugin_network_active = false;
    204 
    205         /**
    206          *
    207          * @param array $args
    208          */
    209         public function __construct( $args = array() ) {
    210                 $defaults = array( 'url' => '', 'plugin' => '', 'nonce' => '', 'title' => __('Update Plugin') );
    211                 $args = wp_parse_args($args, $defaults);
    212 
    213                 $this->plugin = $args['plugin'];
    214 
    215                 $this->plugin_active = is_plugin_active( $this->plugin );
    216                 $this->plugin_network_active = is_plugin_active_for_network( $this->plugin );
    217 
    218                 parent::__construct($args);
    219         }
    220 
    221         /**
    222          * @access public
    223          */
    224         public function after() {
    225                 $this->plugin = $this->upgrader->plugin_info();
    226                 if ( !empty($this->plugin) && !is_wp_error($this->result) && $this->plugin_active ){
    227                         // Currently used only when JS is off for a single plugin update?
    228                         echo '<iframe title="' . esc_attr__( 'Update progress' ) . '" style="border:0;overflow:hidden" width="100%" height="170" src="' . wp_nonce_url( 'update.php?action=activate-plugin&networkwide=' . $this->plugin_network_active . '&plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin ) . '"></iframe>';
    229                 }
    230 
    231                 $this->decrement_update_count( 'plugin' );
    232 
    233                 $update_actions =  array(
    234                         'activate_plugin' => '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin) . '" target="_parent">' . __( 'Activate Plugin' ) . '</a>',
    235                         'plugins_page' => '<a href="' . self_admin_url( 'plugins.php' ) . '" target="_parent">' . __( 'Return to Plugins page' ) . '</a>'
    236                 );
    237                 if ( $this->plugin_active || ! $this->result || is_wp_error( $this->result ) || ! current_user_can( 'activate_plugins' ) )
    238                         unset( $update_actions['activate_plugin'] );
    239 
    240                 /**
    241                  * Filter the list of action links available following a single plugin update.
    242                  *
    243                  * @since 2.7.0
    244                  *
    245                  * @param array  $update_actions Array of plugin action links.
    246                  * @param string $plugin         Path to the plugin file.
    247                  */
    248                 $update_actions = apply_filters( 'update_plugin_complete_actions', $update_actions, $this->plugin );
    249 
    250                 if ( ! empty($update_actions) )
    251                         $this->feedback(implode(' | ', (array)$update_actions));
    252         }
    253 }
    254 
    255 /**
    256  * Plugin Upgrader Skin for WordPress Plugin Upgrades.
    257  *
    258  * @package WordPress
    259  * @subpackage Upgrader
    260  * @since 3.0.0
    261  */
    262 class Bulk_Upgrader_Skin extends WP_Upgrader_Skin {
    263         public $in_loop = false;
    264         /**
    265          * @var string|false
    266          */
    267         public $error = false;
    268 
    269         /**
    270          *
    271          * @param array $args
    272          */
    273         public function __construct($args = array()) {
    274                 $defaults = array( 'url' => '', 'nonce' => '' );
    275                 $args = wp_parse_args($args, $defaults);
    276 
    277                 parent::__construct($args);
    278         }
    279 
    280         /**
    281          * @access public
    282          */
    283         public function add_strings() {
    284                 $this->upgrader->strings['skin_upgrade_start'] = __('The update process is starting. This process may take a while on some hosts, so please be patient.');
    285                 /* translators: 1: Title of an update, 2: Error message */
    286                 $this->upgrader->strings['skin_update_failed_error'] = __('An error occurred while updating %1$s: %2$s');
    287                 /* translators: 1: Title of an update */
    288                 $this->upgrader->strings['skin_update_failed'] = __('The update of %1$s failed.');
    289                 /* translators: 1: Title of an update */
    290                 $this->upgrader->strings['skin_update_successful'] = __( '%1$s updated successfully.' ) . ' <a onclick="%2$s" href="#" class="hide-if-no-js"><span>' . __( 'Show Details' ) . '</span><span class="hidden">' . __( 'Hide Details' ) . '</span></a>';
    291                 $this->upgrader->strings['skin_upgrade_end'] = __('All updates have been completed.');
    292         }
    293 
    294         /**
    295          * @param string $string
    296          */
    297         public function feedback($string) {
    298                 if ( isset( $this->upgrader->strings[$string] ) )
    299                         $string = $this->upgrader->strings[$string];
    300 
    301                 if ( strpos($string, '%') !== false ) {
    302                         $args = func_get_args();
    303                         $args = array_splice($args, 1);
    304                         if ( $args ) {
    305                                 $args = array_map( 'strip_tags', $args );
    306                                 $args = array_map( 'esc_html', $args );
    307                                 $string = vsprintf($string, $args);
    308                         }
    309                 }
    310                 if ( empty($string) )
    311                         return;
    312                 if ( $this->in_loop )
    313                         echo "$string<br />\n";
    314                 else
    315                         echo "<p>$string</p>\n";
    316         }
    317 
    318         /**
    319          * @access public
    320          */
    321         public function header() {
    322                 // Nothing, This will be displayed within a iframe.
    323         }
    324 
    325         /**
    326          * @access public
    327          */
    328         public function footer() {
    329                 // Nothing, This will be displayed within a iframe.
    330         }
    331 
    332         /**
    333          *
    334          * @param string|WP_Error $error
    335          */
    336         public function error($error) {
    337                 if ( is_string($error) && isset( $this->upgrader->strings[$error] ) )
    338                         $this->error = $this->upgrader->strings[$error];
    339 
    340                 if ( is_wp_error($error) ) {
    341                         $messages = array();
    342                         foreach ( $error->get_error_messages() as $emessage ) {
    343                                 if ( $error->get_error_data() && is_string( $error->get_error_data() ) )
    344                                         $messages[] = $emessage . ' ' . esc_html( strip_tags( $error->get_error_data() ) );
    345                                 else
    346                                         $messages[] = $emessage;
    347                         }
    348                         $this->error = implode(', ', $messages);
    349                 }
    350                 echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').hide();</script>';
    351         }
    352 
    353         /**
    354          * @access public
    355          */
    356         public function bulk_header() {
    357                 $this->feedback('skin_upgrade_start');
    358         }
    359 
    360         /**
    361          * @access public
    362          */
    363         public function bulk_footer() {
    364                 $this->feedback('skin_upgrade_end');
    365         }
    366 
    367         /**
    368          *
    369          * @param string $title
    370          */
    371         public function before($title = '') {
    372                 $this->in_loop = true;
    373                 printf( '<h2>' . $this->upgrader->strings['skin_before_update_header'] . ' <span class="spinner waiting-' . $this->upgrader->update_current . '"></span></h2>', $title, $this->upgrader->update_current, $this->upgrader->update_count );
    374                 echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').css("display", "inline-block");</script>';
    375                 echo '<div class="update-messages hide-if-js" id="progress-' . esc_attr($this->upgrader->update_current) . '"><p>';
    376                 $this->flush_output();
    377         }
    378 
    379         /**
    380          *
    381          * @param string $title
    382          */
    383         public function after($title = '') {
    384                 echo '</p></div>';
    385                 if ( $this->error || ! $this->result ) {
    386                         if ( $this->error ) {
    387                                 echo '<div class="error"><p>' . sprintf($this->upgrader->strings['skin_update_failed_error'], $title, '<strong>' . $this->error . '</strong>' ) . '</p></div>';
    388                         } else {
    389                                 echo '<div class="error"><p>' . sprintf($this->upgrader->strings['skin_update_failed'], $title) . '</p></div>';
    390                         }
    391 
    392                         echo '<script type="text/javascript">jQuery(\'#progress-' . esc_js($this->upgrader->update_current) . '\').show();</script>';
    393                 }
    394                 if ( $this->result && ! is_wp_error( $this->result ) ) {
    395                         if ( ! $this->error )
    396                                 echo '<div class="updated"><p>' . sprintf($this->upgrader->strings['skin_update_successful'], $title, 'jQuery(\'#progress-' . esc_js($this->upgrader->update_current) . '\').toggle();jQuery(\'span\', this).toggle(); return false;') . '</p></div>';
    397                         echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').hide();</script>';
    398                 }
    399 
    400                 $this->reset();
    401                 $this->flush_output();
    402         }
    403 
    404         /**
    405          * @access public
    406          */
    407         public function reset() {
    408                 $this->in_loop = false;
    409                 $this->error = false;
    410         }
    411 
    412         /**
    413          * @access public
    414          */
    415         public function flush_output() {
    416                 wp_ob_end_flush_all();
    417                 flush();
    418         }
    419 }
    420 
    421 class Bulk_Plugin_Upgrader_Skin extends Bulk_Upgrader_Skin {
    422         public $plugin_info = array(); // Plugin_Upgrader::bulk() will fill this in.
    423 
    424         public function add_strings() {
    425                 parent::add_strings();
    426                 $this->upgrader->strings['skin_before_update_header'] = __('Updating Plugin %1$s (%2$d/%3$d)');
    427         }
    428 
    429         /**
    430          *
    431          * @param string $title
    432          */
    433         public function before($title = '') {
    434                 parent::before($this->plugin_info['Title']);
    435         }
    436 
    437         /**
    438          *
    439          * @param string $title
    440          */
    441         public function after($title = '') {
    442                 parent::after($this->plugin_info['Title']);
    443                 $this->decrement_update_count( 'plugin' );
    444         }
    445 
    446         /**
    447          * @access public
    448          */
    449         public function bulk_footer() {
    450                 parent::bulk_footer();
    451                 $update_actions =  array(
    452                         'plugins_page' => '<a href="' . self_admin_url( 'plugins.php' ) . '" target="_parent">' . __( 'Return to Plugins page' ) . '</a>',
    453                         'updates_page' => '<a href="' . self_admin_url( 'update-core.php' ) . '" target="_parent">' . __( 'Return to WordPress Updates page' ) . '</a>'
    454                 );
    455                 if ( ! current_user_can( 'activate_plugins' ) )
    456                         unset( $update_actions['plugins_page'] );
    457 
    458                 /**
    459                  * Filter the list of action links available following bulk plugin updates.
    460                  *
    461                  * @since 3.0.0
    462                  *
    463                  * @param array $update_actions Array of plugin action links.
    464                  * @param array $plugin_info    Array of information for the last-updated plugin.
    465                  */
    466                 $update_actions = apply_filters( 'update_bulk_plugins_complete_actions', $update_actions, $this->plugin_info );
    467 
    468                 if ( ! empty($update_actions) )
    469                         $this->feedback(implode(' | ', (array)$update_actions));
    470         }
    471 }
    472 
    473 class Bulk_Theme_Upgrader_Skin extends Bulk_Upgrader_Skin {
    474         public $theme_info = array(); // Theme_Upgrader::bulk() will fill this in.
    475 
    476         public function add_strings() {
    477                 parent::add_strings();
    478                 $this->upgrader->strings['skin_before_update_header'] = __('Updating Theme %1$s (%2$d/%3$d)');
    479         }
    480 
    481         /**
    482          *
    483          * @param string $title
    484          */
    485         public function before($title = '') {
    486                 parent::before( $this->theme_info->display('Name') );
    487         }
    488 
    489         /**
    490          *
    491          * @param string $title
    492          */
    493         public function after($title = '') {
    494                 parent::after( $this->theme_info->display('Name') );
    495                 $this->decrement_update_count( 'theme' );
    496         }
    497 
    498         /**
    499          * @access public
    500          */
    501         public function bulk_footer() {
    502                 parent::bulk_footer();
    503                 $update_actions =  array(
    504                         'themes_page' => '<a href="' . self_admin_url( 'themes.php' ) . '" target="_parent">' . __( 'Return to Themes page' ) . '</a>',
    505                         'updates_page' => '<a href="' . self_admin_url( 'update-core.php' ) . '" target="_parent">' . __( 'Return to WordPress Updates page' ) . '</a>'
    506                 );
    507                 if ( ! current_user_can( 'switch_themes' ) && ! current_user_can( 'edit_theme_options' ) )
    508                         unset( $update_actions['themes_page'] );
    509 
    510                 /**
    511                  * Filter the list of action links available following bulk theme updates.
    512                  *
    513                  * @since 3.0.0
    514                  *
    515                  * @param array $update_actions Array of theme action links.
    516                  * @param array $theme_info     Array of information for the last-updated theme.
    517                  */
    518                 $update_actions = apply_filters( 'update_bulk_theme_complete_actions', $update_actions, $this->theme_info );
    519 
    520                 if ( ! empty($update_actions) )
    521                         $this->feedback(implode(' | ', (array)$update_actions));
    522         }
    523 }
    524 
    525 /**
    526  * Plugin Installer Skin for WordPress Plugin Installer.
    527  *
    528  * @package WordPress
    529  * @subpackage Upgrader
    530  * @since 2.8.0
    531  */
    532 class Plugin_Installer_Skin extends WP_Upgrader_Skin {
    533         public $api;
    534         public $type;
    535 
    536         /**
    537          *
    538          * @param array $args
    539          */
    540         public function __construct($args = array()) {
    541                 $defaults = array( 'type' => 'web', 'url' => '', 'plugin' => '', 'nonce' => '', 'title' => '' );
    542                 $args = wp_parse_args($args, $defaults);
    543 
    544                 $this->type = $args['type'];
    545                 $this->api = isset($args['api']) ? $args['api'] : array();
    546 
    547                 parent::__construct($args);
    548         }
    549 
    550         /**
    551          * @access public
    552          */
    553         public function before() {
    554                 if ( !empty($this->api) )
    555                         $this->upgrader->strings['process_success'] = sprintf( __('Successfully installed the plugin <strong>%s %s</strong>.'), $this->api->name, $this->api->version);
    556         }
    557 
    558         /**
    559          * @access public
    560          */
    561         public function after() {
    562                 $plugin_file = $this->upgrader->plugin_info();
    563 
    564                 $install_actions = array();
    565 
    566                 $from = isset($_GET['from']) ? wp_unslash( $_GET['from'] ) : 'plugins';
    567 
    568                 if ( 'import' == $from )
    569                         $install_actions['activate_plugin'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;from=import&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Activate Plugin &amp; Run Importer' ) . '</a>';
    570                 else
    571                         $install_actions['activate_plugin'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Activate Plugin' ) . '</a>';
    572 
    573                 if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) {
    574                         $install_actions['network_activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;networkwide=1&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Network Activate' ) . '</a>';
    575                         unset( $install_actions['activate_plugin'] );
    576                 }
    577 
    578                 if ( 'import' == $from ) {
    579                         $install_actions['importers_page'] = '<a href="' . admin_url( 'import.php' ) . '" target="_parent">' . __( 'Return to Importers' ) . '</a>';
    580                 } elseif ( $this->type == 'web' ) {
    581                         $install_actions['plugins_page'] = '<a href="' . self_admin_url( 'plugin-install.php' ) . '" target="_parent">' . __( 'Return to Plugin Installer' ) . '</a>';
    582                 } else {
    583                         $install_actions['plugins_page'] = '<a href="' . self_admin_url( 'plugins.php' ) . '" target="_parent">' . __( 'Return to Plugins page' ) . '</a>';
    584                 }
    585 
    586                 if ( ! $this->result || is_wp_error($this->result) ) {
    587                         unset( $install_actions['activate_plugin'], $install_actions['network_activate'] );
    588                 } elseif ( ! current_user_can( 'activate_plugins' ) ) {
    589                         unset( $install_actions['activate_plugin'] );
    590                 }
    591 
    592                 /**
    593                  * Filter the list of action links available following a single plugin installation.
    594                  *
    595                  * @since 2.7.0
    596                  *
    597                  * @param array  $install_actions Array of plugin action links.
    598                  * @param object $api             Object containing WordPress.org API plugin data. Empty
    599                  *                                for non-API installs, such as when a plugin is installed
    600                  *                                via upload.
    601                  * @param string $plugin_file     Path to the plugin file.
    602                  */
    603                 $install_actions = apply_filters( 'install_plugin_complete_actions', $install_actions, $this->api, $plugin_file );
    604 
    605                 if ( ! empty($install_actions) )
    606                         $this->feedback(implode(' | ', (array)$install_actions));
    607         }
    608 }
    609 
    610 /**
    611  * Theme Installer Skin for the WordPress Theme Installer.
    612  *
    613  * @package WordPress
    614  * @subpackage Upgrader
    615  * @since 2.8.0
    616  */
    617 class Theme_Installer_Skin extends WP_Upgrader_Skin {
    618         public $api;
    619         public $type;
    620 
    621         /**
    622          *
    623          * @param array $args
    624          */
    625         public function __construct($args = array()) {
    626                 $defaults = array( 'type' => 'web', 'url' => '', 'theme' => '', 'nonce' => '', 'title' => '' );
    627                 $args = wp_parse_args($args, $defaults);
    628 
    629                 $this->type = $args['type'];
    630                 $this->api = isset($args['api']) ? $args['api'] : array();
    631 
    632                 parent::__construct($args);
    633         }
    634 
    635         /**
    636          * @access public
    637          */
    638         public function before() {
    639                 if ( !empty($this->api) )
    640                         $this->upgrader->strings['process_success'] = sprintf( $this->upgrader->strings['process_success_specific'], $this->api->name, $this->api->version);
    641         }
    642 
    643         /**
    644          * @access public
    645          */
    646         public function after() {
    647                 if ( empty($this->upgrader->result['destination_name']) )
    648                         return;
    649 
    650                 $theme_info = $this->upgrader->theme_info();
    651                 if ( empty( $theme_info ) )
    652                         return;
    653 
    654                 $name       = $theme_info->display('Name');
    655                 $stylesheet = $this->upgrader->result['destination_name'];
    656                 $template   = $theme_info->get_template();
    657 
    658                 $activate_link = add_query_arg( array(
    659                         'action'     => 'activate',
    660                         'template'   => urlencode( $template ),
    661                         'stylesheet' => urlencode( $stylesheet ),
    662                 ), admin_url('themes.php') );
    663                 $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet );
    664 
    665                 $install_actions = array();
    666 
    667                 if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
    668                         $install_actions['preview'] = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Live Preview' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Live Preview &#8220;%s&#8221;' ), $name ) . '</span></a>';
    669                 }
    670                 $install_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink"><span aria-hidden="true">' . __( 'Activate' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Activate &#8220;%s&#8221;' ), $name ) . '</span></a>';
    671 
    672                 if ( is_network_admin() && current_user_can( 'manage_network_themes' ) )
    673                         $install_actions['network_enable'] = '<a href="' . esc_url( wp_nonce_url( 'themes.php?action=enable&amp;theme=' . urlencode( $stylesheet ), 'enable-theme_' . $stylesheet ) ) . '" target="_parent">' . __( 'Network Enable' ) . '</a>';
    674 
    675                 if ( $this->type == 'web' )
    676                         $install_actions['themes_page'] = '<a href="' . self_admin_url( 'theme-install.php' ) . '" target="_parent">' . __( 'Return to Theme Installer' ) . '</a>';
    677                 elseif ( current_user_can( 'switch_themes' ) || current_user_can( 'edit_theme_options' ) )
    678                         $install_actions['themes_page'] = '<a href="' . self_admin_url( 'themes.php' ) . '" target="_parent">' . __( 'Return to Themes page' ) . '</a>';
    679 
    680                 if ( ! $this->result || is_wp_error($this->result) || is_network_admin() || ! current_user_can( 'switch_themes' ) )
    681                         unset( $install_actions['activate'], $install_actions['preview'] );
    682 
    683                 /**
    684                  * Filter the list of action links available following a single theme installation.
    685                  *
    686                  * @since 2.8.0
    687                  *
    688                  * @param array    $install_actions Array of theme action links.
    689                  * @param object   $api             Object containing WordPress.org API theme data.
    690                  * @param string   $stylesheet      Theme directory name.
    691                  * @param WP_Theme $theme_info      Theme object.
    692                  */
    693                 $install_actions = apply_filters( 'install_theme_complete_actions', $install_actions, $this->api, $stylesheet, $theme_info );
    694                 if ( ! empty($install_actions) )
    695                         $this->feedback(implode(' | ', (array)$install_actions));
    696         }
    697 }
    698 
    699 /**
    700  * Theme Upgrader Skin for WordPress Theme Upgrades.
    701  *
    702  * @package WordPress
    703  * @subpackage Upgrader
    704  * @since 2.8.0
    705  */
    706 class Theme_Upgrader_Skin extends WP_Upgrader_Skin {
    707         public $theme = '';
    708 
    709         /**
    710          *
    711          * @param array $args
    712          */
    713         public function __construct($args = array()) {
    714                 $defaults = array( 'url' => '', 'theme' => '', 'nonce' => '', 'title' => __('Update Theme') );
    715                 $args = wp_parse_args($args, $defaults);
    716 
    717                 $this->theme = $args['theme'];
    718 
    719                 parent::__construct($args);
    720         }
    721 
    722         /**
    723          * @access public
    724          */
    725         public function after() {
    726                 $this->decrement_update_count( 'theme' );
    727 
    728                 $update_actions = array();
    729                 if ( ! empty( $this->upgrader->result['destination_name'] ) && $theme_info = $this->upgrader->theme_info() ) {
    730                         $name       = $theme_info->display('Name');
    731                         $stylesheet = $this->upgrader->result['destination_name'];
    732                         $template   = $theme_info->get_template();
    733 
    734                         $activate_link = add_query_arg( array(
    735                                 'action'     => 'activate',
    736                                 'template'   => urlencode( $template ),
    737                                 'stylesheet' => urlencode( $stylesheet ),
    738                         ), admin_url('themes.php') );
    739                         $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet );
    740 
    741                         if ( get_stylesheet() == $stylesheet ) {
    742                                 if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
    743                                         $update_actions['preview']  = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Customize' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Customize &#8220;%s&#8221;' ), $name ) . '</span></a>';
    744                                 }
    745                         } elseif ( current_user_can( 'switch_themes' ) ) {
    746                                 if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
    747                                         $update_actions['preview'] = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Live Preview' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Live Preview &#8220;%s&#8221;' ), $name ) . '</span></a>';
    748                                 }
    749                                 $update_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink"><span aria-hidden="true">' . __( 'Activate' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Activate &#8220;%s&#8221;' ), $name ) . '</span></a>';
    750                         }
    751 
    752                         if ( ! $this->result || is_wp_error( $this->result ) || is_network_admin() )
    753                                 unset( $update_actions['preview'], $update_actions['activate'] );
    754                 }
    755 
    756                 $update_actions['themes_page'] = '<a href="' . self_admin_url( 'themes.php' ) . '" target="_parent">' . __( 'Return to Themes page' ) . '</a>';
    757 
    758                 /**
    759                  * Filter the list of action links available following a single theme update.
    760                  *
    761                  * @since 2.8.0
    762                  *
    763                  * @param array  $update_actions Array of theme action links.
    764                  * @param string $theme          Theme directory name.
    765                  */
    766                 $update_actions = apply_filters( 'update_theme_complete_actions', $update_actions, $this->theme );
    767 
    768                 if ( ! empty($update_actions) )
    769                         $this->feedback(implode(' | ', (array)$update_actions));
    770         }
    771 }
    772 
    773 /**
    774  * Translation Upgrader Skin for WordPress Translation Upgrades.
    775  *
    776  * @package WordPress
    777  * @subpackage Upgrader
    778  * @since 3.7.0
    779  */
    780 class Language_Pack_Upgrader_Skin extends WP_Upgrader_Skin {
    781         public $language_update = null;
    782         public $done_header = false;
    783         public $done_footer = false;
    784         public $display_footer_actions = true;
    785 
    786         /**
    787          *
    788          * @param array $args
    789          */
    790         public function __construct( $args = array() ) {
    791                 $defaults = array( 'url' => '', 'nonce' => '', 'title' => __( 'Update Translations' ), 'skip_header_footer' => false );
    792                 $args = wp_parse_args( $args, $defaults );
    793                 if ( $args['skip_header_footer'] ) {
    794                         $this->done_header = true;
    795                         $this->done_footer = true;
    796                         $this->display_footer_actions = false;
    797                 }
    798                 parent::__construct( $args );
    799         }
    800 
    801         /**
    802          * @access public
    803          */
    804         public function before() {
    805                 $name = $this->upgrader->get_name_for_update( $this->language_update );
    806 
    807                 echo '<div class="update-messages lp-show-latest">';
    808 
    809                 printf( '<h2>' . __( 'Updating translations for %1$s (%2$s)&#8230;' ) . '</h2>', $name, $this->language_update->language );
    810         }
    811 
    812         /**
    813          *
    814          * @param string|WP_Error $error
    815          */
    816         public function error( $error ) {
    817                 echo '<div class="lp-error">';
    818                 parent::error( $error );
    819                 echo '</div>';
    820         }
    821 
    822         /**
    823          * @access public
    824          */
    825         public function after() {
    826                 echo '</div>';
    827         }
    828 
    829         /**
    830          * @access public
    831          */
    832         public function bulk_footer() {
    833                 $this->decrement_update_count( 'translation' );
    834                 $update_actions = array();
    835                 $update_actions['updates_page'] = '<a href="' . self_admin_url( 'update-core.php' ) . '" target="_parent">' . __( 'Return to WordPress Updates page' ) . '</a>';
    836 
    837                 /**
    838                  * Filter the list of action links available following a translations update.
    839                  *
    840                  * @since 3.7.0
    841                  *
    842                  * @param array $update_actions Array of translations update links.
    843                  */
    844                 $update_actions = apply_filters( 'update_translations_complete_actions', $update_actions );
    845 
    846                 if ( $update_actions && $this->display_footer_actions )
    847                         $this->feedback( implode( ' | ', $update_actions ) );
    848         }
    849 }
    850 
    851 /**
    852  * Upgrader Skin for Automatic WordPress Upgrades
    853  *
    854  * This skin is designed to be used when no output is intended, all output
    855  * is captured and stored for the caller to process and log/email/discard.
    856  *
    857  * @package WordPress
    858  * @subpackage Upgrader
    859  * @since 3.7.0
    860  */
    861 class Automatic_Upgrader_Skin extends WP_Upgrader_Skin {
    862         protected $messages = array();
    863 
    864         /**
    865          *
    866          * @param bool   $error
    867          * @param string $context
    868          * @param bool   $allow_relaxed_file_ownership
    869          * @return bool
    870          */
    871         public function request_filesystem_credentials( $error = false, $context = '', $allow_relaxed_file_ownership = false ) {
    872                 if ( $context ) {
    873                         $this->options['context'] = $context;
    874                 }
    875                 // TODO: fix up request_filesystem_credentials(), or split it, to allow us to request a no-output version
    876                 // This will output a credentials form in event of failure, We don't want that, so just hide with a buffer
    877                 ob_start();
    878                 $result = parent::request_filesystem_credentials( $error, $context, $allow_relaxed_file_ownership );
    879                 ob_end_clean();
    880                 return $result;
    881         }
    882 
    883         /**
    884          * @access public
    885          *
    886          * @return array
    887          */
    888         public function get_upgrade_messages() {
    889                 return $this->messages;
    890         }
    891 
    892         /**
    893          * @param string|array|WP_Error $data
    894          */
    895         public function feedback( $data ) {
    896                 if ( is_wp_error( $data ) ) {
    897                         $string = $data->get_error_message();
    898                 } elseif ( is_array( $data ) ) {
    899                         return;
    900                 } else {
    901                         $string = $data;
    902                 }
    903                 if ( ! empty( $this->upgrader->strings[ $string ] ) )
    904                         $string = $this->upgrader->strings[ $string ];
    905 
    906                 if ( strpos( $string, '%' ) !== false ) {
    907                         $args = func_get_args();
    908                         $args = array_splice( $args, 1 );
    909                         if ( ! empty( $args ) )
    910                                 $string = vsprintf( $string, $args );
    911                 }
    912 
    913                 $string = trim( $string );
    914 
    915                 // Only allow basic HTML in the messages, as it'll be used in emails/logs rather than direct browser output.
    916                 $string = wp_kses( $string, array(
    917                         'a' => array(
    918                                 'href' => true
    919                         ),
    920                         'br' => true,
    921                         'em' => true,
    922                         'strong' => true,
    923                 ) );
    924 
    925                 if ( empty( $string ) )
    926                         return;
    927 
    928                 $this->messages[] = $string;
    929         }
    930 
    931         /**
    932          * @access public
    933          */
    934         public function header() {
    935                 ob_start();
    936         }
    937 
    938         /**
    939          * @access public
    940          */
    941         public function footer() {
    942                 $output = ob_get_clean();
    943                 if ( ! empty( $output ) )
    944                         $this->feedback( $output );
    945         }
    946 }
     25require_once ABSPATH . 'wp-admin/includes/class-bulk-upgrader-skin.php';
     26require_once ABSPATH . 'wp-admin/includes/class-bulk-plugin-upgrader-skin.php';
     27require_once ABSPATH . 'wp-admin/includes/class-bulk-theme-upgrader-skin.php';
     28 No newline at end of file
  • src/wp-admin/includes/class-wp-upgrader.php

     
    1111 * @since 2.8.0
    1212 */
    1313
    14 require ABSPATH . 'wp-admin/includes/class-wp-upgrader-skins.php';
     14require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader-skins.php';
    1515
    1616/**
     17 * Classes moved to seperate files
     18 *
     19 * All these need to stay here because of the 'themes_api' functionality
     20 *
     21 * Included in 'wp-admin/update.php'
     22 * include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' ); //for themes_api..
     23 *
     24 * @since 4.5.0
     25 */
     26require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
     27require_once ABSPATH . 'wp-admin/includes/class-theme-upgrader.php';
     28require_once ABSPATH . 'wp-admin/includes/class-language-pack-upgrader.php';
     29require_once ABSPATH . 'wp-admin/includes/class-core-upgrader.php';
     30require_once ABSPATH . 'wp-admin/includes/class-file-upload-upgrader.php';
     31require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php';
     32
     33
     34/**
    1735 * Core class used for upgrading/installing a local set of files via
    1836 * the Filesystem Abstraction classes from a Zip file.
    1937 *
     
    254272        }
    255273
    256274        /**
     275         * Clears optional remnants of previous upgrades
     276         *
     277         * @since 4.5.0
     278         * @access public
     279         *
     280         * @global WP_Filesystem_Base $wp_filesystem Subclass
     281         */
     282        public function clean_upgrade_folder() {
     283                global $wp_filesystem;
     284
     285                //Clean up contents of upgrade directory.
     286                $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
     287                $upgrade_files  = $wp_filesystem->dirlist( $upgrade_folder );
     288                if ( ! empty( $upgrade_files ) ) {
     289                        foreach ( $upgrade_files as $file ) {
     290                                $wp_filesystem->delete( $upgrade_folder . $file['name'], true );
     291                        }
     292                }
     293        }
     294
     295        /**
    257296         * Unpack a compressed package file.
    258297         *
    259298         * @since 2.8.0
     
    274313                $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
    275314
    276315                //Clean up contents of upgrade directory beforehand.
     316                /*
    277317                $upgrade_files = $wp_filesystem->dirlist($upgrade_folder);
    278318                if ( !empty($upgrade_files) ) {
    279319                        foreach ( $upgrade_files as $file )
    280320                                $wp_filesystem->delete($upgrade_folder . $file['name'], true);
    281321                }
     322                */
    282323
    283324                // We need a working directory - Strip off any .tmp or .zip suffixes
    284325                $working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
     
    641682                 */
    642683                $options = apply_filters( 'upgrader_package_options', $options );
    643684
    644                 if ( ! $options['is_multi'] ) { // call $this->header separately if running multiple times
    645                         $this->skin->header();
    646                 }
     685                $this->skin->header();
    647686
    648687                // Connect to the Filesystem first.
    649688                $res = $this->fs_connect( array( WP_CONTENT_DIR, $options['destination'] ) );
     
    666705                        return $res;
    667706                }
    668707
     708                $this->clean_upgrade_folder();
     709
    669710                /*
    670711                 * Download the package (Note, This just returns the filename
    671712                 * of the file if the package is a local file)
     
    751792                }
    752793        }
    753794
    754 }
    755 
    756 /**
    757  * Core class used for upgrading/installing plugins.
    758  *
    759  * It is designed to upgrade/install plugins from a local zip, remote zip URL,
    760  * or uploaded zip file.
    761  *
    762  * @since 2.8.0
    763  *
    764  * @see WP_Upgrader
    765  */
    766 class Plugin_Upgrader extends WP_Upgrader {
    767 
    768795        /**
    769          * Plugin upgrade result.
     796         * Get the used skin
    770797         *
    771          * @since 2.8.0
     798         * @since 4.5.0
    772799         * @access public
    773          * @var array|WP_Error $result
    774800         *
    775          * @see WP_Upgrader::$result
     801         * @return null|WP_Upgrader_Skin
    776802         */
    777         public $result;
    778 
    779         /**
    780          * Whether a bulk upgrade/install is being performed.
    781          *
    782          * @since 2.9.0
    783          * @access public
    784          * @var bool $bulk
    785          */
    786         public $bulk = false;
    787 
    788         /**
    789          * Initialize the upgrade strings.
    790          *
    791          * @since 2.8.0
    792          * @access public
    793          */
    794         public function upgrade_strings() {
    795                 $this->strings['up_to_date'] = __('The plugin is at the latest version.');
    796                 $this->strings['no_package'] = __('Update package not available.');
    797                 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
    798                 $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
    799                 $this->strings['remove_old'] = __('Removing the old version of the plugin&#8230;');
    800                 $this->strings['remove_old_failed'] = __('Could not remove the old plugin.');
    801                 $this->strings['process_failed'] = __('Plugin update failed.');
    802                 $this->strings['process_success'] = __('Plugin updated successfully.');
    803                 $this->strings['process_bulk_success'] = __('Plugins updated successfully.');
     803        public function get_skin() {
     804                return $this->skin;
    804805        }
    805806
    806         /**
    807          * Initialize the install strings.
    808          *
    809          * @since 2.8.0
    810          * @access public
    811          */
    812         public function install_strings() {
    813                 $this->strings['no_package'] = __('Install package not available.');
    814                 $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>&#8230;');
    815                 $this->strings['unpack_package'] = __('Unpacking the package&#8230;');
    816                 $this->strings['installing_package'] = __('Installing the plugin&#8230;');
    817                 $this->strings['no_files'] = __('The plugin contains no files.');
    818                 $this->strings['process_failed'] = __('Plugin install failed.');
    819                 $this->strings['process_success'] = __('Plugin installed successfully.');
    820         }
    821 
    822         /**
    823          * Install a plugin package.
    824          *
    825          * @since 2.8.0
    826          * @since 3.7.0 The `$args` parameter was added, making clearing the plugin update cache optional.
    827          * @access public
    828          *
    829          * @param string $package The full local path or URI of the package.
    830          * @param array  $args {
    831          *     Optional. Other arguments for installing a plugin package. Default empty array.
    832          *
    833          *     @type bool $clear_update_cache Whether to clear the plugin updates cache if successful.
    834          *                                    Default true.
    835          * }
    836          * @return bool|WP_Error True if the install was successful, false or a WP_Error otherwise.
    837          */
    838         public function install( $package, $args = array() ) {
    839 
    840                 $defaults = array(
    841                         'clear_update_cache' => true,
    842                 );
    843                 $parsed_args = wp_parse_args( $args, $defaults );
    844 
    845                 $this->init();
    846                 $this->install_strings();
    847 
    848                 add_filter('upgrader_source_selection', array($this, 'check_package') );
    849                 // Clear cache so wp_update_plugins() knows about the new plugin.
    850                 add_action( 'upgrader_process_complete', 'wp_clean_plugins_cache', 9, 0 );
    851 
    852                 $this->run( array(
    853                         'package' => $package,
    854                         'destination' => WP_PLUGIN_DIR,
    855                         'clear_destination' => false, // Do not overwrite files.
    856                         'clear_working' => true,
    857                         'hook_extra' => array(
    858                                 'type' => 'plugin',
    859                                 'action' => 'install',
    860                         )
    861                 ) );
    862 
    863                 remove_action( 'upgrader_process_complete', 'wp_clean_plugins_cache', 9 );
    864                 remove_filter('upgrader_source_selection', array($this, 'check_package') );
    865 
    866                 if ( ! $this->result || is_wp_error($this->result) )
    867                         return $this->result;
    868 
    869                 // Force refresh of plugin update information
    870                 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
    871 
    872                 return true;
    873         }
    874 
    875         /**
    876          * Upgrade a plugin.
    877          *
    878          * @since 2.8.0
    879          * @since 3.7.0 The `$args` parameter was added, making clearing the plugin update cache optional.
    880          * @access public
    881          *
    882          * @param string $plugin The basename path to the main plugin file.
    883          * @param array  $args {
    884          *     Optional. Other arguments for upgrading a plugin package. Default empty array.
    885          *
    886          *     @type bool $clear_update_cache Whether to clear the plugin updates cache if successful.
    887          *                                    Default true.
    888          * }
    889          * @return bool|WP_Error True if the upgrade was successful, false or a {@see WP_Error} object otherwise.
    890          */
    891         public function upgrade( $plugin, $args = array() ) {
    892 
    893                 $defaults = array(
    894                         'clear_update_cache' => true,
    895                 );
    896                 $parsed_args = wp_parse_args( $args, $defaults );
    897 
    898                 $this->init();
    899                 $this->upgrade_strings();
    900 
    901                 $current = get_site_transient( 'update_plugins' );
    902                 if ( !isset( $current->response[ $plugin ] ) ) {
    903                         $this->skin->before();
    904                         $this->skin->set_result(false);
    905                         $this->skin->error('up_to_date');
    906                         $this->skin->after();
    907                         return false;
    908                 }
    909 
    910                 // Get the URL to the zip file
    911                 $r = $current->response[ $plugin ];
    912 
    913                 add_filter('upgrader_pre_install', array($this, 'deactivate_plugin_before_upgrade'), 10, 2);
    914                 add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 10, 4);
    915                 //'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.
    916 
    917                 $this->run( array(
    918                         'package' => $r->package,
    919                         'destination' => WP_PLUGIN_DIR,
    920                         'clear_destination' => true,
    921                         'clear_working' => true,
    922                         'hook_extra' => array(
    923                                 'plugin' => $plugin,
    924                                 'type' => 'plugin',
    925                                 'action' => 'update',
    926                         ),
    927                 ) );
    928 
    929                 // Cleanup our hooks, in case something else does a upgrade on this connection.
    930                 remove_filter('upgrader_pre_install', array($this, 'deactivate_plugin_before_upgrade'));
    931                 remove_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'));
    932 
    933                 if ( ! $this->result || is_wp_error($this->result) )
    934                         return $this->result;
    935 
    936                 // Force refresh of plugin update information
    937                 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
    938 
    939                 return true;
    940         }
    941 
    942         /**
    943          * Bulk upgrade several plugins at once.
    944          *
    945          * @since 2.8.0
    946          * @since 3.7.0 The `$args` parameter was added, making clearing the plugin update cache optional.
    947          * @access public
    948          *
    949          * @param array $plugins Array of the basename paths of the plugins' main files.
    950          * @param array $args {
    951          *     Optional. Other arguments for upgrading several plugins at once. Default empty array.
    952          *
    953          *     @type bool $clear_update_cache Whether to clear the plugin updates cache if successful.
    954          *                                    Default true.
    955          * }
    956          * @return array|false An array of results indexed by plugin file, or false if unable to connect to the filesystem.
    957          */
    958         public function bulk_upgrade( $plugins, $args = array() ) {
    959 
    960                 $defaults = array(
    961                         'clear_update_cache' => true,
    962                 );
    963                 $parsed_args = wp_parse_args( $args, $defaults );
    964 
    965                 $this->init();
    966                 $this->bulk = true;
    967                 $this->upgrade_strings();
    968 
    969                 $current = get_site_transient( 'update_plugins' );
    970 
    971                 add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 10, 4);
    972 
    973                 $this->skin->header();
    974 
    975                 // Connect to the Filesystem first.
    976                 $res = $this->fs_connect( array(WP_CONTENT_DIR, WP_PLUGIN_DIR) );
    977                 if ( ! $res ) {
    978                         $this->skin->footer();
    979                         return false;
    980                 }
    981 
    982                 $this->skin->bulk_header();
    983 
    984                 /*
    985                  * Only start maintenance mode if:
    986                  * - running Multisite and there are one or more plugins specified, OR
    987                  * - a plugin with an update available is currently active.
    988                  * @TODO: For multisite, maintenance mode should only kick in for individual sites if at all possible.
    989                  */
    990                 $maintenance = ( is_multisite() && ! empty( $plugins ) );
    991                 foreach ( $plugins as $plugin )
    992                         $maintenance = $maintenance || ( is_plugin_active( $plugin ) && isset( $current->response[ $plugin] ) );
    993                 if ( $maintenance )
    994                         $this->maintenance_mode(true);
    995 
    996                 $results = array();
    997 
    998                 $this->update_count = count($plugins);
    999                 $this->update_current = 0;
    1000                 foreach ( $plugins as $plugin ) {
    1001                         $this->update_current++;
    1002                         $this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true);
    1003 
    1004                         if ( !isset( $current->response[ $plugin ] ) ) {
    1005                                 $this->skin->set_result('up_to_date');
    1006                                 $this->skin->before();
    1007                                 $this->skin->feedback('up_to_date');
    1008                                 $this->skin->after();
    1009                                 $results[$plugin] = true;
    1010                                 continue;
    1011                         }
    1012 
    1013                         // Get the URL to the zip file.
    1014                         $r = $current->response[ $plugin ];
    1015 
    1016                         $this->skin->plugin_active = is_plugin_active($plugin);
    1017 
    1018                         $result = $this->run( array(
    1019                                 'package' => $r->package,
    1020                                 'destination' => WP_PLUGIN_DIR,
    1021                                 'clear_destination' => true,
    1022                                 'clear_working' => true,
    1023                                 'is_multi' => true,
    1024                                 'hook_extra' => array(
    1025                                         'plugin' => $plugin
    1026                                 )
    1027                         ) );
    1028 
    1029                         $results[$plugin] = $this->result;
    1030 
    1031                         // Prevent credentials auth screen from displaying multiple times
    1032                         if ( false === $result )
    1033                                 break;
    1034                 } //end foreach $plugins
    1035 
    1036                 $this->maintenance_mode(false);
    1037 
    1038                 /**
    1039                  * Fires when the bulk upgrader process is complete.
    1040                  *
    1041                  * @since 3.6.0
    1042                  *
    1043                  * @param Plugin_Upgrader $this Plugin_Upgrader instance. In other contexts, $this, might
    1044                  *                              be a Theme_Upgrader or Core_Upgrade instance.
    1045                  * @param array           $data {
    1046                  *     Array of bulk item update data.
    1047                  *
    1048                  *     @type string $action   Type of action. Default 'update'.
    1049                  *     @type string $type     Type of update process. Accepts 'plugin', 'theme', or 'core'.
    1050                  *     @type bool   $bulk     Whether the update process is a bulk update. Default true.
    1051                  *     @type array  $packages Array of plugin, theme, or core packages to update.
    1052                  * }
    1053                  */
    1054                 do_action( 'upgrader_process_complete', $this, array(
    1055                         'action' => 'update',
    1056                         'type' => 'plugin',
    1057                         'bulk' => true,
    1058                         'plugins' => $plugins,
    1059                 ) );
    1060 
    1061                 $this->skin->bulk_footer();
    1062 
    1063                 $this->skin->footer();
    1064 
    1065                 // Cleanup our hooks, in case something else does a upgrade on this connection.
    1066                 remove_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'));
    1067 
    1068                 // Force refresh of plugin update information.
    1069                 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
    1070 
    1071                 return $results;
    1072         }
    1073 
    1074         /**
    1075          * Check a source package to be sure it contains a plugin.
    1076          *
    1077          * This function is added to the {@see 'upgrader_source_selection'} filter by
    1078          * {@see Plugin_Upgrader::install()}.
    1079          *
    1080          * @since 3.3.0
    1081          * @access public
    1082          *
    1083          * @global WP_Filesystem_Base $wp_filesystem Subclass
    1084          *
    1085          * @param string $source The path to the downloaded package source.
    1086          * @return string|WP_Error The source as passed, or a {@see WP_Error} object
    1087          *                         if no plugins were found.
    1088          */
    1089         public function check_package($source) {
    1090                 global $wp_filesystem;
    1091 
    1092                 if ( is_wp_error($source) )
    1093                         return $source;
    1094 
    1095                 $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source);
    1096                 if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, let's not prevent installation.
    1097                         return $source;
    1098 
    1099                 // Check the folder contains at least 1 valid plugin.
    1100                 $plugins_found = false;
    1101                 $files = glob( $working_directory . '*.php' );
    1102                 if ( $files ) {
    1103                         foreach ( $files as $file ) {
    1104                                 $info = get_plugin_data( $file, false, false );
    1105                                 if ( ! empty( $info['Name'] ) ) {
    1106                                         $plugins_found = true;
    1107                                         break;
    1108                                 }
    1109                         }
    1110                 }
    1111 
    1112                 if ( ! $plugins_found )
    1113                         return new WP_Error( 'incompatible_archive_no_plugins', $this->strings['incompatible_archive'], __( 'No valid plugins were found.' ) );
    1114 
    1115                 return $source;
    1116         }
    1117 
    1118         /**
    1119          * Retrieve the path to the file that contains the plugin info.
    1120          *
    1121          * This isn't used internally in the class, but is called by the skins.
    1122          *
    1123          * @since 2.8.0
    1124          * @access public
    1125          *
    1126          * @return string|false The full path to the main plugin file, or false.
    1127          */
    1128         public function plugin_info() {
    1129                 if ( ! is_array($this->result) )
    1130                         return false;
    1131                 if ( empty($this->result['destination_name']) )
    1132                         return false;
    1133 
    1134                 $plugin = get_plugins('/' . $this->result['destination_name']); //Ensure to pass with leading slash
    1135                 if ( empty($plugin) )
    1136                         return false;
    1137 
    1138                 $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list
    1139 
    1140                 return $this->result['destination_name'] . '/' . $pluginfiles[0];
    1141         }
    1142 
    1143         /**
    1144          * Deactivates a plugin before it is upgraded.
    1145          *
    1146          * Hooked to the {@see 'upgrader_pre_install'} filter by {@see Plugin_Upgrader::upgrade()}.
    1147          *
    1148          * @since 2.8.0
    1149          * @since 4.1.0 Added a return value.
    1150          * @access public
    1151          *
    1152          * @param bool|WP_Error  $return Upgrade offer return.
    1153          * @param array          $plugin Plugin package arguments.
    1154          * @return bool|WP_Error The passed in $return param or {@see WP_Error}.
    1155          */
    1156         public function deactivate_plugin_before_upgrade($return, $plugin) {
    1157 
    1158                 if ( is_wp_error($return) ) //Bypass.
    1159                         return $return;
    1160 
    1161                 // When in cron (background updates) don't deactivate the plugin, as we require a browser to reactivate it
    1162                 if ( defined( 'DOING_CRON' ) && DOING_CRON )
    1163                         return $return;
    1164 
    1165                 $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : '';
    1166                 if ( empty($plugin) )
    1167                         return new WP_Error('bad_request', $this->strings['bad_request']);
    1168 
    1169                 if ( is_plugin_active($plugin) ) {
    1170                         //Deactivate the plugin silently, Prevent deactivation hooks from running.
    1171                         deactivate_plugins($plugin, true);
    1172                 }
    1173 
    1174                 return $return;
    1175         }
    1176 
    1177         /**
    1178          * Delete the old plugin during an upgrade.
    1179          *
    1180          * Hooked to the {@see 'upgrader_clear_destination'} filter by
    1181          * {@see Plugin_Upgrader::upgrade()} and {@see Plugin_Upgrader::bulk_upgrade()}.
    1182          *
    1183          * @since 2.8.0
    1184          * @access public
    1185          *
    1186          * @global WP_Filesystem_Base $wp_filesystem Subclass
    1187      *
    1188          * @param bool|WP_Error $removed
    1189          * @param string        $local_destination
    1190          * @param string        $remote_destination
    1191          * @param array         $plugin
    1192          * @return WP_Error|bool
    1193          */
    1194         public function delete_old_plugin($removed, $local_destination, $remote_destination, $plugin) {
    1195                 global $wp_filesystem;
    1196 
    1197                 if ( is_wp_error($removed) )
    1198                         return $removed; //Pass errors through.
    1199 
    1200                 $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : '';
    1201                 if ( empty($plugin) )
    1202                         return new WP_Error('bad_request', $this->strings['bad_request']);
    1203 
    1204                 $plugins_dir = $wp_filesystem->wp_plugins_dir();
    1205                 $this_plugin_dir = trailingslashit( dirname($plugins_dir . $plugin) );
    1206 
    1207                 if ( ! $wp_filesystem->exists($this_plugin_dir) ) //If it's already vanished.
    1208                         return $removed;
    1209 
    1210                 // If plugin is in its own directory, recursively delete the directory.
    1211                 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
    1212                         $deleted = $wp_filesystem->delete($this_plugin_dir, true);
    1213                 else
    1214                         $deleted = $wp_filesystem->delete($plugins_dir . $plugin);
    1215 
    1216                 if ( ! $deleted )
    1217                         return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']);
    1218 
    1219                 return true;
    1220         }
    1221807}
    1222 
    1223 /**
    1224  * Core class used for upgrading/installing themes.
    1225  *
    1226  * It is designed to upgrade/install themes from a local zip, remote zip URL,
    1227  * or uploaded zip file.
    1228  *
    1229  * @since 2.8.0
    1230  *
    1231  * @see WP_Upgrader
    1232  */
    1233 class Theme_Upgrader extends WP_Upgrader {
    1234 
    1235         /**
    1236          * Result of the theme upgrade offer.
    1237          *
    1238          * @since 2.8.0
    1239          * @access public
    1240          * @var array|WP_Error $result
    1241          * @see WP_Upgrader::$result
    1242          */
    1243         public $result;
    1244 
    1245         /**
    1246          * Whether multiple themes are being upgraded/installed in bulk.
    1247          *
    1248          * @since 2.9.0
    1249          * @access public
    1250          * @var bool $bulk
    1251          */
    1252         public $bulk = false;
    1253 
    1254         /**
    1255          * Initialize the upgrade strings.
    1256          *
    1257          * @since 2.8.0
    1258          * @access public
    1259          */
    1260         public function upgrade_strings() {
    1261                 $this->strings['up_to_date'] = __('The theme is at the latest version.');
    1262                 $this->strings['no_package'] = __('Update package not available.');
    1263                 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
    1264                 $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
    1265                 $this->strings['remove_old'] = __('Removing the old version of the theme&#8230;');
    1266                 $this->strings['remove_old_failed'] = __('Could not remove the old theme.');
    1267                 $this->strings['process_failed'] = __('Theme update failed.');
    1268                 $this->strings['process_success'] = __('Theme updated successfully.');
    1269         }
    1270 
    1271         /**
    1272          * Initialize the install strings.
    1273          *
    1274          * @since 2.8.0
    1275          * @access public
    1276          */
    1277         public function install_strings() {
    1278                 $this->strings['no_package'] = __('Install package not available.');
    1279                 $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>&#8230;');
    1280                 $this->strings['unpack_package'] = __('Unpacking the package&#8230;');
    1281                 $this->strings['installing_package'] = __('Installing the theme&#8230;');
    1282                 $this->strings['no_files'] = __('The theme contains no files.');
    1283                 $this->strings['process_failed'] = __('Theme install failed.');
    1284                 $this->strings['process_success'] = __('Theme installed successfully.');
    1285                 /* translators: 1: theme name, 2: version */
    1286                 $this->strings['process_success_specific'] = __('Successfully installed the theme <strong>%1$s %2$s</strong>.');
    1287                 $this->strings['parent_theme_search'] = __('This theme requires a parent theme. Checking if it is installed&#8230;');
    1288                 /* translators: 1: theme name, 2: version */
    1289                 $this->strings['parent_theme_prepare_install'] = __('Preparing to install <strong>%1$s %2$s</strong>&#8230;');
    1290                 /* translators: 1: theme name, 2: version */
    1291                 $this->strings['parent_theme_currently_installed'] = __('The parent theme, <strong>%1$s %2$s</strong>, is currently installed.');
    1292                 /* translators: 1: theme name, 2: version */
    1293                 $this->strings['parent_theme_install_success'] = __('Successfully installed the parent theme, <strong>%1$s %2$s</strong>.');
    1294                 $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.');
    1295         }
    1296 
    1297         /**
    1298          * Check if a child theme is being installed and we need to install its parent.
    1299          *
    1300          * Hooked to the {@see 'upgrader_post_install'} filter by {@see Theme_Upgrader::install()}.
    1301          *
    1302          * @since 3.4.0
    1303          * @access public
    1304          *
    1305          * @param bool  $install_result
    1306          * @param array $hook_extra
    1307          * @param array $child_result
    1308          * @return type
    1309          */
    1310         public function check_parent_theme_filter( $install_result, $hook_extra, $child_result ) {
    1311                 // Check to see if we need to install a parent theme
    1312                 $theme_info = $this->theme_info();
    1313 
    1314                 if ( ! $theme_info->parent() )
    1315                         return $install_result;
    1316 
    1317                 $this->skin->feedback( 'parent_theme_search' );
    1318 
    1319                 if ( ! $theme_info->parent()->errors() ) {
    1320                         $this->skin->feedback( 'parent_theme_currently_installed', $theme_info->parent()->display('Name'), $theme_info->parent()->display('Version') );
    1321                         // We already have the theme, fall through.
    1322                         return $install_result;
    1323                 }
    1324 
    1325                 // We don't have the parent theme, let's install it.
    1326                 $api = themes_api('theme_information', array('slug' => $theme_info->get('Template'), 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth.
    1327 
    1328                 if ( ! $api || is_wp_error($api) ) {
    1329                         $this->skin->feedback( 'parent_theme_not_found', $theme_info->get('Template') );
    1330                         // Don't show activate or preview actions after install
    1331                         add_filter('install_theme_complete_actions', array($this, 'hide_activate_preview_actions') );
    1332                         return $install_result;
    1333                 }
    1334 
    1335                 // Backup required data we're going to override:
    1336                 $child_api = $this->skin->api;
    1337                 $child_success_message = $this->strings['process_success'];
    1338 
    1339                 // Override them
    1340                 $this->skin->api = $api;
    1341                 $this->strings['process_success_specific'] = $this->strings['parent_theme_install_success'];//, $api->name, $api->version);
    1342 
    1343                 $this->skin->feedback('parent_theme_prepare_install', $api->name, $api->version);
    1344 
    1345                 add_filter('install_theme_complete_actions', '__return_false', 999); // Don't show any actions after installing the theme.
    1346 
    1347                 // Install the parent theme
    1348                 $parent_result = $this->run( array(
    1349                         'package' => $api->download_link,
    1350                         'destination' => get_theme_root(),
    1351                         'clear_destination' => false, //Do not overwrite files.
    1352                         'clear_working' => true
    1353                 ) );
    1354 
    1355                 if ( is_wp_error($parent_result) )
    1356                         add_filter('install_theme_complete_actions', array($this, 'hide_activate_preview_actions') );
    1357 
    1358                 // Start cleaning up after the parents installation
    1359                 remove_filter('install_theme_complete_actions', '__return_false', 999);
    1360 
    1361                 // Reset child's result and data
    1362                 $this->result = $child_result;
    1363                 $this->skin->api = $child_api;
    1364                 $this->strings['process_success'] = $child_success_message;
    1365 
    1366                 return $install_result;
    1367         }
    1368 
    1369         /**
    1370          * Don't display the activate and preview actions to the user.
    1371          *
    1372          * Hooked to the {@see 'install_theme_complete_actions'} filter by
    1373          * {@see Theme_Upgrader::check_parent_theme_filter()} when installing
    1374          * a child theme and installing the parent theme fails.
    1375          *
    1376          * @since 3.4.0
    1377          * @access public
    1378          *
    1379          * @param array $actions Preview actions.
    1380          * @return array
    1381          */
    1382         public function hide_activate_preview_actions( $actions ) {
    1383                 unset($actions['activate'], $actions['preview']);
    1384                 return $actions;
    1385         }
    1386 
    1387         /**
    1388          * Install a theme package.
    1389          *
    1390          * @since 2.8.0
    1391          * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional.
    1392          * @access public
    1393          *
    1394          * @param string $package The full local path or URI of the package.
    1395          * @param array  $args {
    1396          *     Optional. Other arguments for installing a theme package. Default empty array.
    1397          *
    1398          *     @type bool $clear_update_cache Whether to clear the updates cache if successful.
    1399          *                                    Default true.
    1400          * }
    1401          *
    1402          * @return bool|WP_Error True if the install was successful, false or a {@see WP_Error} object otherwise.
    1403          */
    1404         public function install( $package, $args = array() ) {
    1405 
    1406                 $defaults = array(
    1407                         'clear_update_cache' => true,
    1408                 );
    1409                 $parsed_args = wp_parse_args( $args, $defaults );
    1410 
    1411                 $this->init();
    1412                 $this->install_strings();
    1413 
    1414                 add_filter('upgrader_source_selection', array($this, 'check_package') );
    1415                 add_filter('upgrader_post_install', array($this, 'check_parent_theme_filter'), 10, 3);
    1416                 // Clear cache so wp_update_themes() knows about the new theme.
    1417                 add_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9, 0 );
    1418 
    1419                 $this->run( array(
    1420                         'package' => $package,
    1421                         'destination' => get_theme_root(),
    1422                         'clear_destination' => false, //Do not overwrite files.
    1423                         'clear_working' => true,
    1424                         'hook_extra' => array(
    1425                                 'type' => 'theme',
    1426                                 'action' => 'install',
    1427                         ),
    1428                 ) );
    1429 
    1430                 remove_action( 'upgrader_process_complete', 'wp_clean_themes_cache', 9 );
    1431                 remove_filter('upgrader_source_selection', array($this, 'check_package') );
    1432                 remove_filter('upgrader_post_install', array($this, 'check_parent_theme_filter'));
    1433 
    1434                 if ( ! $this->result || is_wp_error($this->result) )
    1435                         return $this->result;
    1436 
    1437                 // Refresh the Theme Update information
    1438                 wp_clean_themes_cache( $parsed_args['clear_update_cache'] );
    1439 
    1440                 return true;
    1441         }
    1442 
    1443         /**
    1444          * Upgrade a theme.
    1445          *
    1446          * @since 2.8.0
    1447          * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional.
    1448          * @access public
    1449          *
    1450          * @param string $theme The theme slug.
    1451          * @param array  $args {
    1452          *     Optional. Other arguments for upgrading a theme. Default empty array.
    1453          *
    1454          *     @type bool $clear_update_cache Whether to clear the update cache if successful.
    1455          *                                    Default true.
    1456          * }
    1457          * @return bool|WP_Error True if the upgrade was successful, false or a {@see WP_Error} object otherwise.
    1458          */
    1459         public function upgrade( $theme, $args = array() ) {
    1460 
    1461                 $defaults = array(
    1462                         'clear_update_cache' => true,
    1463                 );
    1464                 $parsed_args = wp_parse_args( $args, $defaults );
    1465 
    1466                 $this->init();
    1467                 $this->upgrade_strings();
    1468 
    1469                 // Is an update available?
    1470                 $current = get_site_transient( 'update_themes' );
    1471                 if ( !isset( $current->response[ $theme ] ) ) {
    1472                         $this->skin->before();
    1473                         $this->skin->set_result(false);
    1474                         $this->skin->error( 'up_to_date' );
    1475                         $this->skin->after();
    1476                         return false;
    1477                 }
    1478 
    1479                 $r = $current->response[ $theme ];
    1480 
    1481                 add_filter('upgrader_pre_install', array($this, 'current_before'), 10, 2);
    1482                 add_filter('upgrader_post_install', array($this, 'current_after'), 10, 2);
    1483                 add_filter('upgrader_clear_destination', array($this, 'delete_old_theme'), 10, 4);
    1484 
    1485                 $this->run( array(
    1486                         'package' => $r['package'],
    1487                         'destination' => get_theme_root( $theme ),
    1488                         'clear_destination' => true,
    1489                         'clear_working' => true,
    1490                         'hook_extra' => array(
    1491                                 'theme' => $theme,
    1492                                 'type' => 'theme',
    1493                                 'action' => 'update',
    1494                         ),
    1495                 ) );
    1496 
    1497                 remove_filter('upgrader_pre_install', array($this, 'current_before'));
    1498                 remove_filter('upgrader_post_install', array($this, 'current_after'));
    1499                 remove_filter('upgrader_clear_destination', array($this, 'delete_old_theme'));
    1500 
    1501                 if ( ! $this->result || is_wp_error($this->result) )
    1502                         return $this->result;
    1503 
    1504                 wp_clean_themes_cache( $parsed_args['clear_update_cache'] );
    1505 
    1506                 return true;
    1507         }
    1508 
    1509         /**
    1510          * Upgrade several themes at once.
    1511          *
    1512          * @since 3.0.0
    1513          * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional.
    1514          * @access public
    1515          *
    1516          * @param array $themes The theme slugs.
    1517          * @param array $args {
    1518          *     Optional. Other arguments for upgrading several themes at once. Default empty array.
    1519          *
    1520          *     @type bool $clear_update_cache Whether to clear the update cache if successful.
    1521          *                                    Default true.
    1522          * }
    1523          * @return array[]|false An array of results, or false if unable to connect to the filesystem.
    1524          */
    1525         public function bulk_upgrade( $themes, $args = array() ) {
    1526 
    1527                 $defaults = array(
    1528                         'clear_update_cache' => true,
    1529                 );
    1530                 $parsed_args = wp_parse_args( $args, $defaults );
    1531 
    1532                 $this->init();
    1533                 $this->bulk = true;
    1534                 $this->upgrade_strings();
    1535 
    1536                 $current = get_site_transient( 'update_themes' );
    1537 
    1538                 add_filter('upgrader_pre_install', array($this, 'current_before'), 10, 2);
    1539                 add_filter('upgrader_post_install', array($this, 'current_after'), 10, 2);
    1540                 add_filter('upgrader_clear_destination', array($this, 'delete_old_theme'), 10, 4);
    1541 
    1542                 $this->skin->header();
    1543 
    1544                 // Connect to the Filesystem first.
    1545                 $res = $this->fs_connect( array(WP_CONTENT_DIR) );
    1546                 if ( ! $res ) {
    1547                         $this->skin->footer();
    1548                         return false;
    1549                 }
    1550 
    1551                 $this->skin->bulk_header();
    1552 
    1553                 // Only start maintenance mode if:
    1554                 // - running Multisite and there are one or more themes specified, OR
    1555                 // - a theme with an update available is currently in use.
    1556                 // @TODO: For multisite, maintenance mode should only kick in for individual sites if at all possible.
    1557                 $maintenance = ( is_multisite() && ! empty( $themes ) );
    1558                 foreach ( $themes as $theme )
    1559                         $maintenance = $maintenance || $theme == get_stylesheet() || $theme == get_template();
    1560                 if ( $maintenance )
    1561                         $this->maintenance_mode(true);
    1562 
    1563                 $results = array();
    1564 
    1565                 $this->update_count = count($themes);
    1566                 $this->update_current = 0;
    1567                 foreach ( $themes as $theme ) {
    1568                         $this->update_current++;
    1569 
    1570                         $this->skin->theme_info = $this->theme_info($theme);
    1571 
    1572                         if ( !isset( $current->response[ $theme ] ) ) {
    1573                                 $this->skin->set_result(true);
    1574                                 $this->skin->before();
    1575                                 $this->skin->feedback( 'up_to_date' );
    1576                                 $this->skin->after();
    1577                                 $results[$theme] = true;
    1578                                 continue;
    1579                         }
    1580 
    1581                         // Get the URL to the zip file
    1582                         $r = $current->response[ $theme ];
    1583 
    1584                         $result = $this->run( array(
    1585                                 'package' => $r['package'],
    1586                                 'destination' => get_theme_root( $theme ),
    1587                                 'clear_destination' => true,
    1588                                 'clear_working' => true,
    1589                                 'is_multi' => true,
    1590                                 'hook_extra' => array(
    1591                                         'theme' => $theme
    1592                                 ),
    1593                         ) );
    1594 
    1595                         $results[$theme] = $this->result;
    1596 
    1597                         // Prevent credentials auth screen from displaying multiple times
    1598                         if ( false === $result )
    1599                                 break;
    1600                 } //end foreach $plugins
    1601 
    1602                 $this->maintenance_mode(false);
    1603 
    1604                 /** This action is documented in wp-admin/includes/class-wp-upgrader.php */
    1605                 do_action( 'upgrader_process_complete', $this, array(
    1606                         'action' => 'update',
    1607                         'type' => 'theme',
    1608                         'bulk' => true,
    1609                         'themes' => $themes,
    1610                 ) );
    1611 
    1612                 $this->skin->bulk_footer();
    1613 
    1614                 $this->skin->footer();
    1615 
    1616                 // Cleanup our hooks, in case something else does a upgrade on this connection.
    1617                 remove_filter('upgrader_pre_install', array($this, 'current_before'));
    1618                 remove_filter('upgrader_post_install', array($this, 'current_after'));
    1619                 remove_filter('upgrader_clear_destination', array($this, 'delete_old_theme'));
    1620 
    1621                 // Refresh the Theme Update information
    1622                 wp_clean_themes_cache( $parsed_args['clear_update_cache'] );
    1623 
    1624                 return $results;
    1625         }
    1626 
    1627         /**
    1628          * Check that the package source contains a valid theme.
    1629          *
    1630          * Hooked to the {@see 'upgrader_source_selection'} filter by {@see Theme_Upgrader::install()}.
    1631          * It will return an error if the theme doesn't have style.css or index.php
    1632          * files.
    1633          *
    1634          * @since 3.3.0
    1635          * @access public
    1636          *
    1637          * @global WP_Filesystem_Base $wp_filesystem Subclass
    1638          *
    1639          * @param string $source The full path to the package source.
    1640          * @return string|WP_Error The source or a WP_Error.
    1641          */
    1642         public function check_package( $source ) {
    1643                 global $wp_filesystem;
    1644 
    1645                 if ( is_wp_error($source) )
    1646                         return $source;
    1647 
    1648                 // Check the folder contains a valid theme
    1649                 $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source);
    1650                 if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, let's not prevent installation.
    1651                         return $source;
    1652 
    1653                 // A proper archive should have a style.css file in the single subdirectory
    1654                 if ( ! file_exists( $working_directory . 'style.css' ) ) {
    1655                         return new WP_Error( 'incompatible_archive_theme_no_style', $this->strings['incompatible_archive'],
    1656                                 /* translators: %s: style.css */
    1657                                 sprintf( __( 'The theme is missing the %s stylesheet.' ),
    1658                                         '<code>style.css</code>'
    1659                                 )
    1660                         );
    1661                 }
    1662 
    1663                 $info = get_file_data( $working_directory . 'style.css', array( 'Name' => 'Theme Name', 'Template' => 'Template' ) );
    1664 
    1665                 if ( empty( $info['Name'] ) ) {
    1666                         return new WP_Error( 'incompatible_archive_theme_no_name', $this->strings['incompatible_archive'],
    1667                                 /* translators: %s: style.css */
    1668                                 sprintf( __( 'The %s stylesheet doesn&#8217;t contain a valid theme header.' ),
    1669                                         '<code>style.css</code>'
    1670                                 )
    1671                         );
    1672                 }
    1673 
    1674                 // If it's not a child theme, it must have at least an index.php to be legit.
    1675                 if ( empty( $info['Template'] ) && ! file_exists( $working_directory . 'index.php' ) ) {
    1676                         return new WP_Error( 'incompatible_archive_theme_no_index', $this->strings['incompatible_archive'],
    1677                                 /* translators: %s: index.php */
    1678                                 sprintf( __( 'The theme is missing the %s file.' ),
    1679                                         '<code>index.php</code>'
    1680                                 )
    1681                         );
    1682                 }
    1683 
    1684                 return $source;
    1685         }
    1686 
    1687         /**
    1688          * Turn on maintenance mode before attempting to upgrade the current theme.
    1689          *
    1690          * Hooked to the {@see 'upgrader_pre_install'} filter by {@see Theme_Upgrader::upgrade()} and
    1691          * {@see Theme_Upgrader::bulk_upgrade()}.
    1692          *
    1693          * @since 2.8.0
    1694          * @access public
    1695          *
    1696          * @param bool|WP_Error  $return
    1697          * @param array          $theme
    1698          * @return bool|WP_Error
    1699          */
    1700         public function current_before($return, $theme) {
    1701                 if ( is_wp_error($return) )
    1702                         return $return;
    1703 
    1704                 $theme = isset($theme['theme']) ? $theme['theme'] : '';
    1705 
    1706                 if ( $theme != get_stylesheet() ) //If not current
    1707                         return $return;
    1708                 //Change to maintenance mode now.
    1709                 if ( ! $this->bulk )
    1710                         $this->maintenance_mode(true);
    1711 
    1712                 return $return;
    1713         }
    1714 
    1715         /**
    1716          * Turn off maintenance mode after upgrading the current theme.
    1717          *
    1718          * Hooked to the {@see 'upgrader_post_install'} filter by {@see Theme_Upgrader::upgrade()}
    1719          * and {@see Theme_Upgrader::bulk_upgrade()}.
    1720          *
    1721          * @since 2.8.0
    1722          * @access public
    1723          *
    1724          * @param bool|WP_Error  $return
    1725          * @param array          $theme
    1726          * @return bool|WP_Error
    1727          */
    1728         public function current_after($return, $theme) {
    1729                 if ( is_wp_error($return) )
    1730                         return $return;
    1731 
    1732                 $theme = isset($theme['theme']) ? $theme['theme'] : '';
    1733 
    1734                 if ( $theme != get_stylesheet() ) // If not current
    1735                         return $return;
    1736 
    1737                 // Ensure stylesheet name hasn't changed after the upgrade:
    1738                 if ( $theme == get_stylesheet() && $theme != $this->result['destination_name'] ) {
    1739                         wp_clean_themes_cache();
    1740                         $stylesheet = $this->result['destination_name'];
    1741                         switch_theme( $stylesheet );
    1742                 }
    1743 
    1744                 //Time to remove maintenance mode
    1745                 if ( ! $this->bulk )
    1746                         $this->maintenance_mode(false);
    1747                 return $return;
    1748         }
    1749 
    1750         /**
    1751          * Delete the old theme during an upgrade.
    1752          *
    1753          * Hooked to the {@see 'upgrader_clear_destination'} filter by {@see Theme_Upgrader::upgrade()}
    1754          * and {@see Theme_Upgrader::bulk_upgrade()}.
    1755          *
    1756          * @since 2.8.0
    1757          * @access public
    1758          *
    1759          * @global WP_Filesystem_Base $wp_filesystem Subclass
    1760          *
    1761          * @param bool   $removed
    1762          * @param string $local_destination
    1763          * @param string $remote_destination
    1764          * @param array  $theme
    1765          * @return bool
    1766          */
    1767         public function delete_old_theme( $removed, $local_destination, $remote_destination, $theme ) {
    1768                 global $wp_filesystem;
    1769 
    1770                 if ( is_wp_error( $removed ) )
    1771                         return $removed; // Pass errors through.
    1772 
    1773                 if ( ! isset( $theme['theme'] ) )
    1774                         return $removed;
    1775 
    1776                 $theme = $theme['theme'];
    1777                 $themes_dir = trailingslashit( $wp_filesystem->wp_themes_dir( $theme ) );
    1778                 if ( $wp_filesystem->exists( $themes_dir . $theme ) ) {
    1779                         if ( ! $wp_filesystem->delete( $themes_dir . $theme, true ) )
    1780                                 return false;
    1781                 }
    1782 
    1783                 return true;
    1784         }
    1785 
    1786         /**
    1787          * Get the WP_Theme object for a theme.
    1788          *
    1789          * @since 2.8.0
    1790          * @since 3.0.0 The `$theme` argument was added.
    1791          * @access public
    1792          *
    1793          * @param string $theme The directory name of the theme. This is optional, and if not supplied,
    1794          *                      the directory name from the last result will be used.
    1795          * @return WP_Theme|false The theme's info object, or false `$theme` is not supplied
    1796          *                        and the last result isn't set.
    1797          */
    1798         public function theme_info($theme = null) {
    1799 
    1800                 if ( empty($theme) ) {
    1801                         if ( !empty($this->result['destination_name']) )
    1802                                 $theme = $this->result['destination_name'];
    1803                         else
    1804                                 return false;
    1805                 }
    1806                 return wp_get_theme( $theme );
    1807         }
    1808 
    1809 }
    1810 
    1811 /**
    1812  * Core class used for updating/installing language packs (translations)
    1813  * for plugins, themes, and core.
    1814  *
    1815  * @since 3.7.0
    1816  *
    1817  * @see WP_Upgrader
    1818  */
    1819 class Language_Pack_Upgrader extends WP_Upgrader {
    1820 
    1821         /**
    1822          * Result of the language pack upgrade.
    1823          *
    1824          * @since 3.7.0
    1825          * @access public
    1826          * @var array|WP_Error $result
    1827          * @see WP_Upgrader::$result
    1828          */
    1829         public $result;
    1830 
    1831         /**
    1832          * Whether a bulk upgrade/install is being performed.
    1833          *
    1834          * @since 3.7.0
    1835          * @access public
    1836          * @var bool $bulk
    1837          */
    1838         public $bulk = true;
    1839 
    1840         /**
    1841          * Asynchronously upgrades language packs after other upgrades have been made.
    1842          *
    1843          * Hooked to the {@see 'upgrader_process_complete'} action by default.
    1844          *
    1845          * @since 3.7.0
    1846          * @access public
    1847          * @static
    1848          *
    1849          * @param false|WP_Upgrader $upgrader Optional. WP_Upgrader instance or false. If `$upgrader` is
    1850          *                                    a Language_Pack_Upgrader instance, the method will bail to
    1851          *                                    avoid recursion. Otherwise unused. Default false.
    1852          */
    1853         public static function async_upgrade( $upgrader = false ) {
    1854                 // Avoid recursion.
    1855                 if ( $upgrader && $upgrader instanceof Language_Pack_Upgrader ) {
    1856                         return;
    1857                 }
    1858 
    1859                 // Nothing to do?
    1860                 $language_updates = wp_get_translation_updates();
    1861                 if ( ! $language_updates ) {
    1862                         return;
    1863                 }
    1864 
    1865                 /*
    1866                  * Avoid messing with VCS installs, at least for now.
    1867                  * Noted: this is not the ideal way to accomplish this.
    1868                  */
    1869                 $check_vcs = new WP_Automatic_Updater;
    1870                 if ( $check_vcs->is_vcs_checkout( WP_CONTENT_DIR ) ) {
    1871                         return;
    1872                 }
    1873 
    1874                 foreach ( $language_updates as $key => $language_update ) {
    1875                         $update = ! empty( $language_update->autoupdate );
    1876 
    1877                         /**
    1878                          * Filter whether to asynchronously update translation for core, a plugin, or a theme.
    1879                          *
    1880                          * @since 4.0.0
    1881                          *
    1882                          * @param bool   $update          Whether to update.
    1883                          * @param object $language_update The update offer.
    1884                          */
    1885                         $update = apply_filters( 'async_update_translation', $update, $language_update );
    1886 
    1887                         if ( ! $update ) {
    1888                                 unset( $language_updates[ $key ] );
    1889                         }
    1890                 }
    1891 
    1892                 if ( empty( $language_updates ) ) {
    1893                         return;
    1894                 }
    1895 
    1896                 // Re-use the automatic upgrader skin if the parent upgrader is using it.
    1897                 if ( $upgrader && $upgrader->skin instanceof Automatic_Upgrader_Skin ) {
    1898                         $skin = $upgrader->skin;
    1899                 } else {
    1900                         $skin = new Language_Pack_Upgrader_Skin( array(
    1901                                 'skip_header_footer' => true,
    1902                         ) );
    1903                 }
    1904 
    1905                 $lp_upgrader = new Language_Pack_Upgrader( $skin );
    1906                 $lp_upgrader->bulk_upgrade( $language_updates );
    1907         }
    1908 
    1909         /**
    1910          * Initialize the upgrade strings.
    1911          *
    1912          * @since 3.7.0
    1913          * @access public
    1914          */
    1915         public function upgrade_strings() {
    1916                 $this->strings['starting_upgrade'] = __( 'Some of your translations need updating. Sit tight for a few more seconds while we update them as well.' );
    1917                 $this->strings['up_to_date'] = __( 'The translation is up to date.' ); // We need to silently skip this case
    1918                 $this->strings['no_package'] = __( 'Update package not available.' );
    1919                 $this->strings['downloading_package'] = __( 'Downloading translation from <span class="code">%s</span>&#8230;' );
    1920                 $this->strings['unpack_package'] = __( 'Unpacking the update&#8230;' );
    1921                 $this->strings['process_failed'] = __( 'Translation update failed.' );
    1922                 $this->strings['process_success'] = __( 'Translation updated successfully.' );
    1923         }
    1924 
    1925         /**
    1926          * Upgrade a language pack.
    1927          *
    1928          * @since 3.7.0
    1929          * @access public
    1930          *
    1931          * @param string|false $update Optional. Whether an update offer is available. Default false.
    1932          * @param array        $args   Optional. Other optional arguments, see
    1933          *                             {@see Language_Pack_Upgrader::bulk_upgrade()}. Default empty array.
    1934          * @return array|bool|WP_Error The result of the upgrade, or a {@see wP_Error} object instead.
    1935          */
    1936         public function upgrade( $update = false, $args = array() ) {
    1937                 if ( $update ) {
    1938                         $update = array( $update );
    1939                 }
    1940 
    1941                 $results = $this->bulk_upgrade( $update, $args );
    1942 
    1943                 if ( ! is_array( $results ) ) {
    1944                         return $results;
    1945                 }
    1946 
    1947                 return $results[0];
    1948         }
    1949 
    1950         /**
    1951          * Bulk upgrade language packs.
    1952          *
    1953          * @since 3.7.0
    1954          * @access public
    1955          *
    1956          * @global WP_Filesystem_Base $wp_filesystem Subclass
    1957          *
    1958          * @param array $language_updates Optional. Language pack updates. Default empty array.
    1959          * @param array $args {
    1960          *     Optional. Other arguments for upgrading multiple language packs. Default empty array
    1961          *
    1962          *     @type bool $clear_update_cache Whether to clear the update cache when done.
    1963          *                                    Default true.
    1964          * }
    1965          * @return array|bool|WP_Error Will return an array of results, or true if there are no updates,
    1966          *                                   false or WP_Error for initial errors.
    1967          */
    1968         public function bulk_upgrade( $language_updates = array(), $args = array() ) {
    1969                 global $wp_filesystem;
    1970 
    1971                 $defaults = array(
    1972                         'clear_update_cache' => true,
    1973                 );
    1974                 $parsed_args = wp_parse_args( $args, $defaults );
    1975 
    1976                 $this->init();
    1977                 $this->upgrade_strings();
    1978 
    1979                 if ( ! $language_updates )
    1980                         $language_updates = wp_get_translation_updates();
    1981 
    1982                 if ( empty( $language_updates ) ) {
    1983                         $this->skin->header();
    1984                         $this->skin->before();
    1985                         $this->skin->set_result( true );
    1986                         $this->skin->feedback( 'up_to_date' );
    1987                         $this->skin->after();
    1988                         $this->skin->bulk_footer();
    1989                         $this->skin->footer();
    1990                         return true;
    1991                 }
    1992 
    1993                 if ( 'upgrader_process_complete' == current_filter() )
    1994                         $this->skin->feedback( 'starting_upgrade' );
    1995 
    1996                 // Remove any existing upgrade filters from the plugin/theme upgraders #WP29425 & #WP29230
    1997                 remove_all_filters( 'upgrader_pre_install' );
    1998                 remove_all_filters( 'upgrader_clear_destination' );
    1999                 remove_all_filters( 'upgrader_post_install' );
    2000                 remove_all_filters( 'upgrader_source_selection' );
    2001 
    2002                 add_filter( 'upgrader_source_selection', array( $this, 'check_package' ), 10, 2 );
    2003 
    2004                 $this->skin->header();
    2005 
    2006                 // Connect to the Filesystem first.
    2007                 $res = $this->fs_connect( array( WP_CONTENT_DIR, WP_LANG_DIR ) );
    2008                 if ( ! $res ) {
    2009                         $this->skin->footer();
    2010                         return false;
    2011                 }
    2012 
    2013                 $results = array();
    2014 
    2015                 $this->update_count = count( $language_updates );
    2016                 $this->update_current = 0;
    2017 
    2018                 /*
    2019                  * The filesystem's mkdir() is not recursive. Make sure WP_LANG_DIR exists,
    2020                  * as we then may need to create a /plugins or /themes directory inside of it.
    2021                  */
    2022                 $remote_destination = $wp_filesystem->find_folder( WP_LANG_DIR );
    2023                 if ( ! $wp_filesystem->exists( $remote_destination ) )
    2024                         if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) )
    2025                                 return new WP_Error( 'mkdir_failed_lang_dir', $this->strings['mkdir_failed'], $remote_destination );
    2026 
    2027                 foreach ( $language_updates as $language_update ) {
    2028 
    2029                         $this->skin->language_update = $language_update;
    2030 
    2031                         $destination = WP_LANG_DIR;
    2032                         if ( 'plugin' == $language_update->type )
    2033                                 $destination .= '/plugins';
    2034                         elseif ( 'theme' == $language_update->type )
    2035                                 $destination .= '/themes';
    2036 
    2037                         $this->update_current++;
    2038 
    2039                         $options = array(
    2040                                 'package' => $language_update->package,
    2041                                 'destination' => $destination,
    2042                                 'clear_destination' => false,
    2043                                 'abort_if_destination_exists' => false, // We expect the destination to exist.
    2044                                 'clear_working' => true,
    2045                                 'is_multi' => true,
    2046                                 'hook_extra' => array(
    2047                                         'language_update_type' => $language_update->type,
    2048                                         'language_update' => $language_update,
    2049                                 )
    2050                         );
    2051 
    2052                         $result = $this->run( $options );
    2053 
    2054                         $results[] = $this->result;
    2055 
    2056                         // Prevent credentials auth screen from displaying multiple times.
    2057                         if ( false === $result )
    2058                                 break;
    2059                 }
    2060 
    2061                 $this->skin->bulk_footer();
    2062 
    2063                 $this->skin->footer();
    2064 
    2065                 // Clean up our hooks, in case something else does an upgrade on this connection.
    2066                 remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
    2067 
    2068                 if ( $parsed_args['clear_update_cache'] ) {
    2069                         wp_clean_update_cache();
    2070                 }
    2071 
    2072                 return $results;
    2073         }
    2074 
    2075         /**
    2076          * Check the package source to make sure there are .mo and .po files.
    2077          *
    2078          * Hooked to the {@see 'upgrader_source_selection'} filter by
    2079          * {@see Language_Pack_Upgrader::bulk_upgrade()}.
    2080          *
    2081          * @since 3.7.0
    2082          * @access public
    2083          *
    2084          * @global WP_Filesystem_Base $wp_filesystem Subclass
    2085          *
    2086          * @param string|WP_Error $source
    2087          * @param string          $remote_source
    2088          */
    2089         public function check_package( $source, $remote_source ) {
    2090                 global $wp_filesystem;
    2091 
    2092                 if ( is_wp_error( $source ) )
    2093                         return $source;
    2094 
    2095                 // Check that the folder contains a valid language.
    2096                 $files = $wp_filesystem->dirlist( $remote_source );
    2097 
    2098                 // Check to see if a .po and .mo exist in the folder.
    2099                 $po = $mo = false;
    2100                 foreach ( (array) $files as $file => $filedata ) {
    2101                         if ( '.po' == substr( $file, -3 ) )
    2102                                 $po = true;
    2103                         elseif ( '.mo' == substr( $file, -3 ) )
    2104                                 $mo = true;
    2105                 }
    2106 
    2107                 if ( ! $mo || ! $po ) {
    2108                         return new WP_Error( 'incompatible_archive_pomo', $this->strings['incompatible_archive'],
    2109                                 /* translators: 1: .po 2: .mo */
    2110                                 sprintf( __( 'The language pack is missing either the %1$s or %2$s files.' ),
    2111                                         '<code>.po</code>',
    2112                                         '<code>.mo</code>'
    2113                                 )
    2114                         );
    2115                 }
    2116 
    2117                 return $source;
    2118         }
    2119 
    2120         /**
    2121          * Get the name of an item being updated.
    2122          *
    2123          * @since 3.7.0
    2124          * @access public
    2125          *
    2126          * @param object $update The data for an update.
    2127          * @return string The name of the item being updated.
    2128          */
    2129         public function get_name_for_update( $update ) {
    2130                 switch ( $update->type ) {
    2131                         case 'core':
    2132                                 return 'WordPress'; // Not translated
    2133 
    2134                         case 'theme':
    2135                                 $theme = wp_get_theme( $update->slug );
    2136                                 if ( $theme->exists() )
    2137                                         return $theme->Get( 'Name' );
    2138                                 break;
    2139                         case 'plugin':
    2140                                 $plugin_data = get_plugins( '/' . $update->slug );
    2141                                 $plugin_data = reset( $plugin_data );
    2142                                 if ( $plugin_data )
    2143                                         return $plugin_data['Name'];
    2144                                 break;
    2145                 }
    2146                 return '';
    2147         }
    2148 
    2149 }
    2150 
    2151 /**
    2152  * Core class used for updating core.
    2153  *
    2154  * It allows for WordPress to upgrade itself in combination with
    2155  * the wp-admin/includes/update-core.php file.
    2156  *
    2157  * @since 2.8.0
    2158  *
    2159  * @see WP_Upgrader
    2160  */
    2161 class Core_Upgrader extends WP_Upgrader {
    2162 
    2163         /**
    2164          * Initialize the upgrade strings.
    2165          *
    2166          * @since 2.8.0
    2167          * @access public
    2168          */
    2169         public function upgrade_strings() {
    2170                 $this->strings['up_to_date'] = __('WordPress is at the latest version.');
    2171                 $this->strings['no_package'] = __('Update package not available.');
    2172                 $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
    2173                 $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
    2174                 $this->strings['copy_failed'] = __('Could not copy files.');
    2175                 $this->strings['copy_failed_space'] = __('Could not copy files. You may have run out of disk space.' );
    2176                 $this->strings['start_rollback'] = __( 'Attempting to roll back to previous version.' );
    2177                 $this->strings['rollback_was_required'] = __( 'Due to an error during updating, WordPress has rolled back to your previous version.' );
    2178         }
    2179 
    2180         /**
    2181          * Upgrade WordPress core.
    2182          *
    2183          * @since 2.8.0
    2184          * @access public
    2185          *
    2186          * @global WP_Filesystem_Base $wp_filesystem Subclass
    2187          * @global callable           $_wp_filesystem_direct_method
    2188          *
    2189          * @param object $current Response object for whether WordPress is current.
    2190          * @param array  $args {
    2191          *        Optional. Arguments for upgrading WordPress core. Default empty array.
    2192          *
    2193          *        @type bool $pre_check_md5    Whether to check the file checksums before
    2194          *                                     attempting the upgrade. Default true.
    2195          *        @type bool $attempt_rollback Whether to attempt to rollback the chances if
    2196          *                                     there is a problem. Default false.
    2197          *        @type bool $do_rollback      Whether to perform this "upgrade" as a rollback.
    2198          *                                     Default false.
    2199          * }
    2200          * @return null|false|WP_Error False or WP_Error on failure, null on success.
    2201          */
    2202         public function upgrade( $current, $args = array() ) {
    2203                 global $wp_filesystem;
    2204 
    2205                 include( ABSPATH . WPINC . '/version.php' ); // $wp_version;
    2206 
    2207                 $start_time = time();
    2208 
    2209                 $defaults = array(
    2210                         'pre_check_md5'    => true,
    2211                         'attempt_rollback' => false,
    2212                         'do_rollback'      => false,
    2213                         'allow_relaxed_file_ownership' => false,
    2214                 );
    2215                 $parsed_args = wp_parse_args( $args, $defaults );
    2216 
    2217                 $this->init();
    2218                 $this->upgrade_strings();
    2219 
    2220                 // Is an update available?
    2221                 if ( !isset( $current->response ) || $current->response == 'latest' )
    2222                         return new WP_Error('up_to_date', $this->strings['up_to_date']);
    2223 
    2224                 $res = $this->fs_connect( array( ABSPATH, WP_CONTENT_DIR ), $parsed_args['allow_relaxed_file_ownership'] );
    2225                 if ( ! $res || is_wp_error( $res ) ) {
    2226                         return $res;
    2227                 }
    2228 
    2229                 $wp_dir = trailingslashit($wp_filesystem->abspath());
    2230 
    2231                 $partial = true;
    2232                 if ( $parsed_args['do_rollback'] )
    2233                         $partial = false;
    2234                 elseif ( $parsed_args['pre_check_md5'] && ! $this->check_files() )
    2235                         $partial = false;
    2236 
    2237                 /*
    2238                  * If partial update is returned from the API, use that, unless we're doing
    2239                  * a reinstall. If we cross the new_bundled version number, then use
    2240                  * the new_bundled zip. Don't though if the constant is set to skip bundled items.
    2241                  * If the API returns a no_content zip, go with it. Finally, default to the full zip.
    2242                  */
    2243                 if ( $parsed_args['do_rollback'] && $current->packages->rollback )
    2244                         $to_download = 'rollback';
    2245                 elseif ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version && $partial )
    2246                         $to_download = 'partial';
    2247                 elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' )
    2248                         && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) )
    2249                         $to_download = 'new_bundled';
    2250                 elseif ( $current->packages->no_content )
    2251                         $to_download = 'no_content';
    2252                 else
    2253                         $to_download = 'full';
    2254 
    2255                 $download = $this->download_package( $current->packages->$to_download );
    2256                 if ( is_wp_error($download) )
    2257                         return $download;
    2258 
    2259                 $working_dir = $this->unpack_package( $download );
    2260                 if ( is_wp_error($working_dir) )
    2261                         return $working_dir;
    2262 
    2263                 // Copy update-core.php from the new version into place.
    2264                 if ( !$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true) ) {
    2265                         $wp_filesystem->delete($working_dir, true);
    2266                         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' );
    2267                 }
    2268                 $wp_filesystem->chmod($wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE);
    2269 
    2270                 require_once( ABSPATH . 'wp-admin/includes/update-core.php' );
    2271 
    2272                 if ( ! function_exists( 'update_core' ) )
    2273                         return new WP_Error( 'copy_failed_space', $this->strings['copy_failed_space'] );
    2274 
    2275                 $result = update_core( $working_dir, $wp_dir );
    2276 
    2277                 // In the event of an issue, we may be able to roll back.
    2278                 if ( $parsed_args['attempt_rollback'] && $current->packages->rollback && ! $parsed_args['do_rollback'] ) {
    2279                         $try_rollback = false;
    2280                         if ( is_wp_error( $result ) ) {
    2281                                 $error_code = $result->get_error_code();
    2282                                 /*
    2283                                  * Not all errors are equal. These codes are critical: copy_failed__copy_dir,
    2284                                  * mkdir_failed__copy_dir, copy_failed__copy_dir_retry, and disk_full.
    2285                                  * do_rollback allows for update_core() to trigger a rollback if needed.
    2286                                  */
    2287                                 if ( false !== strpos( $error_code, 'do_rollback' ) )
    2288                                         $try_rollback = true;
    2289                                 elseif ( false !== strpos( $error_code, '__copy_dir' ) )
    2290                                         $try_rollback = true;
    2291                                 elseif ( 'disk_full' === $error_code )
    2292                                         $try_rollback = true;
    2293                         }
    2294 
    2295                         if ( $try_rollback ) {
    2296                                 /** This filter is documented in wp-admin/includes/update-core.php */
    2297                                 apply_filters( 'update_feedback', $result );
    2298 
    2299                                 /** This filter is documented in wp-admin/includes/update-core.php */
    2300                                 apply_filters( 'update_feedback', $this->strings['start_rollback'] );
    2301 
    2302                                 $rollback_result = $this->upgrade( $current, array_merge( $parsed_args, array( 'do_rollback' => true ) ) );
    2303 
    2304                                 $original_result = $result;
    2305                                 $result = new WP_Error( 'rollback_was_required', $this->strings['rollback_was_required'], (object) array( 'update' => $original_result, 'rollback' => $rollback_result ) );
    2306                         }
    2307                 }
    2308 
    2309                 /** This action is documented in wp-admin/includes/class-wp-upgrader.php */
    2310                 do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'core' ) );
    2311 
    2312                 // Clear the current updates
    2313                 delete_site_transient( 'update_core' );
    2314 
    2315                 if ( ! $parsed_args['do_rollback'] ) {
    2316                         $stats = array(
    2317                                 'update_type'      => $current->response,
    2318                                 'success'          => true,
    2319                                 'fs_method'        => $wp_filesystem->method,
    2320                                 'fs_method_forced' => defined( 'FS_METHOD' ) || has_filter( 'filesystem_method' ),
    2321                                 'fs_method_direct' => !empty( $GLOBALS['_wp_filesystem_direct_method'] ) ? $GLOBALS['_wp_filesystem_direct_method'] : '',
    2322                                 'time_taken'       => time() - $start_time,
    2323                                 'reported'         => $wp_version,
    2324                                 'attempted'        => $current->version,
    2325                         );
    2326 
    2327                         if ( is_wp_error( $result ) ) {
    2328                                 $stats['success'] = false;
    2329                                 // Did a rollback occur?
    2330                                 if ( ! empty( $try_rollback ) ) {
    2331                                         $stats['error_code'] = $original_result->get_error_code();
    2332                                         $stats['error_data'] = $original_result->get_error_data();
    2333                                         // Was the rollback successful? If not, collect its error too.
    2334                                         $stats['rollback'] = ! is_wp_error( $rollback_result );
    2335                                         if ( is_wp_error( $rollback_result ) ) {
    2336                                                 $stats['rollback_code'] = $rollback_result->get_error_code();
    2337                                                 $stats['rollback_data'] = $rollback_result->get_error_data();
    2338                                         }
    2339                                 } else {
    2340                                         $stats['error_code'] = $result->get_error_code();
    2341                                         $stats['error_data'] = $result->get_error_data();
    2342                                 }
    2343                         }
    2344 
    2345                         wp_version_check( $stats );
    2346                 }
    2347 
    2348                 return $result;
    2349         }
    2350 
    2351         /**
    2352          * Determines if this WordPress Core version should update to an offered version or not.
    2353          *
    2354          * @since 3.7.0
    2355          * @access public
    2356          *
    2357          * @static
    2358          *
    2359          * @param string $offered_ver The offered version, of the format x.y.z.
    2360          * @return bool True if we should update to the offered version, otherwise false.
    2361          */
    2362         public static function should_update_to_version( $offered_ver ) {
    2363                 include( ABSPATH . WPINC . '/version.php' ); // $wp_version; // x.y.z
    2364 
    2365                 $current_branch = implode( '.', array_slice( preg_split( '/[.-]/', $wp_version  ), 0, 2 ) ); // x.y
    2366                 $new_branch     = implode( '.', array_slice( preg_split( '/[.-]/', $offered_ver ), 0, 2 ) ); // x.y
    2367                 $current_is_development_version = (bool) strpos( $wp_version, '-' );
    2368 
    2369                 // Defaults:
    2370                 $upgrade_dev   = true;
    2371                 $upgrade_minor = true;
    2372                 $upgrade_major = false;
    2373 
    2374                 // WP_AUTO_UPDATE_CORE = true (all), 'minor', false.
    2375                 if ( defined( 'WP_AUTO_UPDATE_CORE' ) ) {
    2376                         if ( false === WP_AUTO_UPDATE_CORE ) {
    2377                                 // Defaults to turned off, unless a filter allows it
    2378                                 $upgrade_dev = $upgrade_minor = $upgrade_major = false;
    2379                         } elseif ( true === WP_AUTO_UPDATE_CORE ) {
    2380                                 // ALL updates for core
    2381                                 $upgrade_dev = $upgrade_minor = $upgrade_major = true;
    2382                         } elseif ( 'minor' === WP_AUTO_UPDATE_CORE ) {
    2383                                 // Only minor updates for core
    2384                                 $upgrade_dev = $upgrade_major = false;
    2385                                 $upgrade_minor = true;
    2386                         }
    2387                 }
    2388 
    2389                 // 1: If we're already on that version, not much point in updating?
    2390                 if ( $offered_ver == $wp_version )
    2391                         return false;
    2392 
    2393                 // 2: If we're running a newer version, that's a nope
    2394                 if ( version_compare( $wp_version, $offered_ver, '>' ) )
    2395                         return false;
    2396 
    2397                 $failure_data = get_site_option( 'auto_core_update_failed' );
    2398                 if ( $failure_data ) {
    2399                         // If this was a critical update failure, cannot update.
    2400                         if ( ! empty( $failure_data['critical'] ) )
    2401                                 return false;
    2402 
    2403                         // Don't claim we can update on update-core.php if we have a non-critical failure logged.
    2404                         if ( $wp_version == $failure_data['current'] && false !== strpos( $offered_ver, '.1.next.minor' ) )
    2405                                 return false;
    2406 
    2407                         // Cannot update if we're retrying the same A to B update that caused a non-critical failure.
    2408                         // Some non-critical failures do allow retries, like download_failed.
    2409                         // 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.
    2410                         if ( empty( $failure_data['retry'] ) && $wp_version == $failure_data['current'] && $offered_ver == $failure_data['attempted'] )
    2411                                 return false;
    2412                 }
    2413 
    2414                 // 3: 3.7-alpha-25000 -> 3.7-alpha-25678 -> 3.7-beta1 -> 3.7-beta2
    2415                 if ( $current_is_development_version ) {
    2416 
    2417                         /**
    2418                          * Filter whether to enable automatic core updates for development versions.
    2419                          *
    2420                          * @since 3.7.0
    2421                          *
    2422                          * @param bool $upgrade_dev Whether to enable automatic updates for
    2423                          *                          development versions.
    2424                          */
    2425                         if ( ! apply_filters( 'allow_dev_auto_core_updates', $upgrade_dev ) )
    2426                                 return false;
    2427                         // Else fall through to minor + major branches below.
    2428                 }
    2429 
    2430                 // 4: Minor In-branch updates (3.7.0 -> 3.7.1 -> 3.7.2 -> 3.7.4)
    2431                 if ( $current_branch == $new_branch ) {
    2432 
    2433                         /**
    2434                          * Filter whether to enable minor automatic core updates.
    2435                          *
    2436                          * @since 3.7.0
    2437                          *
    2438                          * @param bool $upgrade_minor Whether to enable minor automatic core updates.
    2439                          */
    2440                         return apply_filters( 'allow_minor_auto_core_updates', $upgrade_minor );
    2441                 }
    2442 
    2443                 // 5: Major version updates (3.7.0 -> 3.8.0 -> 3.9.1)
    2444                 if ( version_compare( $new_branch, $current_branch, '>' ) ) {
    2445 
    2446                         /**
    2447                          * Filter whether to enable major automatic core updates.
    2448                          *
    2449                          * @since 3.7.0
    2450                          *
    2451                          * @param bool $upgrade_major Whether to enable major automatic core updates.
    2452                          */
    2453                         return apply_filters( 'allow_major_auto_core_updates', $upgrade_major );
    2454                 }
    2455 
    2456                 // If we're not sure, we don't want it
    2457                 return false;
    2458         }
    2459 
    2460         /**
    2461          * Compare the disk file checksums against the expected checksums.
    2462          *
    2463          * @since 3.7.0
    2464          * @access public
    2465          *
    2466          * @global string $wp_version
    2467          * @global string $wp_local_package
    2468          *
    2469          * @return bool True if the checksums match, otherwise false.
    2470          */
    2471         public function check_files() {
    2472                 global $wp_version, $wp_local_package;
    2473 
    2474                 $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' );
    2475 
    2476                 if ( ! is_array( $checksums ) )
    2477                         return false;
    2478 
    2479                 foreach ( $checksums as $file => $checksum ) {
    2480                         // Skip files which get updated
    2481                         if ( 'wp-content' == substr( $file, 0, 10 ) )
    2482                                 continue;
    2483                         if ( ! file_exists( ABSPATH . $file ) || md5_file( ABSPATH . $file ) !== $checksum )
    2484                                 return false;
    2485                 }
    2486 
    2487                 return true;
    2488         }
    2489 }
    2490 
    2491 /**
    2492  * Core class used for handling file uploads.
    2493  *
    2494  * This class handles the upload process and passes it as if it's a local file
    2495  * to the Upgrade/Installer functions.
    2496  *
    2497  * @since 2.8.0
    2498  */
    2499 class File_Upload_Upgrader {
    2500 
    2501         /**
    2502          * The full path to the file package.
    2503          *
    2504          * @since 2.8.0
    2505          * @access public
    2506          * @var string $package
    2507          */
    2508         public $package;
    2509 
    2510         /**
    2511          * The name of the file.
    2512          *
    2513          * @since 2.8.0
    2514          * @access public
    2515          * @var string $filename
    2516          */
    2517         public $filename;
    2518 
    2519         /**
    2520          * The ID of the attachment post for this file.
    2521          *
    2522          * @since 3.3.0
    2523          * @access public
    2524          * @var int $id
    2525          */
    2526         public $id = 0;
    2527 
    2528         /**
    2529          * Construct the upgrader for a form.
    2530          *
    2531          * @since 2.8.0
    2532          * @access public
    2533          *
    2534          * @param string $form      The name of the form the file was uploaded from.
    2535          * @param string $urlholder The name of the `GET` parameter that holds the filename.
    2536          */
    2537         public function __construct( $form, $urlholder ) {
    2538 
    2539                 if ( empty($_FILES[$form]['name']) && empty($_GET[$urlholder]) )
    2540                         wp_die(__('Please select a file'));
    2541 
    2542                 //Handle a newly uploaded file, Else assume it's already been uploaded
    2543                 if ( ! empty($_FILES) ) {
    2544                         $overrides = array( 'test_form' => false, 'test_type' => false );
    2545                         $file = wp_handle_upload( $_FILES[$form], $overrides );
    2546 
    2547                         if ( isset( $file['error'] ) )
    2548                                 wp_die( $file['error'] );
    2549 
    2550                         $this->filename = $_FILES[$form]['name'];
    2551                         $this->package = $file['file'];
    2552 
    2553                         // Construct the object array
    2554                         $object = array(
    2555                                 'post_title' => $this->filename,
    2556                                 'post_content' => $file['url'],
    2557                                 'post_mime_type' => $file['type'],
    2558                                 'guid' => $file['url'],
    2559                                 'context' => 'upgrader',
    2560                                 'post_status' => 'private'
    2561                         );
    2562 
    2563                         // Save the data.
    2564                         $this->id = wp_insert_attachment( $object, $file['file'] );
    2565 
    2566                         // Schedule a cleanup for 2 hours from now in case of failed install.
    2567                         wp_schedule_single_event( time() + 2 * HOUR_IN_SECONDS, 'upgrader_scheduled_cleanup', array( $this->id ) );
    2568 
    2569                 } elseif ( is_numeric( $_GET[$urlholder] ) ) {
    2570                         // Numeric Package = previously uploaded file, see above.
    2571                         $this->id = (int) $_GET[$urlholder];
    2572                         $attachment = get_post( $this->id );
    2573                         if ( empty($attachment) )
    2574                                 wp_die(__('Please select a file'));
    2575 
    2576                         $this->filename = $attachment->post_title;
    2577                         $this->package = get_attached_file( $attachment->ID );
    2578                 } else {
    2579                         // Else, It's set to something, Back compat for plugins using the old (pre-3.3) File_Uploader handler.
    2580                         if ( ! ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) )
    2581                                 wp_die( $uploads['error'] );
    2582 
    2583                         $this->filename = $_GET[$urlholder];
    2584                         $this->package = $uploads['basedir'] . '/' . $this->filename;
    2585                 }
    2586         }
    2587 
    2588         /**
    2589          * Delete the attachment/uploaded file.
    2590          *
    2591          * @since 3.2.2
    2592          * @access public
    2593          *
    2594          * @return bool Whether the cleanup was successful.
    2595          */
    2596         public function cleanup() {
    2597                 if ( $this->id )
    2598                         wp_delete_attachment( $this->id );
    2599 
    2600                 elseif ( file_exists( $this->package ) )
    2601                         return @unlink( $this->package );
    2602 
    2603                 return true;
    2604         }
    2605 }
    2606 
    2607 /**
    2608  * Core class used for handling automatic background updates.
    2609  *
    2610  * @since 3.7.0
    2611  */
    2612 class WP_Automatic_Updater {
    2613 
    2614         /**
    2615          * Tracks update results during processing.
    2616          *
    2617          * @var array
    2618          * @access protected
    2619          */
    2620         protected $update_results = array();
    2621 
    2622         /**
    2623          * Whether the entire automatic updater is disabled.
    2624          *
    2625          * @since 3.7.0
    2626          * @access public
    2627          */
    2628         public function is_disabled() {
    2629                 // Background updates are disabled if you don't want file changes.
    2630                 if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS )
    2631                         return true;
    2632 
    2633                 if ( wp_installing() )
    2634                         return true;
    2635 
    2636                 // More fine grained control can be done through the WP_AUTO_UPDATE_CORE constant and filters.
    2637                 $disabled = defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED;
    2638 
    2639                 /**
    2640                  * Filter whether to entirely disable background updates.
    2641                  *
    2642                  * There are more fine-grained filters and controls for selective disabling.
    2643                  * This filter parallels the AUTOMATIC_UPDATER_DISABLED constant in name.
    2644                  *
    2645                  * This also disables update notification emails. That may change in the future.
    2646                  *
    2647                  * @since 3.7.0
    2648                  *
    2649                  * @param bool $disabled Whether the updater should be disabled.
    2650                  */
    2651                 return apply_filters( 'automatic_updater_disabled', $disabled );
    2652         }
    2653 
    2654         /**
    2655          * Check for version control checkouts.
    2656          *
    2657          * Checks for Subversion, Git, Mercurial, and Bazaar. It recursively looks up the
    2658          * filesystem to the top of the drive, erring on the side of detecting a VCS
    2659          * checkout somewhere.
    2660          *
    2661          * ABSPATH is always checked in addition to whatever $context is (which may be the
    2662          * wp-content directory, for example). The underlying assumption is that if you are
    2663          * using version control *anywhere*, then you should be making decisions for
    2664          * how things get updated.
    2665          *
    2666          * @since 3.7.0
    2667          * @access public
    2668          *
    2669          * @param string $context The filesystem path to check, in addition to ABSPATH.
    2670          */
    2671         public function is_vcs_checkout( $context ) {
    2672                 $context_dirs = array( untrailingslashit( $context ) );
    2673                 if ( $context !== ABSPATH )
    2674                         $context_dirs[] = untrailingslashit( ABSPATH );
    2675 
    2676                 $vcs_dirs = array( '.svn', '.git', '.hg', '.bzr' );
    2677                 $check_dirs = array();
    2678 
    2679                 foreach ( $context_dirs as $context_dir ) {
    2680                         // Walk up from $context_dir to the root.
    2681                         do {
    2682                                 $check_dirs[] = $context_dir;
    2683 
    2684                                 // Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here.
    2685                                 if ( $context_dir == dirname( $context_dir ) )
    2686                                         break;
    2687 
    2688                         // Continue one level at a time.
    2689                         } while ( $context_dir = dirname( $context_dir ) );
    2690                 }
    2691 
    2692                 $check_dirs = array_unique( $check_dirs );
    2693 
    2694                 // Search all directories we've found for evidence of version control.
    2695                 foreach ( $vcs_dirs as $vcs_dir ) {
    2696                         foreach ( $check_dirs as $check_dir ) {
    2697                                 if ( $checkout = @is_dir( rtrim( $check_dir, '\\/' ) . "/$vcs_dir" ) )
    2698                                         break 2;
    2699                         }
    2700                 }
    2701 
    2702                 /**
    2703                  * Filter whether the automatic updater should consider a filesystem
    2704                  * location to be potentially managed by a version control system.
    2705                  *
    2706                  * @since 3.7.0
    2707                  *
    2708                  * @param bool $checkout  Whether a VCS checkout was discovered at $context
    2709                  *                        or ABSPATH, or anywhere higher.
    2710                  * @param string $context The filesystem context (a path) against which
    2711                  *                        filesystem status should be checked.
    2712                  */
    2713                 return apply_filters( 'automatic_updates_is_vcs_checkout', $checkout, $context );
    2714         }
    2715 
    2716         /**
    2717          * Tests to see if we can and should update a specific item.
    2718          *
    2719          * @since 3.7.0
    2720          * @access public
    2721          *
    2722          * @global wpdb $wpdb WordPress database abstraction object.
    2723          *
    2724          * @param string $type    The type of update being checked: 'core', 'theme',
    2725          *                        'plugin', 'translation'.
    2726          * @param object $item    The update offer.
    2727          * @param string $context The filesystem context (a path) against which filesystem
    2728          *                        access and status should be checked.
    2729          */
    2730         public function should_update( $type, $item, $context ) {
    2731                 // Used to see if WP_Filesystem is set up to allow unattended updates.
    2732                 $skin = new Automatic_Upgrader_Skin;
    2733 
    2734                 if ( $this->is_disabled() )
    2735                         return false;
    2736 
    2737                 // Only relax the filesystem checks when the update doesn't include new files
    2738                 $allow_relaxed_file_ownership = false;
    2739                 if ( 'core' == $type && isset( $item->new_files ) && ! $item->new_files ) {
    2740                         $allow_relaxed_file_ownership = true;
    2741                 }
    2742 
    2743                 // If we can't do an auto core update, we may still be able to email the user.
    2744                 if ( ! $skin->request_filesystem_credentials( false, $context, $allow_relaxed_file_ownership ) || $this->is_vcs_checkout( $context ) ) {
    2745                         if ( 'core' == $type )
    2746                                 $this->send_core_update_notification_email( $item );
    2747                         return false;
    2748                 }
    2749 
    2750                 // Next up, is this an item we can update?
    2751                 if ( 'core' == $type )
    2752                         $update = Core_Upgrader::should_update_to_version( $item->current );
    2753                 else
    2754                         $update = ! empty( $item->autoupdate );
    2755 
    2756                 /**
    2757                  * Filter whether to automatically update core, a plugin, a theme, or a language.
    2758                  *
    2759                  * The dynamic portion of the hook name, `$type`, refers to the type of update
    2760                  * being checked. Can be 'core', 'theme', 'plugin', or 'translation'.
    2761                  *
    2762                  * Generally speaking, plugins, themes, and major core versions are not updated
    2763                  * by default, while translations and minor and development versions for core
    2764                  * are updated by default.
    2765                  *
    2766                  * See the {@see 'allow_dev_auto_core_updates', {@see 'allow_minor_auto_core_updates'},
    2767                  * and {@see 'allow_major_auto_core_updates'} filters for a more straightforward way to
    2768                  * adjust core updates.
    2769                  *
    2770                  * @since 3.7.0
    2771                  *
    2772                  * @param bool   $update Whether to update.
    2773                  * @param object $item   The update offer.
    2774                  */
    2775                 $update = apply_filters( 'auto_update_' . $type, $update, $item );
    2776 
    2777                 if ( ! $update ) {
    2778                         if ( 'core' == $type )
    2779                                 $this->send_core_update_notification_email( $item );
    2780                         return false;
    2781                 }
    2782 
    2783                 // If it's a core update, are we actually compatible with its requirements?
    2784                 if ( 'core' == $type ) {
    2785                         global $wpdb;
    2786 
    2787                         $php_compat = version_compare( phpversion(), $item->php_version, '>=' );
    2788                         if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) )
    2789                                 $mysql_compat = true;
    2790                         else
    2791                                 $mysql_compat = version_compare( $wpdb->db_version(), $item->mysql_version, '>=' );
    2792 
    2793                         if ( ! $php_compat || ! $mysql_compat )
    2794                                 return false;
    2795                 }
    2796 
    2797                 return true;
    2798         }
    2799 
    2800         /**
    2801          * Notifies an administrator of a core update.
    2802          *
    2803          * @since 3.7.0
    2804          * @access protected
    2805          *
    2806          * @param object $item The update offer.
    2807          */
    2808         protected function send_core_update_notification_email( $item ) {
    2809                 $notified = get_site_option( 'auto_core_update_notified' );
    2810 
    2811                 // Don't notify if we've already notified the same email address of the same version.
    2812                 if ( $notified && $notified['email'] == get_site_option( 'admin_email' ) && $notified['version'] == $item->current )
    2813                         return false;
    2814 
    2815                 // See if we need to notify users of a core update.
    2816                 $notify = ! empty( $item->notify_email );
    2817 
    2818                 /**
    2819                  * Filter whether to notify the site administrator of a new core update.
    2820                  *
    2821                  * By default, administrators are notified when the update offer received
    2822                  * from WordPress.org sets a particular flag. This allows some discretion
    2823                  * in if and when to notify.
    2824                  *
    2825                  * This filter is only evaluated once per release. If the same email address
    2826                  * was already notified of the same new version, WordPress won't repeatedly
    2827                  * email the administrator.
    2828                  *
    2829                  * This filter is also used on about.php to check if a plugin has disabled
    2830                  * these notifications.
    2831                  *
    2832                  * @since 3.7.0
    2833                  *
    2834                  * @param bool   $notify Whether the site administrator is notified.
    2835                  * @param object $item   The update offer.
    2836                  */
    2837                 if ( ! apply_filters( 'send_core_update_notification_email', $notify, $item ) )
    2838                         return false;
    2839 
    2840                 $this->send_email( 'manual', $item );
    2841                 return true;
    2842         }
    2843 
    2844         /**
    2845          * Update an item, if appropriate.
    2846          *
    2847          * @since 3.7.0
    2848          * @access public
    2849          *
    2850          * @param string $type The type of update being checked: 'core', 'theme', 'plugin', 'translation'.
    2851          * @param object $item The update offer.
    2852          *
    2853          * @return null|WP_Error
    2854          */
    2855         public function update( $type, $item ) {
    2856                 $skin = new Automatic_Upgrader_Skin;
    2857 
    2858                 switch ( $type ) {
    2859                         case 'core':
    2860                                 // The Core upgrader doesn't use the Upgrader's skin during the actual main part of the upgrade, instead, firing a filter.
    2861                                 add_filter( 'update_feedback', array( $skin, 'feedback' ) );
    2862                                 $upgrader = new Core_Upgrader( $skin );
    2863                                 $context  = ABSPATH;
    2864                                 break;
    2865                         case 'plugin':
    2866                                 $upgrader = new Plugin_Upgrader( $skin );
    2867                                 $context  = WP_PLUGIN_DIR; // We don't support custom Plugin directories, or updates for WPMU_PLUGIN_DIR
    2868                                 break;
    2869                         case 'theme':
    2870                                 $upgrader = new Theme_Upgrader( $skin );
    2871                                 $context  = get_theme_root( $item->theme );
    2872                                 break;
    2873                         case 'translation':
    2874                                 $upgrader = new Language_Pack_Upgrader( $skin );
    2875                                 $context  = WP_CONTENT_DIR; // WP_LANG_DIR;
    2876                                 break;
    2877                 }
    2878 
    2879                 // Determine whether we can and should perform this update.
    2880                 if ( ! $this->should_update( $type, $item, $context ) )
    2881                         return false;
    2882 
    2883                 /**
    2884                  * Fires immediately prior to an auto-update.
    2885                  *
    2886                  * @since 4.4.0
    2887                  *
    2888                  * @param string $type    The type of update being checked: 'core', 'theme', 'plugin', or 'translation'.
    2889                  * @param object $item    The update offer.
    2890                  * @param string $context The filesystem context (a path) against which filesystem access and status
    2891                  *                        should be checked.
    2892                  */
    2893                 do_action( 'pre_auto_update', $type, $item, $context );
    2894 
    2895                 $upgrader_item = $item;
    2896                 switch ( $type ) {
    2897                         case 'core':
    2898                                 $skin->feedback( __( 'Updating to WordPress %s' ), $item->version );
    2899                                 $item_name = sprintf( __( 'WordPress %s' ), $item->version );
    2900                                 break;
    2901                         case 'theme':
    2902                                 $upgrader_item = $item->theme;
    2903                                 $theme = wp_get_theme( $upgrader_item );
    2904                                 $item_name = $theme->Get( 'Name' );
    2905                                 $skin->feedback( __( 'Updating theme: %s' ), $item_name );
    2906                                 break;
    2907                         case 'plugin':
    2908                                 $upgrader_item = $item->plugin;
    2909                                 $plugin_data = get_plugin_data( $context . '/' . $upgrader_item );
    2910                                 $item_name = $plugin_data['Name'];
    2911                                 $skin->feedback( __( 'Updating plugin: %s' ), $item_name );
    2912                                 break;
    2913                         case 'translation':
    2914                                 $language_item_name = $upgrader->get_name_for_update( $item );
    2915                                 $item_name = sprintf( __( 'Translations for %s' ), $language_item_name );
    2916                                 $skin->feedback( sprintf( __( 'Updating translations for %1$s (%2$s)&#8230;' ), $language_item_name, $item->language ) );
    2917                                 break;
    2918                 }
    2919 
    2920                 $allow_relaxed_file_ownership = false;
    2921                 if ( 'core' == $type && isset( $item->new_files ) && ! $item->new_files ) {
    2922                         $allow_relaxed_file_ownership = true;
    2923                 }
    2924 
    2925                 // Boom, This sites about to get a whole new splash of paint!
    2926                 $upgrade_result = $upgrader->upgrade( $upgrader_item, array(
    2927                         'clear_update_cache' => false,
    2928                         // Always use partial builds if possible for core updates.
    2929                         'pre_check_md5'      => false,
    2930                         // Only available for core updates.
    2931                         'attempt_rollback'   => true,
    2932                         // Allow relaxed file ownership in some scenarios
    2933                         'allow_relaxed_file_ownership' => $allow_relaxed_file_ownership,
    2934                 ) );
    2935 
    2936                 // If the filesystem is unavailable, false is returned.
    2937                 if ( false === $upgrade_result ) {
    2938                         $upgrade_result = new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) );
    2939                 }
    2940 
    2941                 // Core doesn't output this, so let's append it so we don't get confused.
    2942                 if ( 'core' == $type ) {
    2943                         if ( is_wp_error( $upgrade_result ) ) {
    2944                                 $skin->error( __( 'Installation Failed' ), $upgrade_result );
    2945                         } else {
    2946                                 $skin->feedback( __( 'WordPress updated successfully' ) );
    2947                         }
    2948                 }
    2949 
    2950                 $this->update_results[ $type ][] = (object) array(
    2951                         'item'     => $item,
    2952                         'result'   => $upgrade_result,
    2953                         'name'     => $item_name,
    2954                         'messages' => $skin->get_upgrade_messages()
    2955                 );
    2956 
    2957                 return $upgrade_result;
    2958         }
    2959 
    2960         /**
    2961          * Kicks off the background update process, looping through all pending updates.
    2962          *
    2963          * @since 3.7.0
    2964          * @access public
    2965          *
    2966          * @global wpdb   $wpdb
    2967          * @global string $wp_version
    2968          */
    2969         public function run() {
    2970                 global $wpdb, $wp_version;
    2971 
    2972                 if ( $this->is_disabled() )
    2973                         return;
    2974 
    2975                 if ( ! is_main_network() || ! is_main_site() )
    2976                         return;
    2977 
    2978                 $lock_name = 'auto_updater.lock';
    2979 
    2980                 // Try to lock
    2981                 $lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) );
    2982 
    2983                 if ( ! $lock_result ) {
    2984                         $lock_result = get_option( $lock_name );
    2985 
    2986                         // If we couldn't create a lock, and there isn't a lock, bail
    2987                         if ( ! $lock_result )
    2988                                 return;
    2989 
    2990                         // Check to see if the lock is still valid
    2991                         if ( $lock_result > ( time() - HOUR_IN_SECONDS ) )
    2992                                 return;
    2993                 }
    2994 
    2995                 // Update the lock, as by this point we've definitely got a lock, just need to fire the actions
    2996                 update_option( $lock_name, time() );
    2997 
    2998                 // Don't automatically run these thins, as we'll handle it ourselves
    2999                 remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
    3000                 remove_action( 'upgrader_process_complete', 'wp_version_check' );
    3001                 remove_action( 'upgrader_process_complete', 'wp_update_plugins' );
    3002                 remove_action( 'upgrader_process_complete', 'wp_update_themes' );
    3003 
    3004                 // Next, Plugins
    3005                 wp_update_plugins(); // Check for Plugin updates
    3006                 $plugin_updates = get_site_transient( 'update_plugins' );
    3007                 if ( $plugin_updates && !empty( $plugin_updates->response ) ) {
    3008                         foreach ( $plugin_updates->response as $plugin ) {
    3009                                 $this->update( 'plugin', $plugin );
    3010                         }
    3011                         // Force refresh of plugin update information
    3012                         wp_clean_plugins_cache();
    3013                 }
    3014 
    3015                 // Next, those themes we all love
    3016                 wp_update_themes();  // Check for Theme updates
    3017                 $theme_updates = get_site_transient( 'update_themes' );
    3018                 if ( $theme_updates && !empty( $theme_updates->response ) ) {
    3019                         foreach ( $theme_updates->response as $theme ) {
    3020                                 $this->update( 'theme', (object) $theme );
    3021                         }
    3022                         // Force refresh of theme update information
    3023                         wp_clean_themes_cache();
    3024                 }
    3025 
    3026                 // Next, Process any core update
    3027                 wp_version_check(); // Check for Core updates
    3028                 $core_update = find_core_auto_update();
    3029 
    3030                 if ( $core_update )
    3031                         $this->update( 'core', $core_update );
    3032 
    3033                 // Clean up, and check for any pending translations
    3034                 // (Core_Upgrader checks for core updates)
    3035                 $theme_stats = array();
    3036                 if ( isset( $this->update_results['theme'] ) ) {
    3037                         foreach ( $this->update_results['theme'] as $upgrade ) {
    3038                                 $theme_stats[ $upgrade->item->theme ] = ( true === $upgrade->result );
    3039                         }
    3040                 }
    3041                 wp_update_themes( $theme_stats );  // Check for Theme updates
    3042 
    3043                 $plugin_stats = array();
    3044                 if ( isset( $this->update_results['plugin'] ) ) {
    3045                         foreach ( $this->update_results['plugin'] as $upgrade ) {
    3046                                 $plugin_stats[ $upgrade->item->plugin ] = ( true === $upgrade->result );
    3047                         }
    3048                 }
    3049                 wp_update_plugins( $plugin_stats ); // Check for Plugin updates
    3050 
    3051                 // Finally, Process any new translations
    3052                 $language_updates = wp_get_translation_updates();
    3053                 if ( $language_updates ) {
    3054                         foreach ( $language_updates as $update ) {
    3055                                 $this->update( 'translation', $update );
    3056                         }
    3057 
    3058                         // Clear existing caches
    3059                         wp_clean_update_cache();
    3060 
    3061                         wp_version_check();  // check for Core updates
    3062                         wp_update_themes();  // Check for Theme updates
    3063                         wp_update_plugins(); // Check for Plugin updates
    3064                 }
    3065 
    3066                 // Send debugging email to all development installs.
    3067                 if ( ! empty( $this->update_results ) ) {
    3068                         $development_version = false !== strpos( $wp_version, '-' );
    3069 
    3070                         /**
    3071                          * Filter whether to send a debugging email for each automatic background update.
    3072                          *
    3073                          * @since 3.7.0
    3074                          *
    3075                          * @param bool $development_version By default, emails are sent if the
    3076                          *                                  install is a development version.
    3077                          *                                  Return false to avoid the email.
    3078                          */
    3079                         if ( apply_filters( 'automatic_updates_send_debug_email', $development_version ) )
    3080                                 $this->send_debug_email();
    3081 
    3082                         if ( ! empty( $this->update_results['core'] ) )
    3083                                 $this->after_core_update( $this->update_results['core'][0] );
    3084 
    3085                         /**
    3086                          * Fires after all automatic updates have run.
    3087                          *
    3088                          * @since 3.8.0
    3089                          *
    3090                          * @param array $update_results The results of all attempted updates.
    3091                          */
    3092                         do_action( 'automatic_updates_complete', $this->update_results );
    3093                 }
    3094 
    3095                 // Clear the lock
    3096                 delete_option( $lock_name );
    3097         }
    3098 
    3099         /**
    3100          * If we tried to perform a core update, check if we should send an email,
    3101          * and if we need to avoid processing future updates.
    3102          *
    3103          * @since Unknown
    3104          * @access protected
    3105          *
    3106          * @global string $wp_version
    3107          *
    3108          * @param object|WP_Error $update_result The result of the core update. Includes the update offer and result.
    3109          */
    3110         protected function after_core_update( $update_result ) {
    3111                 global $wp_version;
    3112 
    3113                 $core_update = $update_result->item;
    3114                 $result      = $update_result->result;
    3115 
    3116                 if ( ! is_wp_error( $result ) ) {
    3117                         $this->send_email( 'success', $core_update );
    3118                         return;
    3119                 }
    3120 
    3121                 $error_code = $result->get_error_code();
    3122 
    3123                 // Any of these WP_Error codes are critical failures, as in they occurred after we started to copy core files.
    3124                 // We should not try to perform a background update again until there is a successful one-click update performed by the user.
    3125                 $critical = false;
    3126                 if ( $error_code === 'disk_full' || false !== strpos( $error_code, '__copy_dir' ) ) {
    3127                         $critical = true;
    3128                 } elseif ( $error_code === 'rollback_was_required' && is_wp_error( $result->get_error_data()->rollback ) ) {
    3129                         // A rollback is only critical if it failed too.
    3130                         $critical = true;
    3131                         $rollback_result = $result->get_error_data()->rollback;
    3132                 } elseif ( false !== strpos( $error_code, 'do_rollback' ) ) {
    3133                         $critical = true;
    3134                 }
    3135 
    3136                 if ( $critical ) {
    3137                         $critical_data = array(
    3138                                 'attempted'  => $core_update->current,
    3139                                 'current'    => $wp_version,
    3140                                 'error_code' => $error_code,
    3141                                 'error_data' => $result->get_error_data(),
    3142                                 'timestamp'  => time(),
    3143                                 'critical'   => true,
    3144                         );
    3145                         if ( isset( $rollback_result ) ) {
    3146                                 $critical_data['rollback_code'] = $rollback_result->get_error_code();
    3147                                 $critical_data['rollback_data'] = $rollback_result->get_error_data();
    3148                         }
    3149                         update_site_option( 'auto_core_update_failed', $critical_data );
    3150                         $this->send_email( 'critical', $core_update, $result );
    3151                         return;
    3152                 }
    3153 
    3154                 /*
    3155                  * Any other WP_Error code (like download_failed or files_not_writable) occurs before
    3156                  * we tried to copy over core files. Thus, the failures are early and graceful.
    3157                  *
    3158                  * We should avoid trying to perform a background update again for the same version.
    3159                  * But we can try again if another version is released.
    3160                  *
    3161                  * For certain 'transient' failures, like download_failed, we should allow retries.
    3162                  * In fact, let's schedule a special update for an hour from now. (It's possible
    3163                  * the issue could actually be on WordPress.org's side.) If that one fails, then email.
    3164                  */
    3165                 $send = true;
    3166                 $transient_failures = array( 'incompatible_archive', 'download_failed', 'insane_distro' );
    3167                 if ( in_array( $error_code, $transient_failures ) && ! get_site_option( 'auto_core_update_failed' ) ) {
    3168                         wp_schedule_single_event( time() + HOUR_IN_SECONDS, 'wp_maybe_auto_update' );
    3169                         $send = false;
    3170                 }
    3171 
    3172                 $n = get_site_option( 'auto_core_update_notified' );
    3173                 // Don't notify if we've already notified the same email address of the same version of the same notification type.
    3174                 if ( $n && 'fail' == $n['type'] && $n['email'] == get_site_option( 'admin_email' ) && $n['version'] == $core_update->current )
    3175                         $send = false;
    3176 
    3177                 update_site_option( 'auto_core_update_failed', array(
    3178                         'attempted'  => $core_update->current,
    3179                         'current'    => $wp_version,
    3180                         'error_code' => $error_code,
    3181                         'error_data' => $result->get_error_data(),
    3182                         'timestamp'  => time(),
    3183                         'retry'      => in_array( $error_code, $transient_failures ),
    3184                 ) );
    3185 
    3186                 if ( $send )
    3187                         $this->send_email( 'fail', $core_update, $result );
    3188         }
    3189 
    3190         /**
    3191          * Sends an email upon the completion or failure of a background core update.
    3192          *
    3193          * @since 3.7.0
    3194          * @access protected
    3195          *
    3196          * @global string $wp_version
    3197          *
    3198          * @param string $type        The type of email to send. Can be one of 'success', 'fail', 'manual', 'critical'.
    3199          * @param object $core_update The update offer that was attempted.
    3200          * @param mixed  $result      Optional. The result for the core update. Can be WP_Error.
    3201          */
    3202         protected function send_email( $type, $core_update, $result = null ) {
    3203                 update_site_option( 'auto_core_update_notified', array(
    3204                         'type'      => $type,
    3205                         'email'     => get_site_option( 'admin_email' ),
    3206                         'version'   => $core_update->current,
    3207                         'timestamp' => time(),
    3208                 ) );
    3209 
    3210                 $next_user_core_update = get_preferred_from_update_core();
    3211                 // If the update transient is empty, use the update we just performed
    3212                 if ( ! $next_user_core_update )
    3213                         $next_user_core_update = $core_update;
    3214                 $newer_version_available = ( 'upgrade' == $next_user_core_update->response && version_compare( $next_user_core_update->version, $core_update->version, '>' ) );
    3215 
    3216                 /**
    3217                  * Filter whether to send an email following an automatic background core update.
    3218                  *
    3219                  * @since 3.7.0
    3220                  *
    3221                  * @param bool   $send        Whether to send the email. Default true.
    3222                  * @param string $type        The type of email to send. Can be one of
    3223                  *                            'success', 'fail', 'critical'.
    3224                  * @param object $core_update The update offer that was attempted.
    3225                  * @param mixed  $result      The result for the core update. Can be WP_Error.
    3226                  */
    3227                 if ( 'manual' !== $type && ! apply_filters( 'auto_core_update_send_email', true, $type, $core_update, $result ) )
    3228                         return;
    3229 
    3230                 switch ( $type ) {
    3231                         case 'success' : // We updated.
    3232                                 /* translators: 1: Site name, 2: WordPress version number. */
    3233                                 $subject = __( '[%1$s] Your site has updated to WordPress %2$s' );
    3234                                 break;
    3235 
    3236                         case 'fail' :   // We tried to update but couldn't.
    3237                         case 'manual' : // We can't update (and made no attempt).
    3238                                 /* translators: 1: Site name, 2: WordPress version number. */
    3239                                 $subject = __( '[%1$s] WordPress %2$s is available. Please update!' );
    3240                                 break;
    3241 
    3242                         case 'critical' : // We tried to update, started to copy files, then things went wrong.
    3243                                 /* translators: 1: Site name. */
    3244                                 $subject = __( '[%1$s] URGENT: Your site may be down due to a failed update' );
    3245                                 break;
    3246 
    3247                         default :
    3248                                 return;
    3249                 }
    3250 
    3251                 // If the auto update is not to the latest version, say that the current version of WP is available instead.
    3252                 $version = 'success' === $type ? $core_update->current : $next_user_core_update->current;
    3253                 $subject = sprintf( $subject, wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), $version );
    3254 
    3255                 $body = '';
    3256 
    3257                 switch ( $type ) {
    3258                         case 'success' :
    3259                                 $body .= sprintf( __( 'Howdy! Your site at %1$s has been updated automatically to WordPress %2$s.' ), home_url(), $core_update->current );
    3260                                 $body .= "\n\n";
    3261                                 if ( ! $newer_version_available )
    3262                                         $body .= __( 'No further action is needed on your part.' ) . ' ';
    3263 
    3264                                 // Can only reference the About screen if their update was successful.
    3265                                 list( $about_version ) = explode( '-', $core_update->current, 2 );
    3266                                 $body .= sprintf( __( "For more on version %s, see the About WordPress screen:" ), $about_version );
    3267                                 $body .= "\n" . admin_url( 'about.php' );
    3268 
    3269                                 if ( $newer_version_available ) {
    3270                                         $body .= "\n\n" . sprintf( __( 'WordPress %s is also now available.' ), $next_user_core_update->current ) . ' ';
    3271                                         $body .= __( 'Updating is easy and only takes a few moments:' );
    3272                                         $body .= "\n" . network_admin_url( 'update-core.php' );
    3273                                 }
    3274 
    3275                                 break;
    3276 
    3277                         case 'fail' :
    3278                         case 'manual' :
    3279                                 $body .= sprintf( __( 'Please update your site at %1$s to WordPress %2$s.' ), home_url(), $next_user_core_update->current );
    3280 
    3281                                 $body .= "\n\n";
    3282 
    3283                                 // Don't show this message if there is a newer version available.
    3284                                 // Potential for confusion, and also not useful for them to know at this point.
    3285                                 if ( 'fail' == $type && ! $newer_version_available )
    3286                                         $body .= __( 'We tried but were unable to update your site automatically.' ) . ' ';
    3287 
    3288                                 $body .= __( 'Updating is easy and only takes a few moments:' );
    3289                                 $body .= "\n" . network_admin_url( 'update-core.php' );
    3290                                 break;
    3291 
    3292                         case 'critical' :
    3293                                 if ( $newer_version_available )
    3294                                         $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 );
    3295                                 else
    3296                                         $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 );
    3297 
    3298                                 $body .= "\n\n" . __( "This means your site may be offline or broken. Don't panic; this can be fixed." );
    3299 
    3300                                 $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:" );
    3301                                 $body .= "\n" . network_admin_url( 'update-core.php' );
    3302                                 break;
    3303                 }
    3304 
    3305                 $critical_support = 'critical' === $type && ! empty( $core_update->support_email );
    3306                 if ( $critical_support ) {
    3307                         // Support offer if available.
    3308                         $body .= "\n\n" . sprintf( __( "The WordPress team is willing to help you. Forward this email to %s and the team will work with you to make sure your site is working." ), $core_update->support_email );
    3309                 } else {
    3310                         // Add a note about the support forums.
    3311                         $body .= "\n\n" . __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' );
    3312                         $body .= "\n" . __( 'https://wordpress.org/support/' );
    3313                 }
    3314 
    3315                 // Updates are important!
    3316                 if ( $type != 'success' || $newer_version_available ) {
    3317                         $body .= "\n\n" . __( 'Keeping your site updated is important for security. It also makes the internet a safer place for you and your readers.' );
    3318                 }
    3319 
    3320                 if ( $critical_support ) {
    3321                         $body .= " " . __( "If you reach out to us, we'll also ensure you'll never have this problem again." );
    3322                 }
    3323 
    3324                 // If things are successful and we're now on the latest, mention plugins and themes if any are out of date.
    3325                 if ( $type == 'success' && ! $newer_version_available && ( get_plugin_updates() || get_theme_updates() ) ) {
    3326                         $body .= "\n\n" . __( 'You also have some plugins or themes with updates available. Update them now:' );
    3327                         $body .= "\n" . network_admin_url();
    3328                 }
    3329 
    3330                 $body .= "\n\n" . __( 'The WordPress Team' ) . "\n";
    3331 
    3332                 if ( 'critical' == $type && is_wp_error( $result ) ) {
    3333                         $body .= "\n***\n\n";
    3334                         $body .= sprintf( __( 'Your site was running version %s.' ), $GLOBALS['wp_version'] );
    3335                         $body .= ' ' . __( 'We have some data that describes the error your site encountered.' );
    3336                         $body .= ' ' . __( 'Your hosting company, support forum volunteers, or a friendly developer may be able to use this information to help you:' );
    3337 
    3338                         // If we had a rollback and we're still critical, then the rollback failed too.
    3339                         // Loop through all errors (the main WP_Error, the update result, the rollback result) for code, data, etc.
    3340                         if ( 'rollback_was_required' == $result->get_error_code() )
    3341                                 $errors = array( $result, $result->get_error_data()->update, $result->get_error_data()->rollback );
    3342                         else
    3343                                 $errors = array( $result );
    3344 
    3345                         foreach ( $errors as $error ) {
    3346                                 if ( ! is_wp_error( $error ) )
    3347                                         continue;
    3348                                 $error_code = $error->get_error_code();
    3349                                 $body .= "\n\n" . sprintf( __( "Error code: %s" ), $error_code );
    3350                                 if ( 'rollback_was_required' == $error_code )
    3351                                         continue;
    3352                                 if ( $error->get_error_message() )
    3353                                         $body .= "\n" . $error->get_error_message();
    3354                                 $error_data = $error->get_error_data();
    3355                                 if ( $error_data )
    3356                                         $body .= "\n" . implode( ', ', (array) $error_data );
    3357                         }
    3358                         $body .= "\n";
    3359                 }
    3360 
    3361                 $to  = get_site_option( 'admin_email' );
    3362                 $headers = '';
    3363 
    3364                 $email = compact( 'to', 'subject', 'body', 'headers' );
    3365 
    3366                 /**
    3367                  * Filter the email sent following an automatic background core update.
    3368                  *
    3369                  * @since 3.7.0
    3370                  *
    3371                  * @param array $email {
    3372                  *     Array of email arguments that will be passed to wp_mail().
    3373                  *
    3374                  *     @type string $to      The email recipient. An array of emails
    3375                  *                            can be returned, as handled by wp_mail().
    3376                  *     @type string $subject The email's subject.
    3377                  *     @type string $body    The email message body.
    3378                  *     @type string $headers Any email headers, defaults to no headers.
    3379                  * }
    3380                  * @param string $type        The type of email being sent. Can be one of
    3381                  *                            'success', 'fail', 'manual', 'critical'.
    3382                  * @param object $core_update The update offer that was attempted.
    3383                  * @param mixed  $result      The result for the core update. Can be WP_Error.
    3384                  */
    3385                 $email = apply_filters( 'auto_core_update_email', $email, $type, $core_update, $result );
    3386 
    3387                 wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] );
    3388         }
    3389 
    3390         /**
    3391          * Prepares and sends an email of a full log of background update results, useful for debugging and geekery.
    3392          *
    3393          * @since 3.7.0
    3394          * @access protected
    3395          */
    3396         protected function send_debug_email() {
    3397                 $update_count = 0;
    3398                 foreach ( $this->update_results as $type => $updates )
    3399                         $update_count += count( $updates );
    3400 
    3401                 $body = array();
    3402                 $failures = 0;
    3403 
    3404                 $body[] = sprintf( __( 'WordPress site: %s' ), network_home_url( '/' ) );
    3405 
    3406                 // Core
    3407                 if ( isset( $this->update_results['core'] ) ) {
    3408                         $result = $this->update_results['core'][0];
    3409                         if ( $result->result && ! is_wp_error( $result->result ) ) {
    3410                                 $body[] = sprintf( __( 'SUCCESS: WordPress was successfully updated to %s' ), $result->name );
    3411                         } else {
    3412                                 $body[] = sprintf( __( 'FAILED: WordPress failed to update to %s' ), $result->name );
    3413                                 $failures++;
    3414                         }
    3415                         $body[] = '';
    3416                 }
    3417 
    3418                 // Plugins, Themes, Translations
    3419                 foreach ( array( 'plugin', 'theme', 'translation' ) as $type ) {
    3420                         if ( ! isset( $this->update_results[ $type ] ) )
    3421                                 continue;
    3422                         $success_items = wp_list_filter( $this->update_results[ $type ], array( 'result' => true ) );
    3423                         if ( $success_items ) {
    3424                                 $messages = array(
    3425                                         'plugin'      => __( 'The following plugins were successfully updated:' ),
    3426                                         'theme'       => __( 'The following themes were successfully updated:' ),
    3427                                         'translation' => __( 'The following translations were successfully updated:' ),
    3428                                 );
    3429 
    3430                                 $body[] = $messages[ $type ];
    3431                                 foreach ( wp_list_pluck( $success_items, 'name' ) as $name ) {
    3432                                         $body[] = ' * ' . sprintf( __( 'SUCCESS: %s' ), $name );
    3433                                 }
    3434                         }
    3435                         if ( $success_items != $this->update_results[ $type ] ) {
    3436                                 // Failed updates
    3437                                 $messages = array(
    3438                                         'plugin'      => __( 'The following plugins failed to update:' ),
    3439                                         'theme'       => __( 'The following themes failed to update:' ),
    3440                                         'translation' => __( 'The following translations failed to update:' ),
    3441                                 );
    3442 
    3443                                 $body[] = $messages[ $type ];
    3444                                 foreach ( $this->update_results[ $type ] as $item ) {
    3445                                         if ( ! $item->result || is_wp_error( $item->result ) ) {
    3446                                                 $body[] = ' * ' . sprintf( __( 'FAILED: %s' ), $item->name );
    3447                                                 $failures++;
    3448                                         }
    3449                                 }
    3450                         }
    3451                         $body[] = '';
    3452                 }
    3453 
    3454                 $site_title = wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES );
    3455                 if ( $failures ) {
    3456                         $body[] = trim( __(
    3457 "BETA TESTING?
    3458 =============
    3459 
    3460 This debugging email is sent when you are using a development version of WordPress.
    3461 
    3462 If you think these failures might be due to a bug in WordPress, could you report it?
    3463  * Open a thread in the support forums: https://wordpress.org/support/forum/alphabeta
    3464  * Or, if you're comfortable writing a bug report: https://core.trac.wordpress.org/
    3465 
    3466 Thanks! -- The WordPress Team" ) );
    3467                         $body[] = '';
    3468 
    3469                         $subject = sprintf( __( '[%s] There were failures during background updates' ), $site_title );
    3470                 } else {
    3471                         $subject = sprintf( __( '[%s] Background updates have finished' ), $site_title );
    3472                 }
    3473 
    3474                 $body[] = trim( __(
    3475 'UPDATE LOG
    3476 ==========' ) );
    3477                 $body[] = '';
    3478 
    3479                 foreach ( array( 'core', 'plugin', 'theme', 'translation' ) as $type ) {
    3480                         if ( ! isset( $this->update_results[ $type ] ) )
    3481                                 continue;
    3482                         foreach ( $this->update_results[ $type ] as $update ) {
    3483                                 $body[] = $update->name;
    3484                                 $body[] = str_repeat( '-', strlen( $update->name ) );
    3485                                 foreach ( $update->messages as $message )
    3486                                         $body[] = "  " . html_entity_decode( str_replace( '&#8230;', '...', $message ) );
    3487                                 if ( is_wp_error( $update->result ) ) {
    3488                                         $results = array( 'update' => $update->result );
    3489                                         // If we rolled back, we want to know an error that occurred then too.
    3490                                         if ( 'rollback_was_required' === $update->result->get_error_code() )
    3491                                                 $results = (array) $update->result->get_error_data();
    3492                                         foreach ( $results as $result_type => $result ) {
    3493                                                 if ( ! is_wp_error( $result ) )
    3494                                                         continue;
    3495 
    3496                                                 if ( 'rollback' === $result_type ) {
    3497                                                         /* translators: 1: Error code, 2: Error message. */
    3498                                                         $body[] = '  ' . sprintf( __( 'Rollback Error: [%1$s] %2$s' ), $result->get_error_code(), $result->get_error_message() );
    3499                                                 } else {
    3500                                                         /* translators: 1: Error code, 2: Error message. */
    3501                                                         $body[] = '  ' . sprintf( __( 'Error: [%1$s] %2$s' ), $result->get_error_code(), $result->get_error_message() );
    3502                                                 }
    3503 
    3504                                                 if ( $result->get_error_data() )
    3505                                                         $body[] = '         ' . implode( ', ', (array) $result->get_error_data() );
    3506                                         }
    3507                                 }
    3508                                 $body[] = '';
    3509                         }
    3510                 }
    3511 
    3512                 $email = array(
    3513                         'to'      => get_site_option( 'admin_email' ),
    3514                         'subject' => $subject,
    3515                         'body'    => implode( "\n", $body ),
    3516                         'headers' => ''
    3517                 );
    3518 
    3519                 /**
    3520                  * Filter the debug email that can be sent following an automatic
    3521                  * background core update.
    3522                  *
    3523                  * @since 3.8.0
    3524                  *
    3525                  * @param array $email {
    3526                  *     Array of email arguments that will be passed to wp_mail().
    3527                  *
    3528                  *     @type string $to      The email recipient. An array of emails
    3529                  *                           can be returned, as handled by wp_mail().
    3530                  *     @type string $subject Email subject.
    3531                  *     @type string $body    Email message body.
    3532                  *     @type string $headers Any email headers. Default empty.
    3533                  * }
    3534                  * @param int   $failures The number of failures encountered while upgrading.
    3535                  * @param mixed $results  The results of all attempted updates.
    3536                  */
    3537                 $email = apply_filters( 'automatic_updates_debug_email', $email, $failures, $this->update_results );
    3538 
    3539                 wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] );
    3540         }
    3541 }
  • src/wp-admin/includes/translation-install.php

     
    202202        }
    203203        $translation = (object) $translation;
    204204
    205         require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
     205        require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php';
     206        require_once ABSPATH . 'wp-admin/includes/class-language-pack-upgrader.php';
     207
    206208        $skin = new Automatic_Upgrader_Skin;
    207209        $upgrader = new Language_Pack_Upgrader( $skin );
    208210        $translation->type = 'core';
     
    228230                return false;
    229231        }
    230232
    231         require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
     233        require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php';
     234        require_once ABSPATH . 'wp-admin/includes/class-language-pack-upgrader.php';
     235
    232236        $skin = new Automatic_Upgrader_Skin;
    233237        $upgrader = new Language_Pack_Upgrader( $skin );
    234238        $upgrader->init();
  • src/wp-admin/includes/update.php

     
    7474        if ( ! $updates || empty( $updates->updates ) )
    7575                return false;
    7676
    77         include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
     77        include_once( ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php' );
    7878
    7979        $auto_update = false;
    8080        $upgrader = new WP_Automatic_Updater;
  • src/wp-admin/update-core.php

     
    163163                _e('You have the latest version of WordPress.');
    164164
    165165                if ( wp_http_supports( array( 'ssl' ) ) ) {
    166                         require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
     166                        require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php';
    167167                        $upgrader = new WP_Automatic_Updater;
    168168                        $future_minor_update = (object) array(
    169169                                'current'       => $wp_version . '.1.next.minor',
     
    187187        }
    188188
    189189        if ( isset( $updates[0] ) && $updates[0]->response == 'development' ) {
    190                 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
     190                require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php';
    191191                $upgrader = new WP_Automatic_Updater;
    192192                if ( wp_http_supports( 'ssl' ) && $upgrader->should_update( 'core', $updates[0], ABSPATH ) ) {
    193193                        echo '<div class="updated inline"><p>';
     
    724724        check_admin_referer( 'upgrade-translations' );
    725725
    726726        require_once( ABSPATH . 'wp-admin/admin-header.php' );
    727         include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
     727        require_once( ABSPATH . 'wp-admin/includes/class-language-pack-upgrader.php' );
    728728
    729729        $url = 'update-core.php?action=do-translation-upgrade';
    730730        $nonce = 'upgrade-translations';
  • src/wp-admin/update.php

     
    1212/** WordPress Administration Bootstrap */
    1313require_once( dirname( __FILE__ ) . '/admin.php' );
    1414
    15 include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
    16 
    1715if ( isset($_GET['action']) ) {
    1816        $plugin = isset($_REQUEST['plugin']) ? trim($_REQUEST['plugin']) : '';
    1917        $theme = isset($_REQUEST['theme']) ? urldecode($_REQUEST['theme']) : '';
     
    3836                $nonce = 'bulk-update-plugins';
    3937
    4038                wp_enqueue_script( 'updates' );
     39
     40                require_once( ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php' );
     41                require_once( ABSPATH . 'wp-admin/includes/class-bulk-plugin-upgrader-skin.php' );
     42
    4143                iframe_header();
    4244
    4345                $upgrader = new Plugin_Upgrader( new Bulk_Plugin_Upgrader_Skin( compact( 'nonce', 'url' ) ) );
     
    5658                $submenu_file = 'plugins.php';
    5759
    5860                wp_enqueue_script( 'updates' );
    59                 require_once(ABSPATH . 'wp-admin/admin-header.php');
    6061
     62                require_once( ABSPATH . 'wp-admin/admin-header.php' );
     63                require_once( ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php' );
     64                require_once( ABSPATH . 'wp-admin/includes/class-plugin-upgrader-skin.php' );
     65
    6166                $nonce = 'upgrade-plugin_' . $plugin;
    6267                $url = 'update.php?action=upgrade-plugin&plugin=' . urlencode( $plugin );
    6368
     
    123128                $title = __('Plugin Install');
    124129                $parent_file = 'plugins.php';
    125130                $submenu_file = 'plugin-install.php';
    126                 require_once(ABSPATH . 'wp-admin/admin-header.php');
    127131
     132                require_once( ABSPATH . 'wp-admin/admin-header.php' );
     133                require_once( ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php' );
     134                require_once( ABSPATH . 'wp-admin/includes/class-plugin-installer-skin.php' );
     135
    128136                $title = sprintf( __('Installing Plugin: %s'), $api->name . ' ' . $api->version );
    129137                $nonce = 'install-plugin_' . $plugin;
    130138                $url = 'update.php?action=install-plugin&plugin=' . urlencode( $plugin );
     
    146154
    147155                check_admin_referer('plugin-upload');
    148156
     157                require_once( ABSPATH . 'wp-admin/includes/class-file-upload-upgrader.php' );
     158                require_once( ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php' );
     159                require_once( ABSPATH . 'wp-admin/includes/class-plugin-installer-skin.php' );
     160
    149161                $file_upload = new File_Upload_Upgrader('pluginzip', 'package');
    150162
    151163                $title = __('Upload Plugin');
     
    179191                $title = __('Update Theme');
    180192                $parent_file = 'themes.php';
    181193                $submenu_file = 'themes.php';
    182                 require_once(ABSPATH . 'wp-admin/admin-header.php');
    183194
     195                require_once( ABSPATH . 'wp-admin/admin-header.php' );
     196                require_once( ABSPATH . 'wp-admin/includes/class-theme-upgrader.php' );
     197                require_once( ABSPATH . 'wp-admin/includes/class-theme-upgrader-skin.php' );
     198
    184199                $nonce = 'upgrade-theme_' . $theme;
    185200                $url = 'update.php?action=upgrade-theme&theme=' . urlencode( $theme );
    186201
     
    207222                $nonce = 'bulk-update-themes';
    208223
    209224                wp_enqueue_script( 'updates' );
     225
     226                require_once( ABSPATH . 'wp-admin/includes/class-theme-upgrader.php' );
     227                require_once( ABSPATH . 'wp-admin/includes/class-bulk-theme-upgrader-skin.php' );
     228
    210229                iframe_header();
    211230
    212231                $upgrader = new Theme_Upgrader( new Bulk_Theme_Upgrader_Skin( compact( 'nonce', 'url' ) ) );
     
    231250                $title = __('Install Themes');
    232251                $parent_file = 'themes.php';
    233252                $submenu_file = 'themes.php';
    234                 require_once(ABSPATH . 'wp-admin/admin-header.php');
    235253
     254                require_once( ABSPATH . 'wp-admin/admin-header.php' );
     255                require_once( ABSPATH . 'wp-admin/includes/class-theme-upgrader.php' );
     256                require_once( ABSPATH . 'wp-admin/includes/class-theme-installer-skin.php' );
     257
    236258                $title = sprintf( __('Installing Theme: %s'), $api->name . ' ' . $api->version );
    237259                $nonce = 'install-theme_' . $theme;
    238260                $url = 'update.php?action=install-theme&theme=' . urlencode( $theme );
     
    251273
    252274                check_admin_referer('theme-upload');
    253275
     276                require_once( ABSPATH . 'wp-admin/includes/class-file-upload-upgrader.php' );
     277
    254278                $file_upload = new File_Upload_Upgrader('themezip', 'package');
    255279
    256280                wp_enqueue_script( 'customize-loader' );
     
    259283                $parent_file = 'themes.php';
    260284                $submenu_file = 'theme-install.php';
    261285
    262                 require_once(ABSPATH . 'wp-admin/admin-header.php');
     286                require_once( ABSPATH . 'wp-admin/admin-header.php' );
     287                require_once( ABSPATH . 'wp-admin/includes/class-theme-upgrader.php' );
     288                require_once( ABSPATH . 'wp-admin/includes/class-theme-installer-skin.php' );
    263289
    264290                $title = sprintf( __('Installing Theme from uploaded file: %s'), esc_html( basename( $file_upload->filename ) ) );
    265291                $nonce = 'theme-upload';