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-theme-installer-skin.php

    r47219 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                         'theme' => '',
    30                         'nonce' => '',
    31                         'title' => '',
     31                        'type'      => 'web',
     32                        'url'       => '',
     33                        'theme'     => '',
     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 );
     
    5259
    5360        /**
     61         * Hides the `process_failed` error when updating a theme 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        /**
    5481         */
    5582        public function after() {
     83                if ( $this->do_overwrite() ) {
     84                        return;
     85                }
     86
    5687                if ( empty( $this->upgrader->result['destination_name'] ) ) {
    5788                        return;
     
    131162                if ( ! $this->result || is_wp_error( $this->result ) || is_network_admin() || ! current_user_can( 'switch_themes' ) ) {
    132163                        unset( $install_actions['activate'], $install_actions['preview'] );
     164                } elseif ( get_option( 'template' ) === $stylesheet ) {
     165                        unset( $install_actions['activate'] );
    133166                }
    134167
     
    148181                }
    149182        }
     183
     184        /**
     185         * Check if the theme can be overwritten and output the HTML for overwriting a theme on upload.
     186         *
     187         * @since 5.5.0
     188         *
     189         * @return bool Whether the theme can be overwritten and HTML was outputted.
     190         */
     191        private function do_overwrite() {
     192                if ( 'upload' !== $this->type || ! is_wp_error( $this->result ) || 'folder_exists' !== $this->result->get_error_code() ) {
     193                        return false;
     194                }
     195
     196                $folder = $this->result->get_error_data( 'folder_exists' );
     197                $folder = rtrim( $folder, '/' );
     198
     199                $current_theme_data = false;
     200                $all_themes         = wp_get_themes( array( 'errors' => null ) );
     201
     202                foreach ( $all_themes as $theme ) {
     203                        if ( rtrim( $theme->get_stylesheet_directory(), '/' ) !== $folder ) {
     204                                continue;
     205                        }
     206
     207                        $current_theme_data = $theme;
     208                }
     209
     210                if ( empty( $current_theme_data ) || empty( $this->upgrader->new_theme_data ) ) {
     211                        return false;
     212                }
     213
     214                echo '<h2 class="update-from-upload-heading">' . esc_html( __( 'This theme is already installed.' ) ) . '</h2>';
     215
     216                // Check errors for current theme
     217                if ( is_wp_error( $current_theme_data->errors() ) ) {
     218                        $this->feedback( 'current_theme_has_errors', $current_theme_data->errors()->get_error_message() );
     219                }
     220
     221                $this->is_downgrading = version_compare( $current_theme_data['Version'], $this->upgrader->new_theme_data['Version'], '>' );
     222
     223                $is_invalid_parent = false;
     224                if ( ! empty( $this->upgrader->new_theme_data['Template'] ) ) {
     225                        $is_invalid_parent = ! in_array( $this->upgrader->new_theme_data['Template'], array_keys( $all_themes ), true );
     226                }
     227
     228                $rows = array(
     229                        'Name'        => __( 'Theme name' ),
     230                        'Version'     => __( 'Version' ),
     231                        'Author'      => __( 'Author' ),
     232                        'RequiresWP'  => __( 'Required WordPress version' ),
     233                        'RequiresPHP' => __( 'Required PHP version' ),
     234                        'Template'    => __( 'Parent theme' ),
     235                );
     236
     237                $table  = '<table class="update-from-upload-comparison"><tbody>';
     238                $table .= '<tr><th></th><th>' . esc_html( __( 'Current' ) ) . '</th><th>' . esc_html( __( 'Uploaded' ) ) . '</th></tr>';
     239
     240                $is_same_theme = true; // Let's consider only these rows
     241                foreach ( $rows as $field => $label ) {
     242                        $old_value = $current_theme_data->display( $field, false );
     243                        $old_value = $old_value ? $old_value : '-';
     244
     245                        $new_value = ! empty( $this->upgrader->new_theme_data[ $field ] ) ? $this->upgrader->new_theme_data[ $field ] : '-';
     246
     247                        if ( $old_value === $new_value && '-' === $new_value && 'Template' === $field ) {
     248                                continue;
     249                        }
     250
     251                        $is_same_theme = $is_same_theme && ( $old_value === $new_value );
     252
     253                        $diff_field     = ( 'Version' !== $field && $new_value !== $old_value );
     254                        $diff_version   = ( 'Version' === $field && $this->is_downgrading );
     255                        $invalid_parent = false;
     256
     257                        if ( 'Template' === $field && $is_invalid_parent ) {
     258                                $invalid_parent = true;
     259                                $new_value     .= ' ' . __( '(not found)' );
     260                        }
     261
     262                        $table .= '<tr><td class="name-label">' . $label . '</td><td>' . esc_html( $old_value ) . '</td>';
     263                        $table .= ( $diff_field || $diff_version || $invalid_parent ) ? '<td class="warning">' : '<td>';
     264                        $table .= esc_html( $new_value ) . '</td></tr>';
     265                }
     266
     267                $table .= '</tbody></table>';
     268
     269                /**
     270                 * Filters the compare table output for overwrite a theme package on upload.
     271                 *
     272                 * @since 5.5.0
     273                 *
     274                 * @param string   $table               The output table with Name, Version, Author, RequiresWP and RequiresPHP info.
     275                 * @param array    $current_theme_data  Array with current theme data.
     276                 * @param array    $new_theme_data      Array with uploaded theme data.
     277                 */
     278                echo apply_filters( 'install_theme_overwrite_comparison', $table, $current_theme_data, $this->upgrader->new_theme_data );
     279
     280                $install_actions = array();
     281                $can_update      = true;
     282
     283                $blocked_message  = '<p>' . esc_html( __( 'The theme cannot be updated due to the following:' ) ) . '</p>';
     284                $blocked_message .= '<ul class="ul-disc">';
     285
     286                if ( ! empty( $this->upgrader->new_theme_data['RequiresPHP'] ) && version_compare( phpversion(), $this->upgrader->new_theme_data['RequiresPHP'], '<' ) ) {
     287                        $error = sprintf(
     288                                /* translators: 1: Current PHP version, 2: Version required by the uploaded theme. */
     289                                __( 'The PHP version on your server is %1$s, however the uploaded theme requires %2$s.' ),
     290                                phpversion(),
     291                                $this->upgrader->new_theme_data['RequiresPHP']
     292                        );
     293
     294                        $blocked_message .= '<li>' . esc_html( $error ) . '</li>';
     295                        $can_update       = false;
     296                }
     297
     298                if ( ! empty( $this->upgrader->new_theme_data['RequiresWP'] ) && version_compare( $GLOBALS['wp_version'], $this->upgrader->new_theme_data['RequiresWP'], '<' ) ) {
     299                        $error = sprintf(
     300                                /* translators: 1: Current WordPress version, 2: Version required by the uploaded theme. */
     301                                __( 'Your WordPress version is %1$s, however the uploaded theme requires %2$s.' ),
     302                                $GLOBALS['wp_version'],
     303                                $this->upgrader->new_theme_data['RequiresWP']
     304                        );
     305
     306                        $blocked_message .= '<li>' . esc_html( $error ) . '</li>';
     307                        $can_update       = false;
     308                }
     309
     310                $blocked_message .= '</ul>';
     311
     312                if ( $can_update ) {
     313                        if ( $this->is_downgrading ) {
     314                                $warning = __( 'You are uploading an older version of a current theme. 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.' );
     315                        } else {
     316                                $warning = __( 'You are updating a theme. Be sure to <a href="https://wordpress.org/support/article/wordpress-backups/">backup your database and files</a> first.' );
     317                        }
     318
     319                        echo '<p class="update-from-upload-notice">' . $warning . '</p>';
     320
     321                        $overwrite = $this->is_downgrading ? 'downgrade-theme' : 'update-theme';
     322
     323                        $install_actions['ovewrite_theme'] = sprintf(
     324                                '<a class="button button-primary" href="%s" target="_parent">%s</a>',
     325                                wp_nonce_url( add_query_arg( 'overwrite', $overwrite, $this->url ), 'theme-upload' ),
     326                                esc_html( __( 'Replace current with uploaded' ) )
     327                        );
     328                } else {
     329                        echo $blocked_message;
     330                }
     331
     332                $install_actions['themes_page'] = sprintf(
     333                        '<a class="button" href="%s" target="_parent">%s</a>',
     334                        self_admin_url( 'theme-install.php' ),
     335                        __( 'Cancel and go back' )
     336                );
     337
     338                /**
     339                 * Filters the list of action links available following a single theme installation failed but ovewrite is allowed.
     340                 *
     341                 * @since 5.5.0
     342                 *
     343                 * @param string[] $install_actions Array of theme action links.
     344                 * @param object   $api             Object containing WordPress.org API theme data.
     345                 * @param array    $new_theme_data  Array with uploaded theme data.
     346                 */
     347                $install_actions = apply_filters( 'install_theme_ovewrite_actions', $install_actions, $this->api, $this->upgrader->new_theme_data );
     348
     349                if ( ! empty( $install_actions ) ) {
     350                        echo '<p class="update-from-upload-actions">' . implode( ' ', (array) $install_actions ) . '</p>';
     351                }
     352
     353                return true;
     354        }
     355
    150356}
Note: See TracChangeset for help on using the changeset viewer.