WordPress.org

Make WordPress Core


Ignore:
Timestamp:
07/07/2020 05:47:37 PM (13 months 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.