WordPress.org

Make WordPress Core

Ticket #34676: 34676.1.patch

File 34676.1.patch, 38.6 KB (added by jipmoors, 4 years ago)

Separated Bulk from Upgrader

  • src/wp-admin/includes/class-wp-upgrader-bulk.php

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
     1<?php
     2/**
     3 * The Bulk handlers for the WordPress Upgrader
     4 *
     5 * @package    WordPress
     6 * @subpackage Upgrader
     7 * @since      4.4.1
     8 */
     9
     10/**
     11 * Abstract base class for Bulk Upgrades
     12 *
     13 * @since 4.4.1
     14 */
     15abstract class WP_Bulk_Upgrader_Composite {
     16        /**
     17         * @var WP_Upgrader
     18         */
     19        protected $upgrader;
     20
     21        /**
     22         * @var array Elements to upgrade
     23         */
     24        protected $elements = array();
     25
     26        /**
     27         * WP_Bulk_Upgrader_Composite constructor.
     28         *
     29         * @since 4.4.1
     30         *
     31         * @param WP_Upgrader $upgrader     Upgrader to report back to
     32         * @param array       $elements     List of elements to be bulked.
     33         * @param string      $elementClass Class name to wrap elements in. Extended of WP_Bulk_Upgrader_Element.
     34         */
     35        public function __construct( WP_Upgrader $upgrader, array $elements = array(), $elementClass ) {
     36                if ( ! is_string( $elementClass ) ) {
     37                        throw new InvalidArgumentException( 'Expected element class to be string, got ' . gettype( $elementClass ) );
     38                }
     39
     40                if ( ! class_exists( $elementClass ) ) {
     41                        throw new InvalidArgumentException( sprintf( 'Element class "%s" does not exist.', $elementClass ) );
     42                }
     43
     44                $this->upgrader = $upgrader;
     45
     46                if ( array() !== $elements ) {
     47                        foreach ( $elements as $element ) {
     48                                $this->elements[] = new $elementClass( $element, $upgrader );
     49                        }
     50                }
     51
     52                $this->upgrader->update_count   = count( $this->elements );
     53                $this->upgrader->update_current = 0;
     54        }
     55
     56        /**
     57         * Runs the bulk upgrade
     58         *
     59         * @since  4.4.1
     60         * @access public
     61         *
     62         * @return array
     63         */
     64        public function run() {
     65                $this->upgrader->clean_upgrade_folder();
     66
     67                $this->register_on_skin();
     68
     69                $this->check_up_to_date();
     70
     71                # Work
     72                $this->download();
     73                $this->unpack();
     74                $this->install();
     75                # Done
     76
     77                $this->upgrader->maintenance_mode( false );
     78                $this->upgrader->update_current = false;
     79
     80                return $this->get_results();
     81        }
     82
     83        /**
     84         * Shorthand retrieval of upgrader skin
     85         *
     86         * @since  4.4.1
     87         * @access protected
     88         *
     89         * @return null|WP_Upgrader_Skin
     90         */
     91        protected function get_skin() {
     92                return $this->upgrader->get_skin();
     93        }
     94
     95        /**
     96         * Set the current element as active on the upgrader
     97         *
     98         * @since  4.4.1
     99         * @access protected
     100         *
     101         * @param $element
     102         */
     103        protected function current_element( $element ) {
     104                $index = array_search( $element, $this->elements );
     105
     106                if ( false !== $index ) {
     107                        $this->upgrader->update_current = $index + 1;
     108                } else {
     109                        $this->upgrader->update_current = false;
     110                }
     111        }
     112
     113        /**
     114         * When the element is already up to date
     115         *
     116         * @since  4.4.1
     117         * @access protected
     118         *
     119         * @param $element
     120         */
     121        protected function handle_up_to_date( $element ) {
     122        }
     123
     124        /**
     125         * Optionally let the elements be sorted before installing
     126         *
     127         * @since 4.4.1
     128         * @acces protected
     129         *
     130         * @return array
     131         */
     132        protected function sort_install_elements() {
     133                return $this->elements;
     134        }
     135
     136        /**
     137         * Register elements on the skin
     138         *
     139         * @since  4.4.1
     140         * @access protected
     141         */
     142        protected function register_on_skin() {
     143                foreach ( $this->elements as $element ) {
     144                        $this->current_element( $element );
     145
     146                        $skin = $this->get_skin();
     147                        $skin->before();
     148                }
     149        }
     150
     151        /**
     152         * Check if any of the elements is already up to date
     153         *
     154         * @since  4.4.1
     155         * @access protected
     156         */
     157        protected function check_up_to_date() {
     158                /** @var $element WP_Bulk_Upgrader_Element */
     159                foreach ( $this->elements as $element ) {
     160                        if ( $element->is_up_to_date() ) {
     161                                $this->current_element( $element );
     162
     163                                $this->handle_up_to_date( $element );
     164
     165                                $skin = $this->get_skin();
     166
     167                                $skin->feedback( 'up_to_date' );
     168                                $skin->after();
     169                        }
     170                }
     171        }
     172
     173        /**
     174         * Download all the elements
     175         *
     176         * @since  4.4.1
     177         * @access protected
     178         */
     179        protected function download() {
     180                /** @var $element WP_Bulk_Upgrader_Element */
     181                foreach ( $this->elements as $element ) {
     182                        if ( $element->is_up_to_date() ) {
     183                                continue;
     184                        }
     185
     186                        $this->current_element( $element );
     187
     188                        $result = $element->download();
     189                        if ( is_wp_error( $result ) ) {
     190                                $this->show_error( $result, $element );
     191                        }
     192                }
     193        }
     194
     195        /**
     196         * Unpack downloaded elements
     197         *
     198         * @since  4.4.1
     199         * @access protected
     200         */
     201        protected function unpack() {
     202                /** @var $element WP_Bulk_Upgrader_Element */
     203                foreach ( $this->elements as $element ) {
     204                        if ( $element->is_up_to_date() ) {
     205                                continue;
     206                        }
     207
     208                        $this->current_element( $element );
     209
     210                        $result = $element->unpack();
     211                        if ( is_wp_error( $result ) ) {
     212                                $this->show_error( $result, $element );
     213                        }
     214                }
     215        }
     216
     217        /**
     218         * Install unpacked elements
     219         *
     220         * @since  4.4.1
     221         * @access protected
     222         */
     223        protected function install() {
     224                $elements = $this->sort_install_elements();
     225
     226                /** @var $element WP_Bulk_Upgrader_Element */
     227                foreach ( $elements as $element ) {
     228                        if ( $element->is_up_to_date() ) {
     229                                continue;
     230                        }
     231
     232                        $this->current_element( $element );
     233
     234                        $result = $element->install();
     235
     236                        $skin = $this->get_skin();
     237                        $skin->set_result( $result );
     238                        if ( is_wp_error( $result ) ) {
     239                                $skin->error( $result );
     240                                $skin->feedback( 'process_failed' );
     241                        } else {
     242                                // Install succeeded.
     243                                $skin->feedback( 'process_success' );
     244                        }
     245                        $skin->after();
     246                }
     247        }
     248
     249        /**
     250         * Get the results of the upgrade process
     251         *
     252         * @since  4.4.1
     253         * @access protected
     254         *
     255         * @return array
     256         */
     257        protected function get_results() {
     258                $results = array();
     259
     260                /** @var $element WP_Bulk_Upgrader_Element */
     261                foreach ( $this->elements as $element ) {
     262                        $index = $element->get_result_index();
     263                        if ( false === $index ) {
     264                                $results[] = $element->get_result();
     265                        } else {
     266                                $results[ $index ] = $element->get_result();
     267                        }
     268                }
     269
     270                return $results;
     271        }
     272
     273        /**
     274         * Pass error to skin
     275         *
     276         * @since  4.4.1
     277         * @access protected
     278         *
     279         * @param $error
     280         * @param $element
     281         */
     282        protected function show_error( $error, $element ) {
     283                $this->current_element( $element );
     284
     285                $skin = $this->get_skin();
     286                $skin->error( $error );
     287                $skin->after();
     288        }
     289}
     290
     291/**
     292 * Abstract base class for Bulk Upgrade Elements
     293 *
     294 * @since 4.4.1
     295 */
     296abstract class WP_Bulk_Upgrader_Element {
     297        /**
     298         * @var bool is this element already up-to-date
     299         */
     300        protected $up_to_date = false;
     301        /**
     302         * @var bool has the package been downloaded
     303         */
     304        protected $downloaded = false;
     305        /**
     306         * @var bool was the package unpacked properly
     307         */
     308        protected $unpacked = false;
     309        /**
     310         * @var bool has the package been installed
     311         */
     312        protected $installed = false;
     313
     314        /**
     315         * @var mixed identifier for this element (source)
     316         */
     317        protected $name;
     318        /**
     319         * @var WP_Upgrader upgrader to talk back to
     320         */
     321        protected $upgrader;
     322
     323        /**
     324         * @var array options of current element, used throughout the process
     325         */
     326        protected $options;
     327        /**
     328         * @var mixed info about the current element, used by the upgrader
     329         */
     330        protected $info;
     331        /**
     332         * @var string name of the download
     333         */
     334        protected $download;
     335        /**
     336         * @var string working dir for the unpacked package
     337         */
     338        protected $working_dir;
     339
     340        /**
     341         * @var mixed final result of installation (via upgrader)
     342         */
     343        protected $result;
     344
     345        /**
     346         * WP_Bulk_Upgrader_Element constructor.
     347         *
     348         * @since  4.4.1
     349         * @access public
     350         *
     351         * @param mixed       $name
     352         * @param WP_Upgrader $upgrader
     353         */
     354        public function __construct( $name, WP_Upgrader $upgrader ) {
     355                $this->name     = $name;
     356                $this->upgrader = $upgrader;
     357        }
     358
     359        /**
     360         * Get the original identifier data
     361         *
     362         * @since  4.4.1
     363         * @access public
     364         *
     365         * @return mixed
     366         */
     367        public function get_name() {
     368                return $this->name;
     369        }
     370
     371        /**
     372         * Get the cummulated result of the upgrade
     373         *
     374         * @since  4.4.1
     375         * @access public
     376         *
     377         * @return bool
     378         */
     379        public function get_result() {
     380                return isset( $this->result ) ? $this->result : $this->installed;
     381        }
     382
     383        /**
     384         * If the result needs to be named, it can be overwriten here
     385         *
     386         * @since  4.4.1
     387         * @access public
     388         *
     389         * @return bool
     390         */
     391        public function get_result_index() {
     392                return false;
     393        }
     394
     395        /**
     396         * Has been downloaded correctly
     397         *
     398         * @since  4.4.1
     399         * @access public
     400         *
     401         * @return bool
     402         */
     403        public function downloaded() {
     404                return $this->downloaded;
     405        }
     406
     407        /**
     408         * Has been unpacked succesfully
     409         *
     410         * @since  4.4.1
     411         * @access public
     412         *
     413         * @return bool
     414         */
     415        public function unpacked() {
     416                return $this->unpacked;
     417        }
     418
     419        /**
     420         * Has been installed succesfully
     421         *
     422         * @since  4.4.1
     423         * @access public
     424         *
     425         * @return bool
     426         */
     427        public function installed() {
     428                return $this->installed;
     429        }
     430
     431        /**
     432         * Is it already up-to-date
     433         *
     434         * @since  4.4.1
     435         * @access public
     436         *
     437         * @return bool
     438         */
     439        public function is_up_to_date() {
     440                return $this->up_to_date;
     441        }
     442
     443        /**
     444         * Get element info
     445         *
     446         * @since  4.4.1
     447         * @access public
     448         * @return mixed
     449         */
     450        public function get_info() {
     451                return $this->info;
     452        }
     453
     454        /**
     455         * Optionally manage maintenance after install
     456         *
     457         * @since  4.4.1
     458         * @access protected
     459         *
     460         * @param $maintenance
     461         */
     462        protected function post_install( $maintenance ) {
     463        }
     464
     465        /**
     466         * Apply defaults and filter to options
     467         *
     468         * @since  4.4.1
     469         * @access protected
     470         *
     471         * @param $options
     472         */
     473        protected function set_options( $options ) {
     474                $defaults = array(
     475                        'package'                     => '',
     476                        // Please always pass this.
     477                        'destination'                 => '',
     478                        // And this
     479                        'clear_destination'           => false,
     480                        'abort_if_destination_exists' => true,
     481                        // Abort if the Destination directory exists, Pass clear_destination as false please
     482                        'clear_working'               => true,
     483                        'is_multi'                    => false,
     484                        'hook_extra'                  => array()
     485                        // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
     486                );
     487
     488                $options = wp_parse_args( $options, $defaults );
     489
     490                /** This filter is documented in wp-admin/includes/class-wp-upgrader.php */
     491                $this->options = apply_filters( 'upgrader_package_options', $options );
     492        }
     493
     494        /**
     495         * Does element need maintenance to be enabled
     496         *
     497         * @since  4.4.1
     498         * @access protected
     499         *
     500         * @return bool
     501         */
     502        protected function need_maintenance() {
     503                return false;
     504        }
     505
     506        /**
     507         * Download this element
     508         *
     509         * @since  4.4.1
     510         * @access public
     511         *
     512         * @return bool|string|WP_Error
     513         */
     514        public function download() {
     515                if ( $this->is_up_to_date() ) {
     516                        return false;
     517                }
     518
     519                // Connect to the Filesystem first.
     520                $result = $this->upgrader->fs_connect( array( WP_CONTENT_DIR, $this->options['destination'] ) );
     521                // Mainly for non-connected filesystem.
     522                if ( ! $result || is_wp_error( $result ) ) {
     523                        return $result;
     524                }
     525
     526                /*
     527                 * Download the package (Note, This just returns the filename
     528                 * of the file if the package is a local file)
     529                 */
     530                $result = $this->upgrader->download_package( $this->options['package'] );
     531                if ( ! is_wp_error( $result ) ) {
     532                        $this->downloaded = true;
     533                        $this->download   = $result;
     534                }
     535
     536                return $result;
     537        }
     538
     539        /**
     540         * Unpack this element
     541         *
     542         * @since  4.4.1
     543         * @access public
     544         *
     545         * @return bool|string|WP_Error
     546         */
     547        public function unpack() {
     548                if ( ! $this->downloaded() ) {
     549                        return false;
     550                }
     551
     552                // Do not delete a "local" file
     553                $delete_package = ( $this->download !== $this->options['package'] );
     554
     555                // Unzips the file into a temporary directory.
     556                $result = $this->upgrader->unpack_package( $this->download, $delete_package );
     557                if ( ! is_wp_error( $result ) ) {
     558                        $this->unpacked    = true;
     559                        $this->working_dir = $result;
     560                }
     561
     562                return $result;
     563        }
     564
     565        /**
     566         * Install this element
     567         *
     568         * Enable maintenance mode if required
     569         *
     570         * @since  4.4.1
     571         * @access public
     572         *
     573         * @return array|bool|WP_Error
     574         */
     575        public function install() {
     576                if ( ! $this->unpacked() ) {
     577                        return false;
     578                }
     579
     580                $maintenance = $this->need_maintenance();
     581                $this->upgrader->maintenance_mode( $maintenance );
     582
     583                // With the given options, this installs it to the destination directory.
     584                $result = $this->upgrader->install_package( array(
     585                        'source'                      => $this->working_dir,
     586                        'destination'                 => $this->options['destination'],
     587                        'clear_destination'           => $this->options['clear_destination'],
     588                        'abort_if_destination_exists' => $this->options['abort_if_destination_exists'],
     589                        'clear_working'               => $this->options['clear_working'],
     590                        'hook_extra'                  => $this->options['hook_extra']
     591                ) );
     592
     593                $this->post_install( $maintenance );
     594
     595                /*
     596                 * This does not feel right.
     597                 */
     598                $this->result = $this->upgrader->result;
     599
     600                return $result;
     601        }
     602}
     603
     604/**
     605 * Abstract base class for Bulk Upgrade Elements that are formatted as Plugin/Theme
     606 *
     607 * @since 4.4.1
     608 */
     609abstract class WP_Bulk_Upgrader_Element_Plugin_Format extends WP_Bulk_Upgrader_Element {
     610        /**
     611         * @var object cache for current element type information
     612         */
     613        protected static $current;
     614
     615        /**
     616         * @var object current element response information from repository
     617         */
     618        protected $response;
     619
     620        /**
     621         * Implement logic to tell if this element is active
     622         *
     623         * @since  4.4.1
     624         * @access public
     625         *
     626         * @return mixed
     627         */
     628        abstract public function is_active();
     629
     630        /**
     631         * Implement logic to get current info on all elements
     632         *
     633         * @since  4.4.1
     634         * @access protected
     635         *
     636         * @return mixed
     637         */
     638        abstract protected function get_current();
     639
     640        /**
     641         * Results are based on plugin name
     642         *
     643         * @return mixed
     644         */
     645        public function get_result_index() {
     646                return $this->name;
     647        }
     648
     649        /**
     650         * Get plugin repository response
     651         *
     652         * @since  4.4.1
     653         * @access protected
     654         *
     655         * @return bool|object Response from the respository as stdClass
     656         */
     657        protected function get_response() {
     658                $current = $this->get_current();
     659
     660                if ( is_object( $current ) && is_array( $current->response ) ) {
     661                        return $this->response = isset( $current->response[ $this->name ] ) ? $current->response[ $this->name ] : false;
     662                }
     663
     664                return false;
     665        }
     666}
     667
     668/**
     669 * Plugin Bulk Upgrader implementation
     670 *
     671 * @since 4.4.1
     672 */
     673class WP_Plugin_Bulk_Upgrader extends WP_Bulk_Upgrader_Composite {
     674        /**
     675         * WP_Plugin_Bulk_Upgrader constructor.
     676         *
     677         * @since  4.4.1
     678         * @access public
     679         *
     680         * @param Plugin_Upgrader $upgrader
     681         * @param array           $elements
     682         */
     683        public function __construct( Plugin_Upgrader $upgrader, array $elements = array() ) {
     684                parent::__construct( $upgrader, $elements, 'WP_Bulk_Upgrader_Plugin_Element' );
     685        }
     686
     687        /**
     688         * Communicate plugin info to skin
     689         *
     690         * @since  4.4.1
     691         * @access protected
     692         *
     693         * @param WP_Bulk_Upgrader_Element $element
     694         */
     695        protected function current_element( WP_Bulk_Upgrader_Element $element ) {
     696                parent::current_element( $element );
     697
     698                $skin = $this->get_skin();
     699                if ( $skin instanceof Bulk_Plugin_Upgrader_Skin ) {
     700                        $skin->plugin_info = $element->get_info();
     701                }
     702        }
     703
     704        /**
     705         * Communicate result to skin
     706         *
     707         * @since  4.4.1
     708         * @access public
     709         *
     710         * @param WP_Bulk_Upgrader_Element $element
     711         */
     712        public function handle_up_to_date( WP_Bulk_Upgrader_Element $element ) {
     713                $skin = $this->get_skin();
     714                if ( $skin instanceof WP_Upgrader_Skin ) {
     715                        $skin->set_result( 'up_to_date' );
     716                }
     717        }
     718
     719        /**
     720         * Sort plugin so active ones are bundled at the end
     721         *
     722         * @since  4.4.1
     723         * @access protected
     724         *
     725         * @return array
     726         */
     727        protected function sort_install_elements() {
     728                $sorted = $this->elements;
     729                usort( $sorted, array( $this, 'sort_elements_active_on_bottom' ) );
     730
     731                return $sorted;
     732        }
     733
     734        /**
     735         * Sort plugins
     736         *
     737         * @since  4.4.1
     738         * @access private
     739         *
     740         * @param WP_Bulk_Upgrader_Element_Plugin_Format $a
     741         * @param WP_Bulk_Upgrader_Element_Plugin_Format $b
     742         *
     743         * @return int 0, -1 or 1
     744         */
     745        private function sort_elements_active_on_bottom(
     746                WP_Bulk_Upgrader_Element_Plugin_Format $a,
     747                WP_Bulk_Upgrader_Element_Plugin_Format $b
     748        ) {
     749                if ( $a->is_active() === $b->is_active() ) {
     750                        return 0;
     751                }
     752
     753                // Active plugins last:
     754                return ( $a->is_active() && ! $b->is_active() ) ? 1 : - 1;
     755        }
     756}
     757
     758/**
     759 * Plugin implementation of the Bulk Upgrade Element
     760 *
     761 * @since 4.4.1
     762 */
     763class WP_Bulk_Upgrader_Plugin_Element extends WP_Bulk_Upgrader_Element_Plugin_Format {
     764        /**
     765         * WP_Bulk_Upgrader_Plugin_Element constructor.
     766         *
     767         * @since  4.4.1
     768         * @access public
     769         *
     770         * @param string          $plugin
     771         * @param Plugin_Upgrader $upgrader
     772         */
     773        public function __construct( $plugin, Plugin_Upgrader $upgrader ) {
     774                parent::__construct( $plugin, $upgrader );
     775
     776                $this->info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true );
     777
     778                $response = $this->get_response();
     779                if ( false === $response ) {
     780                        $this->up_to_date = true;
     781
     782                        return;
     783                }
     784
     785                $options = array(
     786                        'package'           => $response->package,
     787                        'destination'       => WP_PLUGIN_DIR,
     788                        'clear_destination' => true,
     789                        'clear_working'     => true,
     790                        'is_multi'          => true,
     791                        'hook_extra'        => array(
     792                                'plugin' => $plugin
     793                        )
     794                );
     795
     796                $this->set_options( $options );
     797        }
     798
     799        /**
     800         * Is this plugin activated
     801         *
     802         * @since  4.4.1
     803         * @access public
     804         *
     805         * @return bool
     806         */
     807        public function is_active() {
     808                return is_plugin_active( $this->name );
     809        }
     810
     811        /**
     812         * Get info from transient update_plugins
     813         *
     814         * @since  4.4.1
     815         * @access protected
     816         *
     817         * @return mixed
     818         */
     819        protected function get_current() {
     820                if ( ! isset( self::$current ) ) {
     821                        self::$current = get_site_transient( 'update_plugins' );
     822                }
     823
     824                return self::$current;
     825        }
     826
     827        /**
     828         * Do we need maintenance mode to install
     829         *
     830         * @since  4.4.1
     831         * @access protected
     832         *
     833         * @return bool
     834         */
     835        protected function need_maintenance() {
     836                return is_multisite() || $this->is_active();
     837        }
     838}
     839
     840/**
     841 * Theme Bulk Upgrader implementation
     842 *
     843 * @since 4.4.1
     844 */
     845class WP_Theme_Bulk_Upgrader extends WP_Bulk_Upgrader_Composite {
     846        /**
     847         * WP_Theme_Bulk_Upgrader constructor.
     848         *
     849         * @since  4.4.1
     850         * @access public
     851         *
     852         * @param Theme_Upgrader $upgrader
     853         * @param array          $elements
     854         */
     855        public function __construct( Theme_Upgrader $upgrader, array $elements = array() ) {
     856                parent::__construct( $upgrader, $elements, 'WP_Bulk_Upgrader_Theme_Element' );
     857        }
     858
     859        /**
     860         * Communicate theme info to skin
     861         *
     862         * @since  4.4.1
     863         * @access protected
     864         *
     865         * @param WP_Bulk_Upgrader_Element $element
     866         */
     867        protected function current_element( WP_Bulk_Upgrader_Element $element ) {
     868                parent::current_element( $element );
     869
     870                $skin = $this->get_skin();
     871                if ( $skin instanceof Bulk_Theme_Upgrader_Skin ) {
     872                        $skin->theme_info = $element->get_info();
     873                }
     874        }
     875
     876        /**
     877         * Communicate result to skin
     878         *
     879         * @since  4.4.1
     880         * @access public
     881         *
     882         * @param $element
     883         */
     884        public function handle_up_to_date( $element ) {
     885                $this->get_skin()->set_result( true );
     886        }
     887}
     888
     889/**
     890 * Theme implementation of the Bulk Upgrade Element
     891 *
     892 * @since 4.4.1
     893 */
     894class WP_Bulk_Upgrader_Theme_Element extends WP_Bulk_Upgrader_Element_Plugin_Format {
     895        /**
     896         * WP_Bulk_Upgrader_Theme_Element constructor.
     897         *
     898         * @since  4.4.1
     899         * @access public
     900         *
     901         * @param string         $theme
     902         * @param Theme_Upgrader $upgrader
     903         */
     904        public function __construct( $theme, Theme_Upgrader $upgrader ) {
     905                parent::__construct( $theme, $upgrader );
     906
     907                $this->info = $upgrader->theme_info( $theme );
     908
     909                $response = $this->get_response();
     910                if ( false === $response ) {
     911                        $this->up_to_date = true;
     912
     913                        return;
     914                }
     915
     916                $options = array(
     917                        'package'           => $this->response['package'],
     918                        'destination'       => get_theme_root( $theme ),
     919                        'clear_destination' => true,
     920                        'clear_working'     => true,
     921                        'is_multi'          => true,
     922                        'hook_extra'        => array(
     923                                'theme' => $theme
     924                        )
     925                );
     926
     927                $this->set_options( $options );
     928        }
     929
     930
     931        /**
     932         * Get info from update_themes
     933         *
     934         * @since  4.4.1
     935         * @access protected
     936         *
     937         * @return mixed
     938         */
     939        protected function get_current() {
     940                // @todo should this be cached or not?
     941                if ( ! isset( self::$current ) ) {
     942                        self::$current = get_site_transient( 'update_themes' );
     943                }
     944
     945                return self::$current;
     946        }
     947
     948        /**
     949         * Is this theme active
     950         *
     951         * @since  4.4.1
     952         * @access public
     953         *
     954         * @return bool
     955         */
     956        public function is_active() {
     957                return $this->name == get_stylesheet() || $this->name == get_template();
     958        }
     959
     960        /**
     961         * Do we need maintenace mode to install
     962         *
     963         * @since  4.4.1
     964         * @access protected
     965         *
     966         * @return bool
     967         */
     968        protected function need_maintenance() {
     969                return is_multisite() || $this->is_active();
     970        }
     971
     972        /**
     973         * Disable maintenance mode if it was active during install
     974         *
     975         * There can be only 1 active theme, so disable maintenance after installing
     976         *
     977         * @since  4.4.1
     978         * @access protected
     979         *
     980         * @param $maintenance
     981         */
     982        protected function post_install( $maintenance ) {
     983                if ( $maintenance ) {
     984                        $this->upgrader->maintenance_mode( false );
     985                }
     986        }
     987}
     988
     989/**
     990 * Language Bulk Upgrader implementation
     991 *
     992 * @since 4.4.1
     993 */
     994class WP_Language_Bulk_Upgrader extends WP_Bulk_Upgrader_Composite {
     995        /**
     996         * WP_Language_Bulk_Upgrader constructor.
     997         *
     998         * @since  4.4.1
     999         * @access public
     1000         *
     1001         * @param Language_Pack_Upgrader $upgrader
     1002         * @param array                  $elements
     1003         */
     1004        public function __construct( Language_Pack_Upgrader $upgrader, array $elements = array() ) {
     1005                parent::__construct( $upgrader, $elements, 'WP_Bulk_Upgrader_Language_Element' );
     1006        }
     1007
     1008        /**
     1009         * Communicate language info to skin
     1010         *
     1011         * @since  4.4.1
     1012         * @access protected
     1013         *
     1014         * @param WP_Bulk_Upgrader_Element $element
     1015         */
     1016        protected function current_element( WP_Bulk_Upgrader_Element $element ) {
     1017                parent::current_element( $element );
     1018
     1019                $skin = $this->get_skin();
     1020                if ( $skin instanceof Language_Pack_Upgrader_Skin ) {
     1021                        $skin->language_update = $element->get_name();
     1022                }
     1023        }
     1024}
     1025
     1026/**
     1027 * Language implementation of the Bulk Upgrade Element
     1028 *
     1029 * @since 4.4.1
     1030 */
     1031class WP_Bulk_Upgrader_Language_Element extends WP_Bulk_Upgrader_Element {
     1032        /**
     1033         * WP_Bulk_Upgrader_Language_Element constructor.
     1034         *
     1035         * @since  4.4.1
     1036         * @access public
     1037         *
     1038         * @param mixed                  $language_update
     1039         * @param Language_Pack_Upgrader $upgrader
     1040         */
     1041        public function __construct( $language_update, Language_Pack_Upgrader $upgrader ) {
     1042                parent::__construct( $language_update, $upgrader );
     1043
     1044                $destination = WP_LANG_DIR;
     1045                if ( 'plugin' == $language_update->type ) {
     1046                        $destination .= '/plugins';
     1047                } elseif ( 'theme' == $language_update->type ) {
     1048                        $destination .= '/themes';
     1049                }
     1050
     1051                $options = array(
     1052                        'package'                     => $language_update->package,
     1053                        'destination'                 => $destination,
     1054                        'clear_destination'           => false,
     1055                        'abort_if_destination_exists' => false, // We expect the destination to exist.
     1056                        'clear_working'               => true,
     1057                        'is_multi'                    => true,
     1058                        'hook_extra'                  => array(
     1059                                'language_update_type' => $language_update->type,
     1060                                'language_update'      => $language_update,
     1061                        )
     1062                );
     1063
     1064                $this->set_options( $options );
     1065        }
     1066}
     1067 No newline at end of file
  • src/wp-admin/includes/class-wp-upgrader-skins.php

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
    5959         * @param bool   $error
    6060         * @param string $context
    6161         * @param bool   $allow_relaxed_file_ownership
    62          * @return type
     62         * @return bool
    6363         */
    6464        public function request_filesystem_credentials( $error = false, $context = false, $allow_relaxed_file_ownership = false ) {
    6565                $url = $this->options['url'];
     
    309309                }
    310310                if ( empty($string) )
    311311                        return;
    312                 if ( $this->in_loop )
    313                         echo "$string<br />\n";
    314                 else
    315                         echo "<p>$string</p>\n";
    316         }
     312
     313                if ( $this->upgrader->update_current > 0 ) {
     314                        $target_id = sprintf( '#progress-%d p:last-child', $this->upgrader->update_current );
     315                        $output    = "$string<br />";
     316
     317                        echo '<script type="text/javascript">jQuery(\'' . $target_id . '\').append(\'' . str_replace( "'", "\\'", $output ) . '\');</script>';
     318                } else {
     319
     320                        if ( $this->in_loop ) {
     321                                echo "$string<br />\n";
     322                        } else {
     323                                echo "<p>$string</p>\n";
     324                        }
     325                }
    317326
     327        }
     328
    318329        /**
    319330         * @access public
    320331         */
     
    372383                $this->in_loop = true;
    373384                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 );
    374385                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>';
     386                echo '<div class="update-messages hide-if-js" id="progress-' . esc_attr($this->upgrader->update_current) . '"><p></p></div>';
    376387                $this->flush_output();
    377388        }
    378389
     
    381392         * @param string $title
    382393         */
    383394        public function after($title = '') {
    384                 echo '</p></div>';
     395
    385396                if ( $this->error || ! $this->result ) {
    386397                        if ( $this->error ) {
    387398                                echo '<div class="error"><p>' . sprintf($this->upgrader->strings['skin_update_failed_error'], $title, '<strong>' . $this->error . '</strong>' ) . '</p></div>';
  • src/wp-admin/includes/class-wp-upgrader.php

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
    1212 */
    1313
    1414require ABSPATH . 'wp-admin/includes/class-wp-upgrader-skins.php';
     15require ABSPATH . 'wp-admin/includes/class-wp-upgrader-bulk.php';
    1516
    1617/**
    1718 * Core class used for upgrading/installing a local set of files via
     
    254255        }
    255256
    256257        /**
     258         * Clears optional remnants of previous upgrades
     259         *
     260         * @since 4.4.1
     261         * @access public
     262         *
     263         * @global WP_Filesystem_Base $wp_filesystem Subclass
     264         */
     265        public function clean_upgrade_folder() {
     266                global $wp_filesystem;
     267
     268                //Clean up contents of upgrade directory.
     269                $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
     270                $upgrade_files  = $wp_filesystem->dirlist( $upgrade_folder );
     271                if ( ! empty( $upgrade_files ) ) {
     272                        foreach ( $upgrade_files as $file ) {
     273                                $wp_filesystem->delete( $upgrade_folder . $file['name'], true );
     274                        }
     275                }
     276        }
     277
     278        /**
    257279         * Unpack a compressed package file.
    258280         *
    259281         * @since 2.8.0
     
    274296                $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
    275297
    276298                //Clean up contents of upgrade directory beforehand.
     299                /*
    277300                $upgrade_files = $wp_filesystem->dirlist($upgrade_folder);
    278301                if ( !empty($upgrade_files) ) {
    279302                        foreach ( $upgrade_files as $file )
    280303                                $wp_filesystem->delete($upgrade_folder . $file['name'], true);
    281304                }
     305                */
    282306
    283307                // We need a working directory - Strip off any .tmp or .zip suffixes
    284308                $working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
     
    641665                 */
    642666                $options = apply_filters( 'upgrader_package_options', $options );
    643667
    644                 if ( ! $options['is_multi'] ) { // call $this->header separately if running multiple times
    645                         $this->skin->header();
    646                 }
     668                $this->skin->header();
    647669
    648670                // Connect to the Filesystem first.
    649671                $res = $this->fs_connect( array( WP_CONTENT_DIR, $options['destination'] ) );
     
    666688                        return $res;
    667689                }
    668690
     691                $this->clean_upgrade_folder();
     692
    669693                /*
    670694                 * Download the package (Note, This just returns the filename
    671695                 * of the file if the package is a local file)
     
    751775                }
    752776        }
    753777
    754 }
     778        /**
     779         * Get the used skin
     780         *
     781         * @since 4.4.1
     782         * @access public
     783         *
     784         * @return null|WP_Upgrader_Skin
     785         */
     786        public function get_skin() {
     787                return $this->skin;
     788        }
    755789
     790}
     791
    756792/**
    757793 * Core class used for upgrading/installing plugins.
    758794 *
     
    950986         * @param array $args {
    951987         *     Optional. Other arguments for upgrading several plugins at once. Default empty array.
    952988         *
    953          *     @type bool $clear_update_cache Whether to clear the plugin updates cache if successful.
     989         * @type bool $clear_update_cache Whether to clear the plugin updates cache if successful.
    954990         *                                    Default true.
    955991         * }
    956992         * @return array|false An array of results indexed by plugin file, or false if unable to connect to the filesystem.
    957993         */
    958994        public function bulk_upgrade( $plugins, $args = array() ) {
    959995
    960                 $defaults = array(
     996                $defaults    = array(
    961997                        'clear_update_cache' => true,
    962998                );
    963999                $parsed_args = wp_parse_args( $args, $defaults );
     
    9681004
    9691005                $current = get_site_transient( 'update_plugins' );
    9701006
    971                 add_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'), 10, 4);
     1007                add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ), 10, 4 );
    9721008
    9731009                $this->skin->header();
    9741010
    9751011                // Connect to the Filesystem first.
    976                 $res = $this->fs_connect( array(WP_CONTENT_DIR, WP_PLUGIN_DIR) );
     1012                $res = $this->fs_connect( array( WP_CONTENT_DIR, WP_PLUGIN_DIR ) );
    9771013                if ( ! $res ) {
    9781014                        $this->skin->footer();
     1015
    9791016                        return false;
    9801017                }
    9811018
    9821019                $this->skin->bulk_header();
    9831020
    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);
     1021                $plugin_bulk_upgrader = new WP_Plugin_Bulk_Upgrader( $this, $plugins );
     1022                $results = $plugin_bulk_upgrader->run();
    9951023
    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 
    10381024                /**
    10391025                 * Fires when the bulk upgrader process is complete.
    10401026                 *
     
    10421028                 *
    10431029                 * @param Plugin_Upgrader $this Plugin_Upgrader instance. In other contexts, $this, might
    10441030                 *                              be a Theme_Upgrader or Core_Upgrade instance.
    1045                  * @param array           $data {
     1031                 * @param array $data {
    10461032                 *     Array of bulk item update data.
    10471033                 *
    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.
     1034                 * @type string $action Type of action. Default 'update'.
     1035                 * @type string $type Type of update process. Accepts 'plugin', 'theme', or 'core'.
     1036                 * @type bool $bulk Whether the update process is a bulk update. Default true.
     1037                 * @type array $packages Array of plugin, theme, or core packages to update.
    10521038                 * }
    10531039                 */
    10541040                do_action( 'upgrader_process_complete', $this, array(
    1055                         'action' => 'update',
    1056                         'type' => 'plugin',
    1057                         'bulk' => true,
     1041                        'action'  => 'update',
     1042                        'type'    => 'plugin',
     1043                        'bulk'    => true,
    10581044                        'plugins' => $plugins,
    10591045                ) );
    10601046
     
    10631049                $this->skin->footer();
    10641050
    10651051                // Cleanup our hooks, in case something else does a upgrade on this connection.
    1066                 remove_filter('upgrader_clear_destination', array($this, 'delete_old_plugin'));
     1052                remove_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ) );
    10671053
    10681054                // Force refresh of plugin update information.
    10691055                wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
     
    15501536
    15511537                $this->skin->bulk_header();
    15521538
    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);
     1539                $theme_bulk_upgrader = new WP_Theme_Bulk_Upgrader( $this, $themes );
     1540                $results = $theme_bulk_upgrader->run();
    15621541
    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 
    16041542                /** This action is documented in wp-admin/includes/class-wp-upgrader.php */
    16051543                do_action( 'upgrader_process_complete', $this, array(
    16061544                        'action' => 'update',
     
    20101948                        return false;
    20111949                }
    20121950
    2013                 $results = array();
    2014 
    2015                 $this->update_count = count( $language_updates );
    2016                 $this->update_current = 0;
    2017 
    20181951                /*
    20191952                 * The filesystem's mkdir() is not recursive. Make sure WP_LANG_DIR exists,
    20201953                 * as we then may need to create a /plugins or /themes directory inside of it.
     
    20241957                        if ( ! $wp_filesystem->mkdir( $remote_destination, FS_CHMOD_DIR ) )
    20251958                                return new WP_Error( 'mkdir_failed_lang_dir', $this->strings['mkdir_failed'], $remote_destination );
    20261959
    2027                 foreach ( $language_updates as $language_update ) {
     1960                $language_bulk_upgrader = new WP_Language_Bulk_Upgrader( $this, $language_updates );
     1961                $results = $language_bulk_upgrader->run();
    20281962
    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 
    20611963                $this->skin->bulk_footer();
    20621964
    20631965                $this->skin->footer();
     
    20781980         * Hooked to the {@see 'upgrader_source_selection'} filter by
    20791981         * {@see Language_Pack_Upgrader::bulk_upgrade()}.
    20801982         *
    2081          * @since 3.7.0
     1983         * @since  3.7.0
    20821984         * @access public
    20831985         *
    20841986         * @global WP_Filesystem_Base $wp_filesystem Subclass
    20851987         *
    2086          * @param string|WP_Error $source
    2087          * @param string          $remote_source
     1988         * @param string|WP_Error     $source
     1989         * @param string              $remote_source
     1990         *
     1991         * @return string|WP_Error
    20881992         */
    20891993        public function check_package( $source, $remote_source ) {
    20901994                global $wp_filesystem;
     
    35383442
    35393443                wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] );
    35403444        }
    3541 }
     3445}
     3446 No newline at end of file