Make WordPress Core

Ticket #34676: 34676.5.patch

File 34676.5.patch, 54.9 KB (added by jipmoors, 4 years ago)

Extended patch 4: Added translator comments

  • src/js/_enqueues/admin/common.js

    diff --git src/js/_enqueues/admin/common.js src/js/_enqueues/admin/common.js
    index 2fc0c38828..84208a0268 100644
    $document.ready( function() { 
    15691569                 * notice. Make sure it gets moved just the first time.
    15701570                 */
    15711571                if ( ! $progressDiv.hasClass( 'update-details-moved' ) ) {
    1572                         $progressDiv.insertAfter( $updateNotice ).addClass( 'update-details-moved' );
     1572                        $progressDiv.appendTo( $updateNotice ).addClass( 'update-details-moved' );
    15731573                }
    15741574
    15751575                // Toggle the progress div visibility.
  • src/wp-admin/css/common.css

    diff --git src/wp-admin/css/common.css src/wp-admin/css/common.css
    index 868978d55f..e475c0aa54 100644
    code { 
    554554        margin-left: 0;
    555555}
    556556
     557.update-php .update-maintenance-start {
     558        margin-top: 30px;
     559}
     560.update-php .update-maintenance-content {
     561        border-left: 2px dashed #aaa;
     562        padding: 1px 0 20px 20px;
     563        margin: -10px 0;
     564}
     565.update-php .update-maintenance-end {
     566        margin-bottom: 30px;
     567}
     568
    557569.no-js .widefat thead .check-column input,
    558570.no-js .widefat tfoot .check-column input {
    559571        display: none;
  • src/wp-admin/includes/class-bulk-plugin-upgrader-skin.php

    diff --git src/wp-admin/includes/class-bulk-plugin-upgrader-skin.php src/wp-admin/includes/class-bulk-plugin-upgrader-skin.php
    index a568d6b107..9e8fe2f69b 100644
    class Bulk_Plugin_Upgrader_Skin extends Bulk_Upgrader_Skin { 
    2222                parent::add_strings();
    2323                /* translators: 1: name of plugin being updated, 2: number of updating plugin, 3: total number of plugins being updated */
    2424                $this->upgrader->strings['skin_before_update_header'] = __( 'Updating Plugin %1$s (%2$d/%3$d)' );
     25                $this->upgrader->strings['bulk_download']             = __( 'Downloading plugin installers.' );
    2526        }
    2627
    2728        /**
    28          * @param string $title
     29         * Outputs copy before workload output.
     30         *
     31         * @param string $title Title or string identifier to use.
     32         *
     33         * @return void
    2934         */
    3035        public function before( $title = '' ) {
    31                 parent::before( $this->plugin_info['Title'] );
     36                $title = ( $title === '' ) ? $this->plugin_info['Title'] : $title;
     37                parent::before( $title );
    3238        }
    3339
    3440        /**
    35          * @param string $title
     41         * Outputs copy after workload output.
     42         *
     43         * @param string $title Title or string identifier to use.
     44         *
     45         * @return void
    3646         */
    3747        public function after( $title = '' ) {
    38                 parent::after( $this->plugin_info['Title'] );
     48                $title = ( $title === '' ) ? $this->plugin_info['Title'] : $title;
     49                parent::after( $title );
    3950                $this->decrement_update_count( 'plugin' );
    4051        }
    4152
    4253        /**
     54         * Outputs copy after bulk actions are all done.
     55         *
     56         * @return void
    4357         */
    4458        public function bulk_footer() {
    4559                parent::bulk_footer();
  • src/wp-admin/includes/class-bulk-theme-upgrader-skin.php

    diff --git src/wp-admin/includes/class-bulk-theme-upgrader-skin.php src/wp-admin/includes/class-bulk-theme-upgrader-skin.php
    index ce426e0154..3c4d69ffe6 100644
     
    1616 * @see Bulk_Upgrader_Skin
    1717 */
    1818class Bulk_Theme_Upgrader_Skin extends Bulk_Upgrader_Skin {
    19         public $theme_info = array(); // Theme_Upgrader::bulk_upgrade() will fill this in.
     19        /**
     20         * Theme information, which will be filled by Theme_Upgrader::bulk_upgrade()
     21         * @var array
     22         */
     23        public $theme_info = array();
    2024
     25        /**
     26         * Registers strings that will be used.
     27         *
     28         * @return void
     29         */
    2130        public function add_strings() {
    2231                parent::add_strings();
    2332                /* translators: 1: name of theme being updated, 2: number of updating themes, 3: total number of themes being updated */
    2433                $this->upgrader->strings['skin_before_update_header'] = __( 'Updating Theme %1$s (%2$d/%3$d)' );
     34                $this->upgrader->strings['bulk_download']             = __( 'Downloading theme installers.' );
    2535        }
    2636
    2737        /**
    28          * @param string $title
     38         * Outputs copy before workload output.
     39         *
     40         * @param string $title Title or string identifier to use.
     41         *
     42         * @return void
    2943         */
    3044        public function before( $title = '' ) {
    31                 parent::before( $this->theme_info->display( 'Name' ) );
     45                $title = ( $title === '' ) ? $this->theme_info->display( 'Name' ) : $title;
     46                parent::before( $title );
    3247        }
    3348
    3449        /**
    35          * @param string $title
     50         * Outputs copy after workload output.
     51         *
     52         * @param string $title Title or string identifier to use.
     53         *
     54         * @return void
    3655         */
    3756        public function after( $title = '' ) {
    38                 parent::after( $this->theme_info->display( 'Name' ) );
     57                $title = ( $title === '' ) ? $this->theme_info->display( 'Name' ) : $title;
     58                parent::after( $title );
    3959                $this->decrement_update_count( 'theme' );
    4060        }
    4161
    4262        /**
     63         * Outputs copy after bulk actions are all done.
     64         *
     65         * @return void
    4366         */
    4467        public function bulk_footer() {
    4568                parent::bulk_footer();
  • new file src/wp-admin/includes/class-bulk-upgrade-element-base.php

    diff --git src/wp-admin/includes/class-bulk-upgrade-element-base.php src/wp-admin/includes/class-bulk-upgrade-element-base.php
    new file mode 100644
    index 0000000000..b950d94c71
    - +  
     1<?php
     2
     3/**
     4 * Abstract base class for Bulk Upgrade Elements
     5 *
     6 * @since x.x
     7 */
     8abstract class WP_Bulk_Upgrade_Element_Base {
     9        /**
     10         * Is this element already up-to-date
     11         *
     12         * @var bool
     13         */
     14        protected $up_to_date = false;
     15        /**
     16         * Has the package been downloaded
     17         *
     18         * @var bool
     19         */
     20        protected $downloaded = false;
     21        /**
     22         * Was the package unpacked properly
     23         *
     24         * @var bool
     25         */
     26        protected $unpacked = false;
     27        /**
     28         * Has the package been installed
     29         *
     30         * @var bool
     31         */
     32        protected $installed = false;
     33
     34        /**
     35         * The verification status of a download
     36
     37         * @var bool|WP_Error
     38         */
     39        protected $download_verification_result = false;
     40
     41        /**
     42         * Identifier for this element (source)
     43         *
     44         * @var mixed
     45         */
     46        protected $name;
     47        /**
     48         * Upgrader to use
     49         *
     50         * @var WP_Upgrader
     51         */
     52        protected $upgrader;
     53
     54        /**
     55         * Options of current element, used throughout the process
     56         *
     57         * @var array
     58         */
     59        protected $options;
     60        /**
     61         * Info about the current element, used by the upgrader
     62         *
     63         * @var mixed
     64         */
     65        protected $info;
     66        /**
     67         * Name of the download
     68         *
     69         * @var string
     70         */
     71        protected $download;
     72        /**
     73         * Working dir for the unpacked package
     74         *
     75         * @var string
     76         */
     77        protected $working_dir;
     78
     79        /**
     80         * Final result of installation (via upgrader)
     81         *
     82         * @var mixed
     83         */
     84        protected $result;
     85
     86        /**
     87         * WP_Bulk_Upgrader_Element constructor.
     88         *
     89         * @param WP_Upgrader $upgrader
     90         * @param mixed       $name
     91         *
     92         * @since x.x
     93         * @access public
     94         */
     95        public function __construct( $name, WP_Upgrader $upgrader ) {
     96                $this->name     = $name;
     97                $this->upgrader = $upgrader;
     98        }
     99
     100        /**
     101         * Retrievs the original identifier data.
     102         *
     103         * @return mixed
     104         *
     105         * @since x.x
     106         * @access public
     107         */
     108        public function get_name() {
     109                return $this->name;
     110        }
     111
     112        /**
     113         * Retrieves the cummulated result of the upgrade.
     114         *
     115         * @return bool
     116         *
     117         * @since x.x
     118         * @access public
     119         */
     120        public function get_result() {
     121                return isset( $this->result ) ? $this->result : $this->installed;
     122        }
     123
     124        /**
     125         * Retrieves the result index for the current result.
     126         *
     127         * @return bool|int
     128         *
     129         * @since x.x
     130         * @access public
     131         */
     132        public function get_result_index() {
     133                return false;
     134        }
     135
     136        /**
     137         * Determines if it is active in the system.
     138         *
     139         * @return boolean
     140         *
     141         * @since x.x
     142         * @access public
     143         */
     144        abstract public function is_active();
     145
     146        /**
     147         * Determines if it is downloaded correctly.
     148         *
     149         * @return bool
     150         *
     151         * @since x.x
     152         * @access public
     153         */
     154        public function is_downloaded() {
     155                return $this->downloaded;
     156        }
     157
     158        /**
     159         * Determines if it is unpacked succesfully.
     160         *
     161         * @return bool
     162         *
     163         * @since x.x
     164         * @access public
     165         */
     166        public function is_unpacked() {
     167                return $this->unpacked;
     168        }
     169
     170        /**
     171         * Determines if it is installed succesfully.
     172         *
     173         * @return bool
     174         *
     175         * @since x.x
     176         * @access public
     177         */
     178        public function is_installed() {
     179                return $this->installed;
     180        }
     181
     182        /**
     183         * Determines if it is already up-to-date.
     184         *
     185         * @return bool
     186         *
     187         * @since x.x
     188         * @access public
     189         */
     190        public function is_up_to_date() {
     191                return $this->up_to_date;
     192        }
     193
     194        /**
     195         * Retrieves element info.
     196         *
     197         * @return mixed
     198         *
     199         * @since x.x
     200         * @access public
     201         */
     202        public function get_info() {
     203                return $this->info;
     204        }
     205
     206        /**
     207         * Applies defaults and filter to options.
     208         *
     209         * @param array $options Options to use.
     210         * @retun void
     211         *
     212         * @since x.x
     213         * @access protected
     214         */
     215        protected function set_options( $options ) {
     216                $defaults = array(
     217                        'package'                     => '',
     218                        // Please always pass this.
     219                        'destination'                 => '',
     220                        // And this
     221                        'clear_destination'           => false,
     222                        'abort_if_destination_exists' => true,
     223                        // Abort if the Destination directory exists, Pass clear_destination as false please
     224                        'clear_working'               => true,
     225                        'is_multi'                    => false,
     226                        'hook_extra'                  => array()
     227                        // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
     228                );
     229
     230                $options = wp_parse_args( $options, $defaults );
     231
     232                /** This filter is documented in wp-admin/includes/class-wp-upgrader.php */
     233                $this->options = apply_filters( 'upgrader_package_options', $options );
     234        }
     235
     236        /**
     237         * Download this element.
     238         *
     239         * @return bool|string|WP_Error
     240         *
     241         * @since x.x
     242         * @access public
     243         */
     244        public function download() {
     245                if ( $this->is_up_to_date() ) {
     246                        return false;
     247                }
     248
     249                // Connect to the Filesystem first.
     250                $result = $this->upgrader->fs_connect( array( WP_CONTENT_DIR, $this->options['destination'] ) );
     251                // Mainly for non-connected filesystem.
     252                if ( ! $result || is_wp_error( $result ) ) {
     253                        return $result;
     254                }
     255
     256                $this->download_verification_result = true;
     257
     258                /*
     259                 * Download the package (Note, This just returns the filename
     260                 * of the file if the package is a local file)
     261                 */
     262                $result = $this->upgrader->download_package( $this->options['package'], true );
     263
     264                if ( ! is_wp_error( $result ) ) {
     265                        $this->downloaded = true;
     266                        $this->download   = $result;
     267                } else {
     268                        $filename = $result->get_error_data( 'softfail-filename' );
     269                        if ( $filename ) {
     270                                $this->download_verification_result = $result;
     271
     272                                $result = $filename;
     273
     274                                $this->downloaded = true;
     275                                $this->download   = $result;
     276                        }
     277                }
     278
     279                return $result;
     280        }
     281
     282        /**
     283         * Unpacks this element.
     284         *
     285         * @return bool|string|WP_Error
     286         *
     287         * @since x.x
     288         * @access public
     289         */
     290        public function unpack() {
     291                if ( ! $this->is_downloaded() ) {
     292                        return false;
     293                }
     294
     295                // Do not delete a "local" file
     296                $delete_package = ( $this->download !== $this->options['package'] );
     297
     298                // Unzips the file into a temporary directory.
     299                $result = $this->upgrader->unpack_package( $this->download, $delete_package );
     300                if ( ! is_wp_error( $result ) ) {
     301                        $this->unpacked    = true;
     302                        $this->working_dir = $result;
     303                }
     304
     305                return $result;
     306        }
     307
     308        /**
     309         * Installs this element.
     310         *
     311         * @return array|bool|WP_Error
     312         *
     313         * @since x.x
     314         * @access public
     315         */
     316        public function install() {
     317                if ( ! $this->is_unpacked() ) {
     318                        return false;
     319                }
     320
     321                // With the given options, this installs it to the destination directory.
     322                $result = $this->upgrader->install_package( array(
     323                        'source'                      => $this->working_dir,
     324                        'destination'                 => $this->options['destination'],
     325                        'clear_destination'           => $this->options['clear_destination'],
     326                        'abort_if_destination_exists' => $this->options['abort_if_destination_exists'],
     327                        'clear_working'               => $this->options['clear_working'],
     328                        'hook_extra'                  => $this->options['hook_extra']
     329                ) );
     330
     331                $this->result = $this->upgrader->result;
     332
     333                return $result;
     334        }
     335
     336        /**
     337         * Retrieves the verification result status.
     338         *
     339         * @return bool|WP_Error
     340         *
     341         * @since  x.x
     342         * @access public
     343         */
     344        public function get_verification_result() {
     345                return $this->download_verification_result;
     346        }
     347}
  • new file src/wp-admin/includes/class-bulk-upgrade-repository-element-base.php

    diff --git src/wp-admin/includes/class-bulk-upgrade-repository-element-base.php src/wp-admin/includes/class-bulk-upgrade-repository-element-base.php
    new file mode 100644
    index 0000000000..7fe211574c
    - +  
     1<?php
     2
     3/**
     4 * Abstract base class for Bulk Upgrade Elements that are formatted as Plugin/Theme
     5 *
     6 * @since x.x
     7 */
     8abstract class WP_Bulk_Upgrade_Repository_Element_Base extends WP_Bulk_Upgrade_Element_Base {
     9        /**
     10         * Cache for current element type information.
     11         *
     12         * @var object
     13         */
     14        protected static $current;
     15
     16        /**
     17         * Current element response information from repository.
     18         *
     19         * @var object
     20         */
     21        protected $response;
     22
     23        /**
     24         * Retrieves the result index for the current item.
     25         *
     26         * @return mixed
     27         *
     28         * @since  x.x
     29         * @access public
     30         */
     31        public function get_result_index() {
     32                return $this->name;
     33        }
     34
     35        /**
     36         * Retrieves the current item.
     37         *
     38         * @return mixed
     39         *
     40         * @since x.x
     41         * @access protected
     42         */
     43        abstract protected function get_current();
     44
     45        /**
     46         * Retrieves plugin repository response.
     47         *
     48         * @return bool|object Response from the respository as stdClass
     49         *
     50         * @since  x.x
     51         * @access protected
     52         */
     53        protected function get_response() {
     54                $current = $this->get_current();
     55
     56                if ( is_object( $current ) && is_array( $current->response ) ) {
     57                        return $this->response = isset( $current->response[ $this->name ] ) ? $current->response[ $this->name ] : false;
     58                }
     59
     60                return false;
     61        }
     62}
  • new file src/wp-admin/includes/class-bulk-upgrader-base.php

    diff --git src/wp-admin/includes/class-bulk-upgrader-base.php src/wp-admin/includes/class-bulk-upgrader-base.php
    new file mode 100644
    index 0000000000..266cec600f
    - +  
     1<?php
     2
     3/**
     4 * Abstract base class for Bulk Upgrades
     5 *
     6 * @since x.x
     7 */
     8abstract class WP_Bulk_Upgrader_Base {
     9        /**
     10         * Upgrader to use.
     11         *
     12         * @var WP_Upgrader
     13         */
     14        protected $upgrader;
     15
     16        /**
     17         * Elements to upgrade.
     18         *
     19         * @var WP_Bulk_Upgrade_Element_Base[]
     20         */
     21        protected $elements = array();
     22
     23        /**
     24         * Current element offset used to show total progression.
     25         *
     26         * @var int
     27         */
     28        protected $current_element_offset = 0;
     29
     30        /**
     31         * WP_Bulk_Upgrader_Composite constructor.
     32         *
     33         * @param WP_Upgrader $upgrader     Upgrader to report back to
     34         * @param array       $elements     List of elements to be bulked.
     35         * @param string      $elementClass Class name to wrap elements in. Extended of WP_Bulk_Upgrader_Element.
     36         *
     37         * @since  x.x
     38         * @access public
     39         */
     40        public function __construct( WP_Upgrader $upgrader, array $elements, $elementClass ) {
     41                if ( ! is_string( $elementClass ) ) {
     42                        throw new InvalidArgumentException( 'Expected element class to be string, got ' . gettype( $elementClass ) );
     43                }
     44
     45                if ( ! class_exists( $elementClass ) ) {
     46                        throw new InvalidArgumentException( sprintf( 'Element class "%s" does not exist.', $elementClass ) );
     47                }
     48
     49                $this->upgrader = $upgrader;
     50
     51                if ( array() !== $elements ) {
     52                        foreach ( $elements as $element ) {
     53                                $this->elements[] = new $elementClass( $element, $upgrader );
     54                        }
     55                }
     56
     57                $this->upgrader->update_count   = count( $this->elements );
     58                $this->upgrader->update_current = 0;
     59        }
     60
     61        /**
     62         * Runs the bulk upgrade.
     63         *
     64         * @return array List of results.
     65         *
     66         * @since x.x
     67         * @access public
     68         */
     69        public function run() {
     70                $this->upgrader->clean_upgrade_folder();
     71
     72                $this->check_up_to_date( $this->elements );
     73
     74                // Get all elements that have an upgrade.
     75                $upgradable_elements = $this->get_upgradable_elements( $this->elements );
     76
     77                $this->upgrader->update_count = count( $upgradable_elements );
     78
     79                // Download and unpack all items with upgrades.
     80                $this->prepare_upgrade( $upgradable_elements );
     81
     82                // On multisite it is hard to determine if a plugin is active on a sub-site or not - assume all are active.
     83                if ( is_multisite() ) {
     84                        $this->upgrade( $upgradable_elements, true );
     85                }
     86
     87                if ( ! is_multisite() ) {
     88                        // Get all non-active elements - these don't need maintenance mode enabled.
     89                        $inactive_elements = $this->get_inactive_elements( $upgradable_elements );
     90                        if ( $inactive_elements ) {
     91                                $this->upgrade( $inactive_elements, false );
     92                        }
     93
     94                        // Get all active elements - these need maintenance mode enabled.
     95                        $active_elements = $this->get_active_elements( $upgradable_elements );
     96                        if ( $active_elements ) {
     97                                $this->upgrade( $active_elements, true );
     98                        }
     99                }
     100
     101                $this->upgrader->update_current = false;
     102
     103                return $this->get_results();
     104        }
     105
     106        /**
     107         * Prepare download and unpack before installing.
     108         *
     109         * @param WP_Bulk_Upgrade_Element_Base[] $elements List of elements to prepare.
     110         *
     111         * @return void
     112         *
     113         * @since  x.x
     114         * @access protected
     115         */
     116        protected function prepare_upgrade( $elements ) {
     117                $skin = $this->get_skin();
     118
     119                $skin->before( 'bulk_download' );
     120                $this->download( $elements );
     121                $skin->set_result(true);
     122                $skin->after( 'bulk_download' );
     123
     124                $skin->before( 'bulk_unpack' );
     125                $this->unpack( $elements );
     126                $skin->after( 'bulk_unpack' );
     127        }
     128
     129        /**
     130         * Upgrades a list of elements.
     131         *
     132         * @param WP_Bulk_Upgrade_Element_Base[] $elements         Elements to upgrade.
     133         * @param boolean                        $maintenance_mode Enable maintenance mode.
     134         *
     135         * @return void
     136         *
     137         * @since  x.x
     138         * @access protected
     139         */
     140        protected function upgrade( $elements, $maintenance_mode ) {
     141                if ( $maintenance_mode ) {
     142                        $this->upgrader->maintenance_mode( true );
     143                }
     144
     145                $this->install( $elements );
     146
     147                if ( $maintenance_mode ) {
     148                        $this->upgrader->maintenance_mode( false );
     149                }
     150
     151                $this->current_element_offset += count( $elements );
     152        }
     153
     154        /**
     155         * Downloads all the elements.
     156         *
     157         * @param WP_Bulk_Upgrade_Element_Base[] $elements
     158         *
     159         * @return void
     160         *
     161         * @since  x.x
     162         * @access protected
     163         */
     164        protected function download( array $elements ) {
     165                /** @var $element WP_Bulk_Upgrade_Element_Base */
     166                foreach ( $elements as $element ) {
     167                        $this->set_current_element( $element, $elements );
     168
     169                        $result = $element->download();
     170                        if ( is_wp_error( $result ) ) {
     171                                $this->show_error( $result, $element );
     172                                break;
     173                        }
     174
     175                        if ( is_wp_error( $element->get_verification_result() ) ) {
     176                                $this->show_warning( $element->get_verification_result(), $element );
     177                        }
     178                }
     179        }
     180
     181        /**
     182         * Unpacks downloaded elements.
     183         *
     184         * @param WP_Bulk_Upgrade_Element_Base[] $elements Elements to unpack.
     185         *
     186         * @return void
     187         *
     188         * @since  x.x
     189         * @access protected
     190         */
     191        protected function unpack( array $elements ) {
     192                /** @var $element WP_Bulk_Upgrade_Element_Base */
     193                foreach ( $elements as $element ) {
     194                        $this->set_current_element( $element, $elements );
     195
     196                        $result = $element->unpack();
     197                        if ( is_wp_error( $result ) ) {
     198                                $this->show_error( $result, $element );
     199                        }
     200                }
     201        }
     202
     203        /**
     204         * Installs elements.
     205         *
     206         * @param WP_Bulk_Upgrade_Element_Base[] $elements Elements to install.
     207         *
     208         * @return void
     209         *
     210         * @since  x.x
     211         * @access protected
     212         */
     213        protected function install( array $elements ) {
     214                foreach ( $elements as $element ) {
     215                        $this->set_current_element( $element, $elements );
     216
     217                        $skin = $this->get_skin();
     218                        $skin->before();
     219
     220                        $result = $element->install();
     221
     222                        $skin->set_result( $result );
     223                        if ( is_wp_error( $result ) ) {
     224                                $skin->error( $result );
     225                                $skin->feedback( 'process_failed' );
     226                        } else {
     227                                // Install succeeded.
     228                                $skin->feedback( 'process_success' );
     229                        }
     230                        $skin->after();
     231
     232                        if ( is_wp_error( $result ) && $this->abort_on_error() ) {
     233                                break;
     234                        }
     235                }
     236
     237                $this->clear_current_element();
     238        }
     239
     240        /**
     241         * Retrieves the elements that have an upgrade available.
     242         *
     243         * @param WP_Bulk_Upgrade_Element_Base[] $elements List of elements to filter.
     244         *
     245         * @return array Filtered list of elements with an upgrade.
     246         *
     247         * @since  x.x
     248         * @access protected
     249         */
     250        protected function get_upgradable_elements( array $elements ) {
     251                return array_values( array_filter( $elements, array( $this, 'is_upgradable' ) ) );
     252        }
     253
     254        /**
     255         * Determines if an element has an update.
     256         *
     257         * @param WP_Bulk_Upgrade_Element_Base $element Element to check.
     258         *
     259         * @return bool True if an upgrade is available, otherwise False.
     260         *
     261         * @since  x.x
     262         * @access protected
     263         */
     264        protected function is_upgradable( WP_Bulk_Upgrade_Element_Base $element ) {
     265                return ! $element->is_up_to_date();
     266        }
     267
     268        /**
     269         * Retrieves the elements that are not active.
     270         *
     271         * @param WP_Bulk_Upgrade_Element_Base[] $elements Elements to check.
     272         *
     273         * @return array Filtered list of elements that are not active.
     274         *
     275         * @since  x.x
     276         * @access protected
     277         */
     278        protected function get_inactive_elements( array $elements ) {
     279                return array_values( array_filter( $elements, array( $this, 'is_inactive') ) );
     280        }
     281
     282        /**
     283         * Determines if an element is active.
     284         *
     285         * @param WP_Bulk_Upgrade_Element_Base $element Element to check.
     286         *
     287         * @return bool True if the element is not active, False otherwise.
     288         *
     289         * @since  x.x
     290         * @access protected
     291         */
     292        protected function is_inactive( WP_Bulk_Upgrade_Element_Base $element ) {
     293                return ! $element->is_active();
     294        }
     295
     296        /**
     297         * Retrieves a list of active elements.
     298         *
     299         * @param WP_Bulk_Upgrade_Element_Base[] $elements Elements to check.
     300         *
     301         * @return array Filtered list of elements that are active.
     302         *
     303         * @since  x.x
     304         * @access protected
     305         */
     306        protected function get_active_elements( array $elements ) {
     307                return array_values( array_filter( $elements, array( $this, 'is_active' ) ) );
     308        }
     309
     310        /**
     311         * Determines if an element is active.
     312         *
     313         * @param WP_Bulk_Upgrade_Element_Base $element Element to check.
     314         *
     315         * @return bool True if the element is active, False otherwise.
     316         *
     317         * @since  x.x
     318         * @access protected
     319         */
     320        protected function is_active( WP_Bulk_Upgrade_Element_Base $element ) {
     321                return $element->is_active();
     322        }
     323
     324        /**
     325         * Set the current element as active on the upgrader
     326         *
     327         * @param WP_Bulk_Upgrade_Element_Base $element  Element to set index of.
     328         * @param array                        $elements List to search in.
     329         *
     330         * @return int Current index.
     331         *
     332         * @since  x.x
     333         * @access protected
     334         */
     335        protected function set_current_element( $element, $elements ) {
     336                $index = array_search( $element, $elements, true );
     337
     338                if ( false === $index ) {
     339                        $this->upgrader->update_current = false;
     340                }
     341
     342                if ( false !== $index ) {
     343                        $this->upgrader->update_current = $index + 1 + $this->current_element_offset;
     344                }
     345
     346                return $this->upgrader->update_current;
     347        }
     348
     349        /**
     350         * Removes the current element.
     351         *
     352         * @return void
     353         *
     354         * @since  x.x
     355         * @access protected
     356         */
     357        protected function clear_current_element() {
     358                $this->upgrader->update_current = false;
     359        }
     360
     361        /**
     362         * Checks if any of the elements is already up to date.
     363         *
     364         * @param WP_Bulk_Upgrade_Element_Base[] $elements Elements to check.
     365         *
     366         * @return void
     367         *
     368         * @since  x.x
     369         * @access protected
     370         */
     371        protected function check_up_to_date( array $elements ) {
     372                /** @var $element WP_Bulk_Upgrade_Element_Base */
     373                foreach ( $elements as $element ) {
     374                        if ( $element->is_up_to_date() ) {
     375                                $this->set_current_element( $element, $elements );
     376
     377                                $this->handle_up_to_date( $element );
     378
     379                                $skin = $this->get_skin();
     380                                $skin->feedback( 'up_to_date' );
     381                                $skin->after();
     382                        }
     383                }
     384        }
     385
     386        /**
     387         * Handles what to do when an element is already up to date.
     388         *
     389         * @param WP_Bulk_Upgrade_Element_Base $element Relevant element.
     390         *
     391         * @return void
     392         *
     393         * @since x.x
     394         * @access protected
     395         */
     396        abstract protected function handle_up_to_date( WP_Bulk_Upgrade_Element_Base $element );
     397
     398        /**
     399         * Retrieves the results of the upgrade process.
     400         *
     401         * @return array List of results.
     402         *
     403         * @since  x.x
     404         * @access protected
     405         */
     406        protected function get_results() {
     407                $results = array();
     408
     409                /** @var $element WP_Bulk_Upgrade_Element_Base */
     410                foreach ( $this->elements as $element ) {
     411                        $index = $element->get_result_index();
     412                        if ( false === $index ) {
     413                                $results[] = $element->get_result();
     414                        } else {
     415                                $results[ $index ] = $element->get_result();
     416                        }
     417                }
     418
     419                return $results;
     420        }
     421
     422        /**
     423         * Passes an error to the skin.
     424         *
     425         * @param string                       $error
     426         * @param WP_Bulk_Upgrade_Element_Base $element
     427         *
     428         * @return void
     429         *
     430         * @since  x.x
     431         * @access protected
     432         */
     433        protected function show_error( $error, WP_Bulk_Upgrade_Element_Base $element ) {
     434                $skin = $this->get_skin();
     435                if ( $skin ) {
     436                        $skin->error( $error );
     437                        $skin->after();
     438                }
     439        }
     440
     441        /**
     442         * Passes a warning to the skin.
     443         *
     444         * @param WP_Error                     $warning Warning to show.
     445         * @param WP_Bulk_Upgrade_Element_Base $element Relevant element.
     446         *
     447         * @return void
     448         *
     449         * @since  x.x
     450         * @access protected
     451         */
     452        protected function show_warning( WP_Error $warning, WP_Bulk_Upgrade_Element_Base $element ) {
     453                $skin = $this->get_skin();
     454                if ( $skin ) {
     455                        foreach ( $warning->get_error_messages() as $message ) {
     456                                if ( $warning->get_error_data() && is_string( $warning->get_error_data() ) ) {
     457                                        $skin->feedback( $message . ' ' . esc_html( strip_tags( $warning->get_error_data() ) ) );
     458                                } else {
     459                                        $skin->feedback( $message );
     460                                }
     461                        }
     462                }
     463        }
     464
     465        /**
     466         * Determines if we should abort when encountering an error.
     467         *
     468         * @return bool
     469         *
     470         * @since  x.x
     471         * @access protected
     472         */
     473        protected function abort_on_error() {
     474                // Prevent credentials auth screen from displaying multiple times.
     475                return true;
     476        }
     477
     478        /**
     479         * Shorthand retrieval of upgrader skin.
     480         *
     481         * @return WP_Upgrader_Skin
     482         *
     483         * @since  x.x
     484         * @access protected
     485         */
     486        protected function get_skin() {
     487                return $this->upgrader->get_skin();
     488        }
     489}
  • src/wp-admin/includes/class-bulk-upgrader-skin.php

    diff --git src/wp-admin/includes/class-bulk-upgrader-skin.php src/wp-admin/includes/class-bulk-upgrader-skin.php
    index c1454e62f1..16028a5f34 100644
     
    1616 * @see WP_Upgrader_Skin
    1717 */
    1818class Bulk_Upgrader_Skin extends WP_Upgrader_Skin {
     19        /**
     20         * Are we in an install/upgrade loop.
     21         *
     22         * @var bool
     23         */
    1924        public $in_loop = false;
     25
    2026        /**
     27         * Did we encounter an error while installing/upgrading.
     28         *
    2129         * @var string|false
    2230         */
    2331        public $error = false;
    2432
    2533        /**
    26          * @param array $args
     34         * @param array $args Arguments used for this skin.
    2735         */
    2836        public function __construct( $args = array() ) {
    2937                $defaults = array(
    class Bulk_Upgrader_Skin extends WP_Upgrader_Skin { 
    3644        }
    3745
    3846        /**
     47         * Register the strings that we need.
     48         *
     49         * @return void
    3950         */
    4051        public function add_strings() {
    4152                $this->upgrader->strings['skin_upgrade_start'] = __( 'The update process is starting. This process may take a while on some hosts, so please be patient.' );
    class Bulk_Upgrader_Skin extends WP_Upgrader_Skin { 
    4657                /* translators: %s: Title of an update */
    4758                $this->upgrader->strings['skin_update_successful'] = __( '%s updated successfully.' );
    4859                $this->upgrader->strings['skin_upgrade_end']       = __( 'All updates have been completed.' );
     60                $this->upgrader->strings['bulk_download']          = __( 'Downloading items.' );
     61                $this->upgrader->strings['bulk_unpack']            = __( 'Unpacking downloaded installers.' );
    4962        }
    5063
    5164        /**
    52          * @param string $string
     65         * Outputs feedback.
     66         *
     67         * @param string $string Text to show.
     68         *
     69         * @return void
    5370         */
    5471        public function feedback( $string ) {
     72                $original_string = $string;
     73
    5574                if ( isset( $this->upgrader->strings[ $string ] ) ) {
    5675                        $string = $this->upgrader->strings[ $string ];
    5776                }
    class Bulk_Upgrader_Skin extends WP_Upgrader_Skin { 
    6584                                $string = vsprintf( $string, $args );
    6685                        }
    6786                }
     87
    6888                if ( empty( $string ) ) {
    6989                        return;
    7090                }
    71                 if ( $this->in_loop ) {
    72                         echo "$string<br />\n";
     91
     92                if ( $original_string === 'maintenance_start' ) {
     93                        printf( '<p class="update-maintenance-start"><strong>%s</strong></p><div class="update-maintenance-content">', $string );
     94                } elseif( $original_string === 'maintenance_end' ) {
     95                        printf( '</div><p class="update-maintenance-end"><strong>%s</strong></p>', $string );
    7396                } else {
    74                         echo "<p>$string</p>\n";
     97                        if ( $this->in_loop ) {
     98                                $string = "$string<br/>";
     99                        } else {
     100                                $string = "<p>$string</p>";
     101                        }
     102
     103                        echo "$string\n";
    75104                }
     105
     106                $this->flush_output();
    76107        }
    77108
    78109        /**
     110         * Outputs nothing, this will be displayed within a iframe.
     111         *
     112         * @return void
    79113         */
    80114        public function header() {
    81115                // Nothing, This will be displayed within a iframe.
    82116        }
    83117
    84118        /**
     119         * Outputs nothing, this will be displayed within a iframe.
     120         *
     121         * @return void
    85122         */
    86123        public function footer() {
    87124                // Nothing, This will be displayed within a iframe.
    88125        }
    89126
    90127        /**
    91          * @param string|WP_Error $error
     128         * Showns an error.
     129         *
     130         * @param string|WP_Error $error Error that will be shown.
    92131         */
    93132        public function error( $error ) {
    94133                if ( is_string( $error ) && isset( $this->upgrader->strings[ $error ] ) ) {
    class Bulk_Upgrader_Skin extends WP_Upgrader_Skin { 
    110149        }
    111150
    112151        /**
     152         * Shows the bulk header copy.
     153         *
     154         * @return void
    113155         */
    114156        public function bulk_header() {
    115157                $this->feedback( 'skin_upgrade_start' );
    116158        }
    117159
    118160        /**
     161         * Shows the bulk footer copy.
     162         *
     163         * @return void
    119164         */
    120165        public function bulk_footer() {
    121166                $this->feedback( 'skin_upgrade_end' );
    122167        }
    123168
    124169        /**
    125          * @param string $title
     170         * Shows an header for an element.
     171         * side-effect: Flushes the output buffer
     172         *
     173         * @param string $title Copy or string identifier to use.
     174         *
     175         * @return void
    126176         */
    127177        public function before( $title = '' ) {
    128178                $this->in_loop = true;
    129                 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 );
    130                 echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js( $this->upgrader->update_current ) . '\').css("display", "inline-block");</script>';
     179
     180                $format = $this->upgrader->strings['skin_before_update_header'];
     181
     182                $identifier = $this->upgrader->update_current;
     183                if ( isset( $this->upgrader->strings[ $title ] ) ) {
     184                        $identifier = $title;
     185                        $format = $this->upgrader->strings[ $title ];
     186                }
     187
     188                printf(
     189                        '<h2>' . $format . ' <span class="' . esc_attr( 'spinner waiting-' . $identifier ) . '"></span></h2>',
     190                        $title,
     191                        $this->upgrader->update_current,
     192                        $this->upgrader->update_count
     193                );
     194
     195                echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js( $identifier ) . '\').css("display", "inline-block");</script>';
    131196                // This progress messages div gets moved via JavaScript when clicking on "Show details.".
    132                 echo '<div class="update-messages hide-if-js" id="progress-' . esc_attr( $this->upgrader->update_current ) . '"><p>';
     197                echo '<div class="update-messages hide-if-js" id="' . esc_attr( 'progress-' . $identifier ) . '"><p>';
    133198                $this->flush_output();
    134199        }
    135200
    136201        /**
    137          * @param string $title
     202         * Shows a footer for an element.
     203         * side-effect: Flushes the output buffer
     204         *
     205         * @param string $title Copy or string identifier to use.
     206         *
     207         * @return void
    138208         */
    139209        public function after( $title = '' ) {
     210                $success_format = $this->upgrader->strings['skin_update_successful'];
     211                $error_format = $this->upgrader->strings['skin_update_failed_error'];
     212                $failed_format = $this->upgrader->strings['skin_update_failed'];
     213
     214                $identifier = $this->upgrader->update_current;
     215                if ( isset( $this->upgrader->strings[ $title ] ) ) {
     216                        $identifier = $title;
     217                        $title = $this->upgrader->strings[ $title ];
     218
     219                        $success_format = '';
     220                        $error_format = '%2$s';
     221                        $failed_format = '%s';
     222                }
     223
    140224                echo '</p></div>';
     225
    141226                if ( $this->error || ! $this->result ) {
    142227                        if ( $this->error ) {
    143                                 echo '<div class="error"><p>' . sprintf( $this->upgrader->strings['skin_update_failed_error'], $title, '<strong>' . $this->error . '</strong>' ) . '</p></div>';
     228                                echo '<div class="error"><p>' . sprintf( $error_format, $title, '<strong>' . $this->error . '</strong>' ) . '</p></div>';
    144229                        } else {
    145                                 echo '<div class="error"><p>' . sprintf( $this->upgrader->strings['skin_update_failed'], $title ) . '</p></div>';
     230                                echo '<div class="error"><p>' . sprintf( $failed_format, $title ) . '</p></div>';
    146231                        }
    147232
    148                         echo '<script type="text/javascript">jQuery(\'#progress-' . esc_js( $this->upgrader->update_current ) . '\').show();</script>';
     233                        echo '<script type="text/javascript">jQuery(\'#progress-' . esc_js( $identifier ) . '\').show();</script>';
    149234                }
     235
    150236                if ( $this->result && ! is_wp_error( $this->result ) ) {
    151237                        if ( ! $this->error ) {
    152                                 echo '<div class="updated js-update-details" data-update-details="progress-' . esc_attr( $this->upgrader->update_current ) . '">' .
    153                                         '<p>' . sprintf( $this->upgrader->strings['skin_update_successful'], $title ) .
     238                                echo '<div class="updated js-update-details" data-update-details="' . esc_attr( 'progress-' . $identifier ) . '">' .
     239                                        '<p>' . sprintf( $success_format, $title ) .
    154240                                        ' <button type="button" class="hide-if-no-js button-link js-update-details-toggle" aria-expanded="false">' . __( 'Show details.' ) . '</button>' .
    155241                                        '</p></div>';
    156242                        }
    class Bulk_Upgrader_Skin extends WP_Upgrader_Skin { 
    163249        }
    164250
    165251        /**
     252         * Resets the state of this class.
     253         *
     254         * @return void
    166255         */
    167256        public function reset() {
    168257                $this->in_loop = false;
    class Bulk_Upgrader_Skin extends WP_Upgrader_Skin { 
    170259        }
    171260
    172261        /**
     262         * Flushes the output buffer.
     263         *
     264         * @return void
    173265         */
    174266        public function flush_output() {
    175267                wp_ob_end_flush_all();
  • src/wp-admin/includes/class-core-upgrader.php

    diff --git src/wp-admin/includes/class-core-upgrader.php src/wp-admin/includes/class-core-upgrader.php
    index 977f6ec9c6..3ff7fa0c45 100644
    class Core_Upgrader extends WP_Upgrader { 
    3232                /* translators: %s: package URL */
    3333                $this->strings['downloading_package']   = sprintf( __( 'Downloading update from %s&#8230;' ), '<span class="code">%s</span>' );
    3434                $this->strings['unpack_package']        = __( 'Unpacking the update&#8230;' );
     35                /* translators: %1$d: current update counter, %2$d: total amount of updates */
     36                $this->strings['unpack_package_bulk']   = __( 'Unpacking the update&#8230; (%1$d/%2$d)' );
    3537                $this->strings['copy_failed']           = __( 'Could not copy files.' );
    3638                $this->strings['copy_failed_space']     = __( 'Could not copy files. You may have run out of disk space.' );
    3739                $this->strings['start_rollback']        = __( 'Attempting to roll back to previous version.' );
  • src/wp-admin/includes/class-language-pack-upgrader.php

    diff --git src/wp-admin/includes/class-language-pack-upgrader.php src/wp-admin/includes/class-language-pack-upgrader.php
    index 754c303c0b..a33e883142 100644
    class Language_Pack_Upgrader extends WP_Upgrader { 
    116116                /* translators: %s: package URL */
    117117                $this->strings['downloading_package'] = sprintf( __( 'Downloading translation from %s&#8230;' ), '<span class="code">%s</span>' );
    118118                $this->strings['unpack_package']      = __( 'Unpacking the update&#8230;' );
     119                /* translators: %1$d: current update counter, %2$d: total amount of updates */
     120                $this->strings['unpack_package_bulk'] = __( 'Unpacking the update&#8230; (%1$d/%2$d)' );
    119121                $this->strings['process_failed']      = __( 'Translation update failed.' );
    120122                $this->strings['process_success']     = __( 'Translation updated successfully.' );
    121123                $this->strings['remove_old']          = __( 'Removing the old version of the translation&#8230;' );
  • new file src/wp-admin/includes/class-plugin-bulk-upgrade-element.php

    diff --git src/wp-admin/includes/class-plugin-bulk-upgrade-element.php src/wp-admin/includes/class-plugin-bulk-upgrade-element.php
    new file mode 100644
    index 0000000000..a73d5b549e
    - +  
     1<?php
     2
     3/**
     4 * Plugin implementation of the Bulk Upgrade Element
     5 *
     6 * @since x.x
     7 */
     8class WP_Plugin_Bulk_Upgrade_Element extends WP_Bulk_Upgrade_Repository_Element_Base {
     9        /**
     10         * WP_Bulk_Upgrader_Plugin_Element constructor.
     11         *
     12         * @param string          $plugin   Current plugin
     13         * @param Plugin_Upgrader $upgrader Upgrader to use.
     14         *
     15         * @since  x.x
     16         * @access public
     17         */
     18        public function __construct( $plugin, Plugin_Upgrader $upgrader ) {
     19                parent::__construct( $plugin, $upgrader );
     20
     21                $this->info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true );
     22
     23                $response = $this->get_response();
     24                if ( false === $response ) {
     25                        $this->up_to_date = true;
     26
     27                        return;
     28                }
     29
     30                $options = array(
     31                        'package'           => $response->package,
     32                        'destination'       => WP_PLUGIN_DIR,
     33                        'clear_destination' => true,
     34                        'clear_working'     => true,
     35                        'is_multi'          => true,
     36                        'hook_extra'        => array(
     37                                'plugin' => $plugin
     38                        )
     39                );
     40
     41                $this->set_options( $options );
     42        }
     43
     44        /**
     45         * Determines if this plugin is activated.
     46         *
     47         * @return bool
     48         *
     49         * @since  x.x
     50         * @access public
     51         */
     52        public function is_active() {
     53                return is_plugin_active( $this->name );
     54        }
     55
     56        /**
     57         * Retrieves information for the plugin from the `update_plugins` transient.
     58         *
     59         * @return mixed
     60         *
     61         * @since x.x
     62         * @access protected
     63         */
     64        protected function get_current() {
     65                if ( ! isset( self::$current ) ) {
     66                        self::$current = get_site_transient( 'update_plugins' );
     67                }
     68
     69                return self::$current;
     70        }
     71}
  • new file src/wp-admin/includes/class-plugin-bulk-upgrader.php

    diff --git src/wp-admin/includes/class-plugin-bulk-upgrader.php src/wp-admin/includes/class-plugin-bulk-upgrader.php
    new file mode 100644
    index 0000000000..c49acf0650
    - +  
     1<?php
     2
     3/**
     4 * Plugin Bulk Upgrader implementation
     5 *
     6 * @since x.x
     7 */
     8class WP_Plugin_Bulk_Upgrader extends WP_Bulk_Upgrader_Base {
     9        /**
     10         * WP_Plugin_Bulk_Upgrader constructor.
     11         *
     12         * @param Plugin_Upgrader $upgrader Upgrader to use.
     13         * @param array           $elements Elements to use.
     14         *
     15         * @since x.x
     16         * @access public
     17         */
     18        public function __construct( Plugin_Upgrader $upgrader, array $elements = array() ) {
     19                parent::__construct( $upgrader, $elements, 'WP_Plugin_Bulk_Upgrade_Element' );
     20        }
     21
     22        /**
     23         * Communicates result to skin.
     24         *
     25         * @param WP_Bulk_Upgrade_Element_Base $element Relevant element.
     26         *
     27         * @return void
     28         *
     29         * @since  x.x
     30         * @access public
     31         */
     32        public function handle_up_to_date( WP_Bulk_Upgrade_Element_Base $element ) {
     33                $skin = $this->get_skin();
     34                if ( $skin instanceof WP_Upgrader_Skin ) {
     35                        $skin->set_result( 'up_to_date' );
     36                }
     37        }
     38
     39        /**
     40         * Communicate plugin info to skin
     41         *
     42         * @param WP_Bulk_Upgrade_Element_Base $element  Element to set as current.
     43         * @param array                        $elements List to search in.
     44         *
     45         * @return void
     46         *
     47         * @since  x.x
     48         * @access protected
     49         */
     50        protected function set_current_element( $element, $elements ) {
     51                parent::set_current_element( $element, $elements );
     52
     53                if ( ! $this->upgrader->update_current ) {
     54                        return;
     55                }
     56
     57                $skin = $this->get_skin();
     58                $skin->plugin_info = $element->get_info();
     59        }
     60}
  • src/wp-admin/includes/class-plugin-upgrader.php

    diff --git src/wp-admin/includes/class-plugin-upgrader.php src/wp-admin/includes/class-plugin-upgrader.php
    index c80c9c4c97..b6b848e37d 100644
    class Plugin_Upgrader extends WP_Upgrader { 
    4949                /* translators: %s: package URL */
    5050                $this->strings['downloading_package']  = sprintf( __( 'Downloading update from %s&#8230;' ), '<span class="code">%s</span>' );
    5151                $this->strings['unpack_package']       = __( 'Unpacking the update&#8230;' );
     52                $this->strings['unpack_package_bulk']  = __( 'Unpacking the update&#8230; (%1$s/%2$s)' );
    5253                $this->strings['remove_old']           = __( 'Removing the old version of the plugin&#8230;' );
    5354                $this->strings['remove_old_failed']    = __( 'Could not remove the old plugin.' );
    5455                $this->strings['process_failed']       = __( 'Plugin update failed.' );
    class Plugin_Upgrader extends WP_Upgrader { 
    6667                /* translators: %s: package URL */
    6768                $this->strings['downloading_package'] = sprintf( __( 'Downloading installation package from %s&#8230;' ), '<span class="code">%s</span>' );
    6869                $this->strings['unpack_package']      = __( 'Unpacking the package&#8230;' );
     70                /* translators: %1$d: current update counter, %2$d: total amount of updates */
     71                $this->strings['unpack_package_bulk'] = __( 'Unpacking the update&#8230; (%1$d/%2$d)' );
    6972                $this->strings['installing_package']  = __( 'Installing the plugin&#8230;' );
    7073                $this->strings['no_files']            = __( 'The plugin contains no files.' );
    7174                $this->strings['process_failed']      = __( 'Plugin installation failed.' );
    class Plugin_Upgrader extends WP_Upgrader { 
    228231                $this->bulk = true;
    229232                $this->upgrade_strings();
    230233
    231                 $current = get_site_transient( 'update_plugins' );
    232 
    233234                add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ), 10, 4 );
    234235
    235236                $this->skin->header();
    class Plugin_Upgrader extends WP_Upgrader { 
    243244
    244245                $this->skin->bulk_header();
    245246
    246                 /*
    247                  * Only start maintenance mode if:
    248                  * - running Multisite and there are one or more plugins specified, OR
    249                  * - a plugin with an update available is currently active.
    250                  * @TODO: For multisite, maintenance mode should only kick in for individual sites if at all possible.
    251                  */
    252                 $maintenance = ( is_multisite() && ! empty( $plugins ) );
    253                 foreach ( $plugins as $plugin ) {
    254                         $maintenance = $maintenance || ( is_plugin_active( $plugin ) && isset( $current->response[ $plugin ] ) );
    255                 }
    256                 if ( $maintenance ) {
    257                         $this->maintenance_mode( true );
    258                 }
    259 
    260                 $results = array();
    261 
    262                 $this->update_count   = count( $plugins );
    263                 $this->update_current = 0;
    264                 foreach ( $plugins as $plugin ) {
    265                         $this->update_current++;
    266                         $this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true );
    267 
    268                         if ( ! isset( $current->response[ $plugin ] ) ) {
    269                                 $this->skin->set_result( 'up_to_date' );
    270                                 $this->skin->before();
    271                                 $this->skin->feedback( 'up_to_date' );
    272                                 $this->skin->after();
    273                                 $results[ $plugin ] = true;
    274                                 continue;
    275                         }
    276 
    277                         // Get the URL to the zip file.
    278                         $r = $current->response[ $plugin ];
    279 
    280                         $this->skin->plugin_active = is_plugin_active( $plugin );
    281 
    282                         $result = $this->run(
    283                                 array(
    284                                         'package'           => $r->package,
    285                                         'destination'       => WP_PLUGIN_DIR,
    286                                         'clear_destination' => true,
    287                                         'clear_working'     => true,
    288                                         'is_multi'          => true,
    289                                         'hook_extra'        => array(
    290                                                 'plugin' => $plugin,
    291                                         ),
    292                                 )
    293                         );
    294 
    295                         $results[ $plugin ] = $this->result;
    296 
    297                         // Prevent credentials auth screen from displaying multiple times
    298                         if ( false === $result ) {
    299                                 break;
    300                         }
    301                 } //end foreach $plugins
    302 
    303                 $this->maintenance_mode( false );
     247                $plugin_bulk_upgrader = new WP_Plugin_Bulk_Upgrader( $this, $plugins );
     248                $results = $plugin_bulk_upgrader->run();
    304249
    305250                // Force refresh of plugin update information.
    306251                wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
  • new file src/wp-admin/includes/class-theme-bulk-upgrade-element.php

    diff --git src/wp-admin/includes/class-theme-bulk-upgrade-element.php src/wp-admin/includes/class-theme-bulk-upgrade-element.php
    new file mode 100644
    index 0000000000..05cab0e440
    - +  
     1<?php
     2
     3/**
     4 * Theme implementation of the Bulk Upgrade Element
     5 *
     6 * @since x.x
     7 */
     8class WP_Theme_Bulk_Upgrade_Element extends WP_Bulk_Upgrade_Repository_Element_Base {
     9        /**
     10         * WP_Bulk_Upgrader_Theme_Element constructor.
     11         *
     12         * @param string         $theme    Theme to use.
     13         * @param Theme_Upgrader $upgrader Upgrader to use.
     14         *
     15         * @since x.x
     16         * @access public
     17         */
     18        public function __construct( $theme, Theme_Upgrader $upgrader ) {
     19                parent::__construct( $theme, $upgrader );
     20
     21                $this->info = $upgrader->theme_info( $theme );
     22
     23                $response = $this->get_response();
     24                if ( false === $response ) {
     25                        $this->up_to_date = true;
     26
     27                        return;
     28                }
     29
     30                $options = array(
     31                        'package'           => $this->response['package'],
     32                        'destination'       => get_theme_root( $theme ),
     33                        'clear_destination' => true,
     34                        'clear_working'     => true,
     35                        'is_multi'          => true,
     36                        'hook_extra'        => array(
     37                                'theme' => $theme
     38                        )
     39                );
     40
     41                $this->set_options( $options );
     42        }
     43
     44        /**
     45         * Determines if this theme is active.
     46         *
     47         * @return bool
     48         *
     49         * @since x.x
     50         * @access public
     51         */
     52        public function is_active() {
     53                return $this->name === get_stylesheet() || $this->name === get_template();
     54        }
     55
     56        /**
     57         * Retrieves information about the theme from the `update_themes` transient.
     58         *
     59         * @return mixed
     60         *
     61         * @since x.x
     62         * @access protected
     63         */
     64        protected function get_current() {
     65                if ( ! isset( self::$current ) ) {
     66                        self::$current = get_site_transient( 'update_themes' );
     67                }
     68
     69                return self::$current;
     70        }
     71}
  • new file src/wp-admin/includes/class-theme-bulk-upgrader.php

    diff --git src/wp-admin/includes/class-theme-bulk-upgrader.php src/wp-admin/includes/class-theme-bulk-upgrader.php
    new file mode 100644
    index 0000000000..de4c95327d
    - +  
     1<?php
     2
     3/**
     4 * Theme Bulk Upgrader implementation
     5 *
     6 * @since x.x
     7 */
     8class WP_Theme_Bulk_Upgrader extends WP_Bulk_Upgrader_Base {
     9        /**
     10         * WP_Theme_Bulk_Upgrader constructor.
     11         *
     12         * @param Theme_Upgrader                 $upgrader Upgrader to use.
     13         * @param WP_Bulk_Upgrade_Element_Base[] $elements Elements to use.
     14         *
     15         * @since  x.x
     16         * @access public
     17         */
     18        public function __construct( Theme_Upgrader $upgrader, array $elements = array() ) {
     19                parent::__construct( $upgrader, $elements, 'WP_Theme_Bulk_Upgrade_Element' );
     20        }
     21
     22        /**
     23         * Handles what to do for an up-to-date theme.
     24         *
     25         * @param WP_Bulk_Upgrade_Element_Base $element Element to use.
     26         *
     27         * @return void
     28         *
     29         * @since  x.x
     30         * @access public
     31         */
     32        public function handle_up_to_date( WP_Bulk_Upgrade_Element_Base $element ) {
     33                $skin = $this->get_skin();
     34                if ( $skin instanceof WP_Upgrader_Skin ) {
     35                        $skin->set_result( true );
     36                }
     37        }
     38
     39        /**
     40         * Sets the current element on the skin.
     41         *
     42         * @param WP_Bulk_Upgrade_Element_Base $element  Element to set as current.
     43         * @param array                        $elements List to search in.
     44         *
     45         * @return void
     46         *
     47         * @since  x.x
     48         * @access protected
     49         */
     50        protected function set_current_element( $element, $elements ) {
     51                parent::set_current_element( $element, $elements );
     52
     53                if ( ! $this->upgrader->update_current ) {
     54                        return;
     55                }
     56
     57                $skin = $this->get_skin();
     58                if ( $skin instanceof Bulk_Theme_Upgrader_Skin ) {
     59                        $skin->theme_info = $element->get_info();
     60                }
     61        }
     62}
  • src/wp-admin/includes/class-theme-upgrader.php

    diff --git src/wp-admin/includes/class-theme-upgrader.php src/wp-admin/includes/class-theme-upgrader.php
    index 7b521063f8..6f2301d8d1 100644
    class Theme_Upgrader extends WP_Upgrader { 
    4848                /* translators: %s: package URL */
    4949                $this->strings['downloading_package'] = sprintf( __( 'Downloading update from %s&#8230;' ), '<span class="code">%s</span>' );
    5050                $this->strings['unpack_package']      = __( 'Unpacking the update&#8230;' );
     51                /* translators: %1$d: current update counter, %2$d: total amount of updates */
     52                $this->strings['unpack_package_bulk'] = __( 'Unpacking the update&#8230; (%1$d/%2$d)' );
    5153                $this->strings['remove_old']          = __( 'Removing the old version of the theme&#8230;' );
    5254                $this->strings['remove_old_failed']   = __( 'Could not remove the old theme.' );
    5355                $this->strings['process_failed']      = __( 'Theme update failed.' );
    class Theme_Upgrader extends WP_Upgrader { 
    6466                /* translators: %s: package URL */
    6567                $this->strings['downloading_package'] = sprintf( __( 'Downloading installation package from %s&#8230;' ), '<span class="code">%s</span>' );
    6668                $this->strings['unpack_package']      = __( 'Unpacking the package&#8230;' );
     69                /* translators: %1$d: current update counter, %2$d: total amount of updates */
     70                $this->strings['unpack_package_bulk'] = __( 'Unpacking the update&#8230; (%1$d/%2$d)' );
    6771                $this->strings['installing_package']  = __( 'Installing the theme&#8230;' );
    6872                $this->strings['no_files']            = __( 'The theme contains no files.' );
    6973                $this->strings['process_failed']      = __( 'Theme installation failed.' );
    class Theme_Upgrader extends WP_Upgrader { 
    358362
    359363                $this->skin->bulk_header();
    360364
    361                 // Only start maintenance mode if:
    362                 // - running Multisite and there are one or more themes specified, OR
    363                 // - a theme with an update available is currently in use.
    364                 // @TODO: For multisite, maintenance mode should only kick in for individual sites if at all possible.
    365                 $maintenance = ( is_multisite() && ! empty( $themes ) );
    366                 foreach ( $themes as $theme ) {
    367                         $maintenance = $maintenance || $theme == get_stylesheet() || $theme == get_template();
    368                 }
    369                 if ( $maintenance ) {
    370                         $this->maintenance_mode( true );
    371                 }
    372 
    373                 $results = array();
    374 
    375                 $this->update_count   = count( $themes );
    376                 $this->update_current = 0;
    377                 foreach ( $themes as $theme ) {
    378                         $this->update_current++;
    379 
    380                         $this->skin->theme_info = $this->theme_info( $theme );
    381 
    382                         if ( ! isset( $current->response[ $theme ] ) ) {
    383                                 $this->skin->set_result( true );
    384                                 $this->skin->before();
    385                                 $this->skin->feedback( 'up_to_date' );
    386                                 $this->skin->after();
    387                                 $results[ $theme ] = true;
    388                                 continue;
    389                         }
    390 
    391                         // Get the URL to the zip file
    392                         $r = $current->response[ $theme ];
    393 
    394                         $result = $this->run(
    395                                 array(
    396                                         'package'           => $r['package'],
    397                                         'destination'       => get_theme_root( $theme ),
    398                                         'clear_destination' => true,
    399                                         'clear_working'     => true,
    400                                         'is_multi'          => true,
    401                                         'hook_extra'        => array(
    402                                                 'theme' => $theme,
    403                                         ),
    404                                 )
    405                         );
    406 
    407                         $results[ $theme ] = $this->result;
    408 
    409                         // Prevent credentials auth screen from displaying multiple times
    410                         if ( false === $result ) {
    411                                 break;
    412                         }
    413                 } //end foreach $plugins
    414 
    415                 $this->maintenance_mode( false );
     365                $theme_bulk_upgrader = new WP_Theme_Bulk_Upgrader( $this, $themes );
     366                $results = $theme_bulk_upgrader->run();
    416367
    417368                // Refresh the Theme Update information
    418369                wp_clean_themes_cache( $parsed_args['clear_update_cache'] );
  • new file src/wp-admin/includes/class-wp-upgrader-bulk.php

    diff --git src/wp-admin/includes/class-wp-upgrader-bulk.php src/wp-admin/includes/class-wp-upgrader-bulk.php
    new file mode 100644
    index 0000000000..6e1c43828c
    - +  
     1<?php
     2/**
     3 * The Bulk handlers for the WordPress Upgrader
     4 *
     5 * @package    WordPress
     6 * @subpackage Upgrader
     7 * @since      x.x
     8 */
     9
     10require_once 'class-bulk-upgrade-element-base.php';
     11require_once 'class-bulk-upgrade-repository-element-base.php';
     12
     13require_once 'class-bulk-upgrader-base.php';
     14
     15require_once 'class-plugin-bulk-upgrade-element.php';
     16require_once 'class-plugin-bulk-upgrader.php';
     17
     18require_once 'class-theme-bulk-upgrade-element.php';
     19require_once 'class-theme-bulk-upgrader.php';
  • src/wp-admin/includes/class-wp-upgrader-skin.php

    diff --git src/wp-admin/includes/class-wp-upgrader-skin.php src/wp-admin/includes/class-wp-upgrader-skin.php
    index ddcfd19f18..5b110fb0ff 100644
     
    1515 */
    1616class WP_Upgrader_Skin {
    1717
     18        /**
     19         * Holds the Upgrader to use.
     20         *
     21         * @var WP_Upgrader
     22         */
    1823        public $upgrader;
    1924        public $done_header = false;
    2025        public $done_footer = false;
    class WP_Upgrader_Skin { 
    4247        }
    4348
    4449        /**
    45          * @param WP_Upgrader $upgrader
     50         * Sets the upgrader to use internally.
     51         *
     52         * @param WP_Upgrader $upgrader Upgrader to use.
    4653         */
    4754        public function set_upgrader( &$upgrader ) {
    4855                if ( is_object( $upgrader ) ) {
  • src/wp-admin/includes/class-wp-upgrader.php

    diff --git src/wp-admin/includes/class-wp-upgrader.php src/wp-admin/includes/class-wp-upgrader.php
    index b8258d4bc2..1737f46849 100644
     
    99 * @since 2.8.0
    1010 */
    1111
     12/** WP_Upgrader_Bulk class */
     13require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader-bulk.php';
     14
    1215/** WP_Upgrader_Skin class */
    1316require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader-skin.php';
    1417
    class WP_Upgrader { 
    6467         * @since 2.8.0
    6568         * @var Automatic_Upgrader_Skin|WP_Upgrader_Skin $skin
    6669         */
    67         public $skin = null;
     70        public $skin;
    6871
    6972        /**
    7073         * The result of the installation.
    class WP_Upgrader { 
    120123         *                               instance.
    121124         */
    122125        public function __construct( $skin = null ) {
    123                 if ( null == $skin ) {
     126                if ( $skin === null ) {
    124127                        $this->skin = new WP_Upgrader_Skin();
    125128                } else {
    126129                        $this->skin = $skin;
    class WP_Upgrader { 
    300303        public function unpack_package( $package, $delete_package = true ) {
    301304                global $wp_filesystem;
    302305
    303                 $this->skin->feedback( 'unpack_package' );
     306                if ( $this->update_count > 1 ) {
     307                        $this->skin->feedback( 'unpack_package_bulk', $this->update_current, $this->update_count );
     308                } else {
     309                        $this->skin->feedback( 'unpack_package' );
     310                }
    304311
    305312                $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
    306313
    307                 //Clean up contents of upgrade directory beforehand.
    308                 $upgrade_files = $wp_filesystem->dirlist( $upgrade_folder );
    309                 if ( ! empty( $upgrade_files ) ) {
    310                         foreach ( $upgrade_files as $file ) {
    311                                 $wp_filesystem->delete( $upgrade_folder . $file['name'], true );
    312                         }
    313                 }
    314 
    315314                // We need a working directory - Strip off any .tmp or .zip suffixes
    316315                $working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
    317316
    class WP_Upgrader { 
    702701                 */
    703702                $options = apply_filters( 'upgrader_package_options', $options );
    704703
    705                 if ( ! $options['is_multi'] ) { // call $this->header separately if running multiple times
    706                         $this->skin->header();
    707                 }
     704                $this->skin->header();
    708705
    709706                // Connect to the Filesystem first.
    710707                $res = $this->fs_connect( array( WP_CONTENT_DIR, $options['destination'] ) );
    class WP_Upgrader { 
    727724                        return $res;
    728725                }
    729726
     727                $this->clean_upgrade_folder();
     728
    730729                /*
    731730                 * Download the package (Note, This just returns the filename
    732731                 * of the file if the package is a local file)
    class WP_Upgrader { 
    925924                return delete_option( $lock_name . '.lock' );
    926925        }
    927926
     927        /**
     928         * Clears optional remnants of previous upgrades
     929         *
     930         * @since x.x
     931         * @access public
     932         *
     933         * @global WP_Filesystem_Base $wp_filesystem Subclass
     934         */
     935        public function clean_upgrade_folder() {
     936                /** @var WP_Filesystem_Base $wp_filesystem */
     937                global $wp_filesystem;
     938
     939                //Clean up contents of upgrade directory.
     940                $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
     941                $upgrade_files  = $wp_filesystem->dirlist( $upgrade_folder );
     942                if ( ! empty( $upgrade_files ) ) {
     943                        foreach ( $upgrade_files as $file ) {
     944                                $wp_filesystem->delete( $upgrade_folder . $file['name'], true );
     945                        }
     946                }
     947        }
     948
     949        /**
     950         * Retrieves the used skin.
     951         *
     952         * @return WP_Upgrader_Skin The used skin.
     953         *
     954         * @since  x.x
     955         * @access public
     956         */
     957        public function get_skin() {
     958                return $this->skin;
     959        }
    928960}
    929961
    930962/** Plugin_Upgrader class */