Ticket #9757: 9757.7.patch
File 9757.7.patch, 36.5 KB (added by , 4 years ago) |
---|
-
src/wp-admin/css/themes.css
diff --git src/wp-admin/css/themes.css src/wp-admin/css/themes.css index 127ce2ebca..6136155021 100644
body.folded .theme-browser ~ .theme-overlay .theme-wrap { 984 984 16.2 - Install Themes 985 985 ------------------------------------------------------------------------------*/ 986 986 987 .update-php .wrap { 988 max-width: 40rem; 989 } 990 987 991 /* Already installed theme */ 988 992 .theme-browser .theme .theme-installed { 989 993 background: #0073aa; 990 994 } 995 991 996 .theme-browser .theme .notice-success p:before { 992 997 color: #79ba49; 993 998 content: "\f147"; … … body.folded .theme-browser ~ .theme-overlay .theme-wrap { 1030 1035 overflow: hidden; 1031 1036 position: relative; 1032 1037 top: 10px; 1033 } 1034 1035 .upload-plugin-wrap { 1036 display: none; 1038 text-align: center; 1037 1039 } 1038 1040 1039 1041 .show-upload-view .upload-theme, … … body.folded .theme-browser ~ .theme-overlay .theme-wrap { 1049 1051 border: 1px solid #ccd0d4; 1050 1052 padding: 30px; 1051 1053 margin: 30px auto; 1052 max-width: 380px; 1053 display: flex; 1054 display: inline-flex; 1054 1055 justify-content: space-between; 1055 1056 align-items: center; 1056 1057 } 1057 1058 1059 .upload-theme .wp-upload-form input[type="file"], 1060 .upload-plugin .wp-upload-form input[type="file"] { 1061 margin-right: 10px; 1062 } 1063 1058 1064 .upload-theme .install-help, 1059 1065 .upload-plugin .install-help { 1060 1066 color: #555d66; /* #f1f1f1 background */ … … p.no-themes-local { 1093 1099 .upload-theme .install-help { 1094 1100 font-size: 15px; 1095 1101 padding: 20px 0 0; 1096 text-align: left;1097 1102 } 1098 1103 } 1099 1104 … … p.no-themes-local { 1116 1121 line-height: 1.9; 1117 1122 } 1118 1123 1124 .update-from-upload-comparison { 1125 border-top: 1px solid #ddd; 1126 border-bottom: 1px solid #ddd; 1127 text-align: left; 1128 margin: 1rem 0 1.4rem; 1129 border-collapse: collapse; 1130 width: 100%; 1131 } 1132 1133 .update-from-upload-comparison tr:last-child td { 1134 height: 1.4rem; 1135 vertical-align: top; 1136 } 1137 1138 .update-from-upload-comparison tr:first-child th { 1139 font-weight: bold; 1140 height: 1.4rem; 1141 vertical-align: bottom; 1142 } 1143 1144 .update-from-upload-comparison td.name-label { 1145 text-align: right; 1146 } 1147 1148 .update-from-upload-comparison td, 1149 .update-from-upload-comparison th { 1150 padding: 0.4rem 1.4rem; 1151 } 1152 1153 .update-from-upload-comparison td.warning { 1154 color: #a00; 1155 } 1156 1157 .update-from-upload-actions { 1158 margin-top: 1.4rem; 1159 } 1160 1119 1161 /*------------------------------------------------------------------------------ 1120 1162 16.3 - Custom Header Screen 1121 1163 ------------------------------------------------------------------------------*/ -
src/wp-admin/includes/class-plugin-installer-skin.php
diff --git src/wp-admin/includes/class-plugin-installer-skin.php src/wp-admin/includes/class-plugin-installer-skin.php index cb44919c66..27ca1506f4 100644
18 18 class Plugin_Installer_Skin extends WP_Upgrader_Skin { 19 19 public $api; 20 20 public $type; 21 public $url; 22 public $overwrite; 23 24 private $is_downgrading = false; 21 25 22 26 /** 23 27 * @param array $args 24 28 */ 25 29 public function __construct( $args = array() ) { 26 30 $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' => '', 32 37 ); 33 38 $args = wp_parse_args( $args, $defaults ); 34 39 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']; 37 44 38 45 parent::__construct( $args ); 39 46 } … … class Plugin_Installer_Skin extends WP_Upgrader_Skin { 43 50 public function before() { 44 51 if ( ! empty( $this->api ) ) { 45 52 $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'], 48 54 $this->api->name, 49 55 $this->api->version 50 56 ); 51 57 } 52 58 } 53 59 60 /** 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 54 80 /** 55 81 */ 56 82 public function after() { 83 // Check if the plugin can be overwritten and output the HTML. 84 if ( $this->do_overwrite() ) { 85 return; 86 } 87 57 88 $plugin_file = $this->upgrader->plugin_info(); 58 89 59 90 $install_actions = array(); … … class Plugin_Installer_Skin extends WP_Upgrader_Skin { 117 148 118 149 if ( ! $this->result || is_wp_error( $this->result ) ) { 119 150 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 ) ) { 121 152 unset( $install_actions['activate_plugin'] ); 122 153 } 123 154 … … class Plugin_Installer_Skin extends WP_Upgrader_Skin { 138 169 $this->feedback( implode( ' ', (array) $install_actions ) ); 139 170 } 140 171 } 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 } 141 326 } -
src/wp-admin/includes/class-plugin-upgrader.php
diff --git src/wp-admin/includes/class-plugin-upgrader.php src/wp-admin/includes/class-plugin-upgrader.php index 361b7a5c8d..e6c3715975 100644
class Plugin_Upgrader extends WP_Upgrader { 38 38 */ 39 39 public $bulk = false; 40 40 41 /** 42 * New plugin info. 43 * 44 * @since 5.5.0 45 * @var array $new_plugin_data 46 * 47 * @see check_package() 48 */ 49 public $new_plugin_data = array(); 50 41 51 /** 42 52 * Initialize the upgrade strings. 43 53 * … … class Plugin_Upgrader extends WP_Upgrader { 54 64 $this->strings['process_failed'] = __( 'Plugin update failed.' ); 55 65 $this->strings['process_success'] = __( 'Plugin updated successfully.' ); 56 66 $this->strings['process_bulk_success'] = __( 'Plugins updated successfully.' ); 67 68 /* translators: 1: Plugin name, 2: Plugin version. */ 69 $this->strings['process_success_specific'] = __( 'Successfully installed the plugin <strong>%1$s %2$s</strong>.' ); 57 70 } 58 71 59 72 /** … … class Plugin_Upgrader extends WP_Upgrader { 67 80 $this->strings['downloading_package'] = sprintf( __( 'Downloading installation package from %s…' ), '<span class="code">%s</span>' ); 68 81 $this->strings['unpack_package'] = __( 'Unpacking the package…' ); 69 82 $this->strings['installing_package'] = __( 'Installing the plugin…' ); 83 $this->strings['remove_old'] = __( 'Removing the current plugin…' ); 84 $this->strings['remove_old_failed'] = __( 'Could not remove the current plugin.' ); 70 85 $this->strings['no_files'] = __( 'The plugin contains no files.' ); 71 86 $this->strings['process_failed'] = __( 'Plugin installation failed.' ); 72 87 $this->strings['process_success'] = __( 'Plugin installed successfully.' ); 88 89 if ( ! empty( $this->skin->overwrite ) ) { 90 if ( 'update-plugin' === $this->skin->overwrite ) { 91 $this->strings['installing_package'] = __( 'Updating the plugin…' ); 92 $this->strings['process_failed'] = __( 'Plugin update failed.' ); 93 $this->strings['process_success'] = __( 'Plugin updated successfully.' ); 94 } 95 96 if ( 'downgrade-plugin' === $this->skin->overwrite ) { 97 $this->strings['installing_package'] = __( 'Downgrading the plugin…' ); 98 $this->strings['process_failed'] = __( 'Plugin downgrade failed.' ); 99 $this->strings['process_success'] = __( 'Plugin downgraded successfully.' ); 100 } 101 } 73 102 } 74 103 75 104 /** … … class Plugin_Upgrader extends WP_Upgrader { 88 117 * @return bool|WP_Error True if the installation was successful, false or a WP_Error otherwise. 89 118 */ 90 119 public function install( $package, $args = array() ) { 91 92 120 $defaults = array( 93 121 'clear_update_cache' => true, 122 'overwrite_package' => false, // Do not overwrite files. 94 123 ); 95 124 $parsed_args = wp_parse_args( $args, $defaults ); 96 125 … … class Plugin_Upgrader extends WP_Upgrader { 107 136 array( 108 137 'package' => $package, 109 138 'destination' => WP_PLUGIN_DIR, 110 'clear_destination' => false, // Do not overwrite files.139 'clear_destination' => $parsed_args['overwrite_package'], 111 140 'clear_working' => true, 112 141 'hook_extra' => array( 113 142 'type' => 'plugin', … … class Plugin_Upgrader extends WP_Upgrader { 126 155 // Force refresh of plugin update information. 127 156 wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); 128 157 158 if ( $parsed_args['overwrite_package'] ) { 159 /** 160 * Fires when the upgrader overwrites a currently installed plugin or theme with an uploaded zip package. 161 * 162 * @since 5.5.0 163 * 164 * @param string $package The package file. 165 * @param array $new_plugin_data The new plugin data. 166 * @param string $package_type The package type (plugin or theme). 167 */ 168 do_action( 'upgrader_overwrited_package', $package, $this->new_plugin_data, 'plugin' ); 169 } 170 129 171 return true; 130 172 } 131 173 … … class Plugin_Upgrader extends WP_Upgrader { 145 187 * @return bool|WP_Error True if the upgrade was successful, false or a WP_Error object otherwise. 146 188 */ 147 189 public function upgrade( $plugin, $args = array() ) { 148 149 190 $defaults = array( 150 191 'clear_update_cache' => true, 151 192 ); … … class Plugin_Upgrader extends WP_Upgrader { 223 264 * @return array|false An array of results indexed by plugin file, or false if unable to connect to the filesystem. 224 265 */ 225 266 public function bulk_upgrade( $plugins, $args = array() ) { 226 227 267 $defaults = array( 228 268 'clear_update_cache' => true, 229 269 ); … … class Plugin_Upgrader extends WP_Upgrader { 349 389 public function check_package( $source ) { 350 390 global $wp_filesystem; 351 391 392 $this->new_plugin_data = array(); 393 352 394 if ( is_wp_error( $source ) ) { 353 395 return $source; 354 396 } … … class Plugin_Upgrader extends WP_Upgrader { 359 401 } 360 402 361 403 // Check that the folder contains at least 1 valid plugin. 362 $plugins_found = false; 363 $files = glob( $working_directory . '*.php' ); 404 $files = glob( $working_directory . '*.php' ); 364 405 if ( $files ) { 365 406 foreach ( $files as $file ) { 366 407 $info = get_plugin_data( $file, false, false ); 367 408 if ( ! empty( $info['Name'] ) ) { 368 $ plugins_found = true;409 $this->new_plugin_data = $info; 369 410 break; 370 411 } 371 412 } 372 413 } 373 414 374 if ( ! $plugins_found) {415 if ( empty( $this->new_plugin_data ) ) { 375 416 return new WP_Error( 'incompatible_archive_no_plugins', $this->strings['incompatible_archive'], __( 'No valid plugins were found.' ) ); 376 417 } 377 418 -
src/wp-admin/includes/class-theme-installer-skin.php
diff --git src/wp-admin/includes/class-theme-installer-skin.php src/wp-admin/includes/class-theme-installer-skin.php index f568766086..3032237cfe 100644
18 18 class Theme_Installer_Skin extends WP_Upgrader_Skin { 19 19 public $api; 20 20 public $type; 21 public $url; 22 public $overwrite; 23 24 private $is_downgrading = false; 21 25 22 26 /** 23 27 * @param array $args 24 28 */ 25 29 public function __construct( $args = array() ) { 26 30 $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' => '', 32 37 ); 33 38 $args = wp_parse_args( $args, $defaults ); 34 39 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']; 37 44 38 45 parent::__construct( $args ); 39 46 } … … class Theme_Installer_Skin extends WP_Upgrader_Skin { 50 57 } 51 58 } 52 59 60 /** 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 53 80 /** 54 81 */ 55 82 public function after() { 83 if ( $this->do_overwrite() ) { 84 return; 85 } 86 56 87 if ( empty( $this->upgrader->result['destination_name'] ) ) { 57 88 return; 58 89 } … … class Theme_Installer_Skin extends WP_Upgrader_Skin { 130 161 131 162 if ( ! $this->result || is_wp_error( $this->result ) || is_network_admin() || ! current_user_can( 'switch_themes' ) ) { 132 163 unset( $install_actions['activate'], $install_actions['preview'] ); 164 } elseif ( get_option( 'template' ) === $stylesheet ) { 165 unset( $install_actions['activate'] ); 133 166 } 134 167 135 168 /** … … class Theme_Installer_Skin extends WP_Upgrader_Skin { 147 180 $this->feedback( implode( ' | ', (array) $install_actions ) ); 148 181 } 149 182 } 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 150 356 } -
src/wp-admin/includes/class-theme-upgrader.php
diff --git src/wp-admin/includes/class-theme-upgrader.php src/wp-admin/includes/class-theme-upgrader.php index d5da2344c7..172f6907b1 100644
class Theme_Upgrader extends WP_Upgrader { 37 37 */ 38 38 public $bulk = false; 39 39 40 /** 41 * New theme info. 42 * 43 * @since 5.5.0 44 * @var array $new_theme_data 45 * 46 * @see check_package() 47 */ 48 public $new_theme_data = array(); 49 40 50 /** 41 51 * Initialize the upgrade strings. 42 52 * … … class Theme_Upgrader extends WP_Upgrader { 65 75 $this->strings['downloading_package'] = sprintf( __( 'Downloading installation package from %s…' ), '<span class="code">%s</span>' ); 66 76 $this->strings['unpack_package'] = __( 'Unpacking the package…' ); 67 77 $this->strings['installing_package'] = __( 'Installing the theme…' ); 78 $this->strings['remove_old'] = __( 'Removing the old version of the theme…' ); 79 $this->strings['remove_old_failed'] = __( 'Could not remove the old theme.' ); 68 80 $this->strings['no_files'] = __( 'The theme contains no files.' ); 69 81 $this->strings['process_failed'] = __( 'Theme installation failed.' ); 70 82 $this->strings['process_success'] = __( 'Theme installed successfully.' ); … … class Theme_Upgrader extends WP_Upgrader { 79 91 $this->strings['parent_theme_install_success'] = __( 'Successfully installed the parent theme, <strong>%1$s %2$s</strong>.' ); 80 92 /* translators: %s: Theme name. */ 81 93 $this->strings['parent_theme_not_found'] = sprintf( __( '<strong>The parent theme could not be found.</strong> You will need to install the parent theme, %s, before you can use this child theme.' ), '<strong>%s</strong>' ); 94 /* translators: %s: Theme error. */ 95 $this->strings['current_theme_has_errors'] = __( 'The current theme has the follow error: "%s".' ); 96 97 if ( 'update-theme' === $this->skin->overwrite ) { 98 $this->strings['installing_package'] = __( 'Updating the theme…' ); 99 $this->strings['process_failed'] = __( 'Theme update failed.' ); 100 $this->strings['process_success'] = __( 'Theme updated successfully.' ); 101 } 102 103 if ( 'downgrade-theme' === $this->skin->overwrite ) { 104 $this->strings['installing_package'] = __( 'Downgrading the theme…' ); 105 $this->strings['process_failed'] = __( 'Theme downgrade failed.' ); 106 $this->strings['process_success'] = __( 'Theme downgraded successfully.' ); 107 } 82 108 } 83 109 84 110 /** … … class Theme_Upgrader extends WP_Upgrader { 200 226 * @return bool|WP_Error True if the installation was successful, false or a WP_Error object otherwise. 201 227 */ 202 228 public function install( $package, $args = array() ) { 203 204 229 $defaults = array( 205 230 'clear_update_cache' => true, 231 'overwrite_package' => false, // Do not overwrite files. 206 232 ); 207 233 $parsed_args = wp_parse_args( $args, $defaults ); 208 234 … … class Theme_Upgrader extends WP_Upgrader { 220 246 array( 221 247 'package' => $package, 222 248 'destination' => get_theme_root(), 223 'clear_destination' => false, // Do not overwrite files.249 'clear_destination' => $args['overwrite_package'], 224 250 'clear_working' => true, 225 251 'hook_extra' => array( 226 252 'type' => 'theme', … … class Theme_Upgrader extends WP_Upgrader { 240 266 // Refresh the Theme Update information. 241 267 wp_clean_themes_cache( $parsed_args['clear_update_cache'] ); 242 268 269 if ( $parsed_args['overwrite_package'] ) { 270 /** 271 * Fires when the upgrader overwrites a currently installed plugin or theme with an uploaded zip package. 272 * 273 * @since 5.5.0 274 * 275 * @param string $package The package file. 276 * @param array $new_plugin_data The new theme data. 277 * @param string $package_type The package type (theme or theme). 278 */ 279 do_action( 'upgrader_overwrited_package', $package, $this->new_theme_data, 'theme' ); 280 } 281 243 282 return true; 244 283 } 245 284 … … class Theme_Upgrader extends WP_Upgrader { 259 298 * @return bool|WP_Error True if the upgrade was successful, false or a WP_Error object otherwise. 260 299 */ 261 300 public function upgrade( $theme, $args = array() ) { 262 263 301 $defaults = array( 264 302 'clear_update_cache' => true, 265 303 ); … … class Theme_Upgrader extends WP_Upgrader { 332 370 * @return array[]|false An array of results, or false if unable to connect to the filesystem. 333 371 */ 334 372 public function bulk_upgrade( $themes, $args = array() ) { 335 336 373 $defaults = array( 337 374 'clear_update_cache' => true, 338 375 ); … … class Theme_Upgrader extends WP_Upgrader { 461 498 public function check_package( $source ) { 462 499 global $wp_filesystem; 463 500 501 $this->new_theme_data = array(); 502 464 503 if ( is_wp_error( $source ) ) { 465 504 return $source; 466 505 } … … class Theme_Upgrader extends WP_Upgrader { 484 523 ); 485 524 } 486 525 526 // All these headers are needed on Theme_Installer_Skin::do_overwrite(). 487 527 $info = get_file_data( 488 528 $working_directory . 'style.css', 489 529 array( 490 'Name' => 'Theme Name', 491 'Template' => 'Template', 530 'Name' => 'Theme Name', 531 'Version' => 'Version', 532 'Author' => 'Author', 533 'Template' => 'Template', 534 'RequiresWP' => 'Requires at least', 535 'RequiresPHP' => 'Requires PHP', 492 536 ) 493 537 ); 494 538 … … class Theme_Upgrader extends WP_Upgrader { 517 561 ); 518 562 } 519 563 564 $this->new_theme_data = $info; 520 565 return $source; 521 566 } 522 567 … … class Theme_Upgrader extends WP_Upgrader { 640 685 * and the last result isn't set. 641 686 */ 642 687 public function theme_info( $theme = null ) { 643 644 688 if ( empty( $theme ) ) { 645 689 if ( ! empty( $this->result['destination_name'] ) ) { 646 690 $theme = $this->result['destination_name']; … … class Theme_Upgrader extends WP_Upgrader { 648 692 return false; 649 693 } 650 694 } 651 return wp_get_theme( $theme ); 695 696 $theme = wp_get_theme( $theme ); 697 $theme->cache_delete(); 698 699 return $theme; 652 700 } 653 701 654 702 } -
src/wp-admin/includes/class-wp-upgrader-skin.php
diff --git src/wp-admin/includes/class-wp-upgrader-skin.php src/wp-admin/includes/class-wp-upgrader-skin.php index e776076d64..26a77ec39a 100644
class WP_Upgrader_Skin { 205 205 /** 206 206 */ 207 207 public function bulk_footer() {} 208 209 /** 210 * Hides the `process_failed` error message when updating by uploading a zip file. 211 * 212 * @since 5.5.0 213 * 214 * @param $wp_error WP_Error 215 * @return bool 216 */ 217 public function hide_process_failed( $wp_error ) { 218 return false; 219 } 208 220 } -
src/wp-admin/includes/class-wp-upgrader.php
diff --git src/wp-admin/includes/class-wp-upgrader.php src/wp-admin/includes/class-wp-upgrader.php index f29eb6cfcd..1a63096892 100644
class WP_Upgrader { 798 798 $this->skin->set_result( $result ); 799 799 if ( is_wp_error( $result ) ) { 800 800 $this->skin->error( $result ); 801 $this->skin->feedback( 'process_failed' ); 801 802 if ( ! method_exists( $this->skin, 'hide_process_failed' ) || ! $this->skin->hide_process_failed( $result ) ) { 803 $this->skin->feedback( 'process_failed' ); 804 } 802 805 } else { 803 806 // Installation succeeded. 804 807 $this->skin->feedback( 'process_success' ); -
src/wp-admin/includes/plugin-install.php
diff --git src/wp-admin/includes/plugin-install.php src/wp-admin/includes/plugin-install.php index c8f3406f7b..dac564bfa2 100644
function install_plugins_upload() { 353 353 <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url( 'update.php?action=upload-plugin' ); ?>"> 354 354 <?php wp_nonce_field( 'plugin-upload' ); ?> 355 355 <label class="screen-reader-text" for="pluginzip"><?php _e( 'Plugin zip file' ); ?></label> 356 <input type="file" id="pluginzip" name="pluginzip" />356 <input type="file" id="pluginzip" name="pluginzip" accept=".zip" /> 357 357 <?php submit_button( __( 'Install Now' ), '', 'install-plugin-submit', false ); ?> 358 358 </form> 359 359 </div> -
src/wp-admin/includes/theme-install.php
diff --git src/wp-admin/includes/theme-install.php src/wp-admin/includes/theme-install.php index 267ae26a94..bbc132ff4c 100644
function install_themes_upload() { 183 183 <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url( 'update.php?action=upload-theme' ); ?>"> 184 184 <?php wp_nonce_field( 'theme-upload' ); ?> 185 185 <label class="screen-reader-text" for="themezip"><?php _e( 'Theme zip file' ); ?></label> 186 <input type="file" id="themezip" name="themezip" />186 <input type="file" id="themezip" name="themezip" accept=".zip"/> 187 187 <?php submit_button( __( 'Install Now' ), '', 'install-theme-submit', false ); ?> 188 188 </form> 189 189 <?php -
src/wp-admin/update.php
diff --git src/wp-admin/update.php src/wp-admin/update.php index 8cb0cf44b8..efd96f26ca 100644
if ( isset( $_GET['action'] ) ) { 162 162 $url = add_query_arg( array( 'package' => $file_upload->id ), 'update.php?action=upload-plugin' ); 163 163 $type = 'upload'; // Install plugin type, From Web or an Upload. 164 164 165 $upgrader = new Plugin_Upgrader( new Plugin_Installer_Skin( compact( 'type', 'title', 'nonce', 'url' ) ) ); 166 $result = $upgrader->install( $file_upload->package ); 165 $overwrite = isset( $_GET['overwrite'] ) ? sanitize_text_field( $_GET['overwrite'] ) : ''; 166 $overwrite = in_array( $overwrite, array( 'update-plugin', 'downgrade-plugin' ), true ) ? $overwrite : ''; 167 168 $upgrader = new Plugin_Upgrader( new Plugin_Installer_Skin( compact( 'type', 'title', 'nonce', 'url', 'overwrite' ) ) ); 169 $result = $upgrader->install( $file_upload->package, array( 'overwrite_package' => $overwrite ) ); 167 170 168 171 if ( $result || is_wp_error( $result ) ) { 169 172 $file_upload->cleanup(); … … if ( isset( $_GET['action'] ) ) { 282 285 $url = add_query_arg( array( 'package' => $file_upload->id ), 'update.php?action=upload-theme' ); 283 286 $type = 'upload'; // Install theme type, From Web or an Upload. 284 287 285 $upgrader = new Theme_Upgrader( new Theme_Installer_Skin( compact( 'type', 'title', 'nonce', 'url' ) ) ); 286 $result = $upgrader->install( $file_upload->package ); 288 $overwrite = isset( $_GET['overwrite'] ) ? sanitize_text_field( $_GET['overwrite'] ) : ''; 289 $overwrite = in_array( $overwrite, array( 'update-theme', 'downgrade-theme' ), true ) ? $overwrite : ''; 290 291 $upgrader = new Theme_Upgrader( new Theme_Installer_Skin( compact( 'type', 'title', 'nonce', 'url', 'overwrite' ) ) ); 292 $result = $upgrader->install( $file_upload->package, array( 'overwrite_package' => $overwrite ) ); 287 293 288 294 if ( $result || is_wp_error( $result ) ) { 289 295 $file_upload->cleanup();