Make WordPress Core


Ignore:
Timestamp:
07/07/2020 05:47:37 PM (6 years ago)
Author:
azaozz
Message:

Upgrade/install: Allow plugin and theme updates from a uploaded .zip file.

Props mariovalney, cyberhobo, imath, shaunandrews, mariovalney, earnjam, desrosj, dd32, folletto, swissspidy, melchoyce, pento, joshuawold, psykro, clorith, ahortin, galbaras, pingram3541, joyously, doobeedoo, karmatosed, poena, whyisjake, earnjam, sergeybiryukov, audrasjb, azaozz.

Fixes #9757.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-plugin-installer-skin.php

    r47808 r48390  
    1919        public $api;
    2020        public $type;
     21        public $url;
     22        public $overwrite;
     23
     24        private $is_downgrading = false;
    2125
    2226        /**
     
    2529        public function __construct( $args = array() ) {
    2630                $defaults = array(
    27                         'type'   => 'web',
    28                         'url'    => '',
    29                         'plugin' => '',
    30                         'nonce'  => '',
    31                         'title'  => '',
     31                        'type'      => 'web',
     32                        'url'       => '',
     33                        'plugin'    => '',
     34                        'nonce'     => '',
     35                        'title'     => '',
     36                        'overwrite' => '',
    3237                );
    3338                $args     = wp_parse_args( $args, $defaults );
    3439
    35                 $this->type = $args['type'];
    36                 $this->api  = isset( $args['api'] ) ? $args['api'] : array();
     40                $this->type      = $args['type'];
     41                $this->url       = $args['url'];
     42                $this->api       = isset( $args['api'] ) ? $args['api'] : array();
     43                $this->overwrite = $args['overwrite'];
    3744
    3845                parent::__construct( $args );
     
    4451                if ( ! empty( $this->api ) ) {
    4552                        $this->upgrader->strings['process_success'] = sprintf(
    46                                 /* translators: 1: Plugin name, 2: Plugin version. */
    47                                 __( 'Successfully installed the plugin <strong>%1$s %2$s</strong>.' ),
     53                                $this->upgrader->strings['process_success_specific'],
    4854                                $this->api->name,
    4955                                $this->api->version
     
    5359
    5460        /**
     61         * Hides the `process_failed` error when updating a plugin by uploading a zip file.
     62         *
     63         * @since 5.5.0
     64         *
     65         * @param $wp_error WP_Error.
     66         * @return bool
     67         */
     68        public function hide_process_failed( $wp_error ) {
     69                if (
     70                        'upload' === $this->type &&
     71                        '' === $this->overwrite &&
     72                        $wp_error->get_error_code() === 'folder_exists'
     73                ) {
     74                        return true;
     75                }
     76
     77                return false;
     78        }
     79
     80        /**
    5581         */
    5682        public function after() {
     83                // Check if the plugin can be overwritten and output the HTML.
     84                if ( $this->do_overwrite() ) {
     85                        return;
     86                }
     87
    5788                $plugin_file = $this->upgrader->plugin_info();
    5889
     
    118149                if ( ! $this->result || is_wp_error( $this->result ) ) {
    119150                        unset( $install_actions['activate_plugin'], $install_actions['network_activate'] );
    120                 } elseif ( ! current_user_can( 'activate_plugin', $plugin_file ) ) {
     151                } elseif ( ! current_user_can( 'activate_plugin', $plugin_file ) || is_plugin_active( $plugin_file ) ) {
    121152                        unset( $install_actions['activate_plugin'] );
    122153                }
     
    139170                }
    140171        }
     172
     173        /**
     174         * Check if the plugin can be overwritten and output the HTML for overwriting a plugin on upload.
     175         *
     176         * @since 5.5.0
     177         *
     178         * @return bool Whether the plugin can be overwritten and HTML was outputted.
     179         */
     180        private function do_overwrite() {
     181                if ( 'upload' !== $this->type || ! is_wp_error( $this->result ) || 'folder_exists' !== $this->result->get_error_code() ) {
     182                        return false;
     183                }
     184
     185                $folder = $this->result->get_error_data( 'folder_exists' );
     186                $folder = ltrim( substr( $folder, strlen( WP_PLUGIN_DIR ) ), '/' );
     187
     188                $current_plugin_data = false;
     189                foreach ( get_plugins() as $plugin => $plugin_data ) {
     190                        if ( strrpos( $plugin, $folder ) !== 0 ) {
     191                                continue;
     192                        }
     193
     194                        $current_plugin_data = $plugin_data;
     195                }
     196
     197                if ( empty( $current_plugin_data ) || empty( $this->upgrader->new_plugin_data ) ) {
     198                        return false;
     199                }
     200
     201                echo '<h2 class="update-from-upload-heading">' . esc_html( __( 'This plugin is already installed.' ) ) . '</h2>';
     202
     203                $this->is_downgrading = version_compare( $current_plugin_data['Version'], $this->upgrader->new_plugin_data['Version'], '>' );
     204
     205                $rows = array(
     206                        'Name'        => __( 'Plugin name' ),
     207                        'Version'     => __( 'Version' ),
     208                        'Author'      => __( 'Author' ),
     209                        'RequiresWP'  => __( 'Required WordPress version' ),
     210                        'RequiresPHP' => __( 'Required PHP version' ),
     211                );
     212
     213                $table  = '<table class="update-from-upload-comparison"><tbody>';
     214                $table .= '<tr><th></th><th>' . esc_html( __( 'Current' ) ) . '</th>';
     215                $table .= '<th>' . esc_html( __( 'Uploaded' ) ) . '</th></tr>';
     216
     217                $is_same_plugin = true; // Let's consider only these rows
     218                foreach ( $rows as $field => $label ) {
     219                        $old_value = ! empty( $current_plugin_data[ $field ] ) ? $current_plugin_data[ $field ] : '-';
     220                        $new_value = ! empty( $this->upgrader->new_plugin_data[ $field ] ) ? $this->upgrader->new_plugin_data[ $field ] : '-';
     221
     222                        $is_same_plugin = $is_same_plugin && ( $old_value === $new_value );
     223
     224                        $diff_field   = ( 'Version' !== $field && $new_value !== $old_value );
     225                        $diff_version = ( 'Version' === $field && $this->is_downgrading );
     226
     227                        $table .= '<tr><td class="name-label">' . $label . '</td><td>' . esc_html( $old_value ) . '</td>';
     228                        $table .= ( $diff_field || $diff_version ) ? '<td class="warning">' : '<td>';
     229                        $table .= esc_html( $new_value ) . '</td></tr>';
     230                }
     231
     232                $table .= '</tbody></table>';
     233
     234                /**
     235                 * Filters the compare table output for overwrite a plugin package on upload.
     236                 *
     237                 * @since 5.5.0
     238                 *
     239                 * @param string   $table                The output table with Name, Version, Author, RequiresWP and RequiresPHP info.
     240                 * @param array    $current_plugin_data  Array with current plugin data.
     241                 * @param array    $new_plugin_data      Array with uploaded plugin data.
     242                 */
     243                echo apply_filters( 'install_plugin_ovewrite_comparison', $table, $current_plugin_data, $this->upgrader->new_plugin_data );
     244
     245                $install_actions = array();
     246                $can_update      = true;
     247
     248                $blocked_message  = '<p>' . esc_html( __( 'The plugin cannot be updated due to the following:' ) ) . '</p>';
     249                $blocked_message .= '<ul class="ul-disc">';
     250
     251                if (
     252                        ! empty( $this->upgrader->new_plugin_data['RequiresPHP'] ) &&
     253                        version_compare( phpversion(), $this->upgrader->new_plugin_data['RequiresPHP'], '<' )
     254                ) {
     255                        $error = sprintf(
     256                                /* translators: 1: Current PHP version, 2: Version required by the uploaded plugin. */
     257                                __( 'The PHP version on your server is %1$s, however the uploaded plugin requires %2$s.' ),
     258                                phpversion(),
     259                                $this->upgrader->new_plugin_data['RequiresPHP']
     260                        );
     261
     262                        $blocked_message .= '<li>' . esc_html( $error ) . '</li>';
     263                        $can_update       = false;
     264                }
     265
     266                if (
     267                        ! empty( $this->upgrader->new_plugin_data['RequiresWP'] ) &&
     268                        version_compare( $GLOBALS['wp_version'], $this->upgrader->new_plugin_data['RequiresWP'], '<' )
     269                ) {
     270                        $error = sprintf(
     271                                /* translators: 1: Current WordPress version, 2: Version required by the uploaded plugin. */
     272                                __( 'Your WordPress version is %1$s, however the uploaded plugin requires %2$s.' ),
     273                                $GLOBALS['wp_version'],
     274                                $this->upgrader->new_plugin_data['RequiresWP']
     275                        );
     276
     277                        $blocked_message .= '<li>' . esc_html( $error ) . '</li>';
     278                        $can_update       = false;
     279                }
     280
     281                $blocked_message .= '</ul>';
     282
     283                if ( $can_update ) {
     284                        if ( $this->is_downgrading ) {
     285                                $warning = __( 'You are uploading an older version of a current plugin. You can continue to install the older version, but be sure to <a href="https://wordpress.org/support/article/wordpress-backups/">backup your database and files</a> first.' );
     286                        } else {
     287                                $warning = __( 'You are updating a plugin. Be sure to <a href="https://wordpress.org/support/article/wordpress-backups/">backup your database and files</a> first.' );
     288                        }
     289
     290                        echo '<p class="update-from-upload-notice">' . $warning . '</p>';
     291
     292                        $overwrite = $this->is_downgrading ? 'downgrade-plugin' : 'update-plugin';
     293
     294                        $install_actions['ovewrite_plugin'] = sprintf(
     295                                '<a class="button button-primary" href="%s" target="_parent">%s</a>',
     296                                wp_nonce_url( add_query_arg( 'overwrite', $overwrite, $this->url ), 'plugin-upload' ),
     297                                esc_html( __( 'Replace current with uploaded' ) )
     298                        );
     299                } else {
     300                        echo $blocked_message;
     301                }
     302
     303                $install_actions['plugins_page'] = sprintf(
     304                        '<a class="button" href="%s">%s</a>',
     305                        self_admin_url( 'plugin-install.php' ),
     306                        __( 'Cancel and go back' )
     307                );
     308
     309                /**
     310                 * Filters the list of action links available following a single plugin installation failed but ovewrite is allowed.
     311                 *
     312                 * @since 5.5.0
     313                 *
     314                 * @param string[] $install_actions Array of plugin action links.
     315                 * @param object   $api             Object containing WordPress.org API plugin data.
     316                 * @param array    $new_plugin_data Array with uploaded plugin data.
     317                 */
     318                $install_actions = apply_filters( 'install_plugin_ovewrite_actions', $install_actions, $this->api, $this->upgrader->new_plugin_data );
     319
     320                if ( ! empty( $install_actions ) ) {
     321                        echo '<p class="update-from-upload-actions">' . implode( ' ', (array) $install_actions ) . '</p>';
     322                }
     323
     324                return true;
     325        }
    141326}
Note: See TracChangeset for help on using the changeset viewer.