<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[48390] trunk/src/wp-admin: Upgrade/install: Allow plugin and theme updates from a uploaded .zip file.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/48390">48390</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/48390","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>azaozz</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2020-07-07 17:47:37 +0000 (Tue, 07 Jul 2020)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>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 <a href="https://core.trac.wordpress.org/ticket/9757">#9757</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadmincssthemescss">trunk/src/wp-admin/css/themes.css</a></li>
<li><a href="#trunksrcwpadminincludesclassplugininstallerskinphp">trunk/src/wp-admin/includes/class-plugin-installer-skin.php</a></li>
<li><a href="#trunksrcwpadminincludesclasspluginupgraderphp">trunk/src/wp-admin/includes/class-plugin-upgrader.php</a></li>
<li><a href="#trunksrcwpadminincludesclassthemeinstallerskinphp">trunk/src/wp-admin/includes/class-theme-installer-skin.php</a></li>
<li><a href="#trunksrcwpadminincludesclassthemeupgraderphp">trunk/src/wp-admin/includes/class-theme-upgrader.php</a></li>
<li><a href="#trunksrcwpadminincludesclasswpupgraderskinphp">trunk/src/wp-admin/includes/class-wp-upgrader-skin.php</a></li>
<li><a href="#trunksrcwpadminincludesclasswpupgraderphp">trunk/src/wp-admin/includes/class-wp-upgrader.php</a></li>
<li><a href="#trunksrcwpadminincludesplugininstallphp">trunk/src/wp-admin/includes/plugin-install.php</a></li>
<li><a href="#trunksrcwpadminincludesthemeinstallphp">trunk/src/wp-admin/includes/theme-install.php</a></li>
<li><a href="#trunksrcwpadminupdatephp">trunk/src/wp-admin/update.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadmincssthemescss"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/css/themes.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/css/themes.css 2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/css/themes.css   2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -984,10 +984,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">   16.2 - Install Themes
</span><span class="cx" style="display: block; padding: 0 10px"> ------------------------------------------------------------------------------*/
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.update-php .wrap {
+       max-width: 40rem;
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /* Already installed theme */
</span><span class="cx" style="display: block; padding: 0 10px"> .theme-browser .theme .theme-installed {
</span><span class="cx" style="display: block; padding: 0 10px">        background: #0073aa;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .theme-browser .theme .notice-success p:before {
</span><span class="cx" style="display: block; padding: 0 10px">        color: #79ba49;
</span><span class="cx" style="display: block; padding: 0 10px">        content: "\f147";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1030,12 +1035,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">        overflow: hidden;
</span><span class="cx" style="display: block; padding: 0 10px">        position: relative;
</span><span class="cx" style="display: block; padding: 0 10px">        top: 10px;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        text-align: center;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.upload-plugin-wrap {
-       display: none;
-}
-
</del><span class="cx" style="display: block; padding: 0 10px"> .show-upload-view .upload-theme,
</span><span class="cx" style="display: block; padding: 0 10px"> .show-upload-view .upload-plugin,
</span><span class="cx" style="display: block; padding: 0 10px"> .show-upload-view .upload-plugin-wrap,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1049,12 +1051,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">        border: 1px solid #ccd0d4;
</span><span class="cx" style="display: block; padding: 0 10px">        padding: 30px;
</span><span class="cx" style="display: block; padding: 0 10px">        margin: 30px auto;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        max-width: 380px;
-       display: flex;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ display: inline-flex;
</ins><span class="cx" style="display: block; padding: 0 10px">         justify-content: space-between;
</span><span class="cx" style="display: block; padding: 0 10px">        align-items: center;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.upload-theme .wp-upload-form input[type="file"],
+.upload-plugin .wp-upload-form input[type="file"] {
+       margin-right: 10px;
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> .upload-theme .install-help,
</span><span class="cx" style="display: block; padding: 0 10px"> .upload-plugin .install-help {
</span><span class="cx" style="display: block; padding: 0 10px">        color: #555d66; /* #f1f1f1 background */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1093,7 +1099,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        .upload-theme .install-help {
</span><span class="cx" style="display: block; padding: 0 10px">                font-size: 15px;
</span><span class="cx" style="display: block; padding: 0 10px">                padding: 20px 0 0;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                text-align: left;
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1116,6 +1121,43 @@
</span><span class="cx" style="display: block; padding: 0 10px">        line-height: 1.9;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.update-from-upload-comparison {
+       border-top: 1px solid #ddd;
+       border-bottom: 1px solid #ddd;
+       text-align: left;
+       margin: 1rem 0 1.4rem;
+       border-collapse: collapse;
+       width: 100%;
+}
+
+.update-from-upload-comparison tr:last-child td {
+       height: 1.4rem;
+    vertical-align: top;
+}
+
+.update-from-upload-comparison tr:first-child th {
+       font-weight: bold;
+       height: 1.4rem;
+    vertical-align: bottom;
+}
+
+.update-from-upload-comparison td.name-label {
+       text-align: right;
+}
+
+.update-from-upload-comparison td,
+.update-from-upload-comparison th {
+       padding: 0.4rem 1.4rem;
+}
+
+.update-from-upload-comparison td.warning {
+       color: #a00;
+}
+
+.update-from-upload-actions {
+       margin-top: 1.4rem;
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /*------------------------------------------------------------------------------
</span><span class="cx" style="display: block; padding: 0 10px">   16.3 - Custom Header Screen
</span><span class="cx" style="display: block; padding: 0 10px"> ------------------------------------------------------------------------------*/
</span></span></pre></div>
<a id="trunksrcwpadminincludesclassplugininstallerskinphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/class-plugin-installer-skin.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-plugin-installer-skin.php       2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/includes/class-plugin-installer-skin.php 2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -18,22 +18,29 @@
</span><span class="cx" style="display: block; padding: 0 10px"> class Plugin_Installer_Skin extends WP_Upgrader_Skin {
</span><span class="cx" style="display: block; padding: 0 10px">        public $api;
</span><span class="cx" style="display: block; padding: 0 10px">        public $type;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        public $url;
+       public $overwrite;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        private $is_downgrading = false;
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><span class="cx" style="display: block; padding: 0 10px">         * @param array $args
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function __construct( $args = array() ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $defaults = array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        'type'   => 'web',
-                       'url'    => '',
-                       'plugin' => '',
-                       'nonce'  => '',
-                       'title'  => '',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 'type'      => 'web',
+                       'url'       => '',
+                       'plugin'    => '',
+                       'nonce'     => '',
+                       'title'     => '',
+                       'overwrite' => '',
</ins><span class="cx" style="display: block; padding: 0 10px">                 );
</span><span class="cx" style="display: block; padding: 0 10px">                $args     = wp_parse_args( $args, $defaults );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->type = $args['type'];
-               $this->api  = isset( $args['api'] ) ? $args['api'] : array();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->type      = $args['type'];
+               $this->url       = $args['url'];
+               $this->api       = isset( $args['api'] ) ? $args['api'] : array();
+               $this->overwrite = $args['overwrite'];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                parent::__construct( $args );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -43,8 +50,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public function before() {
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! empty( $this->api ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->upgrader->strings['process_success'] = sprintf(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                /* translators: 1: Plugin name, 2: Plugin version. */
-                               __( 'Successfully installed the plugin <strong>%1$s %2$s</strong>.' ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $this->upgrader->strings['process_success_specific'],
</ins><span class="cx" style="display: block; padding: 0 10px">                                 $this->api->name,
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->api->version
</span><span class="cx" style="display: block; padding: 0 10px">                        );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -52,8 +58,33 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Hides the `process_failed` error when updating a plugin by uploading a zip file.
+        *
+        * @since 5.5.0
+        *
+        * @param $wp_error WP_Error.
+        * @return bool
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        public function hide_process_failed( $wp_error ) {
+               if (
+                       'upload' === $this->type &&
+                       '' === $this->overwrite &&
+                       $wp_error->get_error_code() === 'folder_exists'
+               ) {
+                       return true;
+               }
+
+               return false;
+       }
+
+       /**
+        */
</ins><span class="cx" style="display: block; padding: 0 10px">         public function after() {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Check if the plugin can be overwritten and output the HTML.
+               if ( $this->do_overwrite() ) {
+                       return;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $plugin_file = $this->upgrader->plugin_info();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $install_actions = array();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -117,7 +148,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! $this->result || is_wp_error( $this->result ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        unset( $install_actions['activate_plugin'], $install_actions['network_activate'] );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                } elseif ( ! current_user_can( 'activate_plugin', $plugin_file ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         } elseif ( ! current_user_can( 'activate_plugin', $plugin_file ) || is_plugin_active( $plugin_file ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         unset( $install_actions['activate_plugin'] );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -138,4 +169,158 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->feedback( implode( ' ', (array) $install_actions ) );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * Check if the plugin can be overwritten and output the HTML for overwriting a plugin on upload.
+        *
+        * @since 5.5.0
+        *
+        * @return bool Whether the plugin can be overwritten and HTML was outputted.
+        */
+       private function do_overwrite() {
+               if ( 'upload' !== $this->type || ! is_wp_error( $this->result ) || 'folder_exists' !== $this->result->get_error_code() ) {
+                       return false;
+               }
+
+               $folder = $this->result->get_error_data( 'folder_exists' );
+               $folder = ltrim( substr( $folder, strlen( WP_PLUGIN_DIR ) ), '/' );
+
+               $current_plugin_data = false;
+               foreach ( get_plugins() as $plugin => $plugin_data ) {
+                       if ( strrpos( $plugin, $folder ) !== 0 ) {
+                               continue;
+                       }
+
+                       $current_plugin_data = $plugin_data;
+               }
+
+               if ( empty( $current_plugin_data ) || empty( $this->upgrader->new_plugin_data ) ) {
+                       return false;
+               }
+
+               echo '<h2 class="update-from-upload-heading">' . esc_html( __( 'This plugin is already installed.' ) ) . '</h2>';
+
+               $this->is_downgrading = version_compare( $current_plugin_data['Version'], $this->upgrader->new_plugin_data['Version'], '>' );
+
+               $rows = array(
+                       'Name'        => __( 'Plugin name' ),
+                       'Version'     => __( 'Version' ),
+                       'Author'      => __( 'Author' ),
+                       'RequiresWP'  => __( 'Required WordPress version' ),
+                       'RequiresPHP' => __( 'Required PHP version' ),
+               );
+
+               $table  = '<table class="update-from-upload-comparison"><tbody>';
+               $table .= '<tr><th></th><th>' . esc_html( __( 'Current' ) ) . '</th>';
+               $table .= '<th>' . esc_html( __( 'Uploaded' ) ) . '</th></tr>';
+
+               $is_same_plugin = true; // Let's consider only these rows
+               foreach ( $rows as $field => $label ) {
+                       $old_value = ! empty( $current_plugin_data[ $field ] ) ? $current_plugin_data[ $field ] : '-';
+                       $new_value = ! empty( $this->upgrader->new_plugin_data[ $field ] ) ? $this->upgrader->new_plugin_data[ $field ] : '-';
+
+                       $is_same_plugin = $is_same_plugin && ( $old_value === $new_value );
+
+                       $diff_field   = ( 'Version' !== $field && $new_value !== $old_value );
+                       $diff_version = ( 'Version' === $field && $this->is_downgrading );
+
+                       $table .= '<tr><td class="name-label">' . $label . '</td><td>' . esc_html( $old_value ) . '</td>';
+                       $table .= ( $diff_field || $diff_version ) ? '<td class="warning">' : '<td>';
+                       $table .= esc_html( $new_value ) . '</td></tr>';
+               }
+
+               $table .= '</tbody></table>';
+
+               /**
+                * Filters the compare table output for overwrite a plugin package on upload.
+                *
+                * @since 5.5.0
+                *
+                * @param string   $table                The output table with Name, Version, Author, RequiresWP and RequiresPHP info.
+                * @param array    $current_plugin_data  Array with current plugin data.
+                * @param array    $new_plugin_data      Array with uploaded plugin data.
+                */
+               echo apply_filters( 'install_plugin_ovewrite_comparison', $table, $current_plugin_data, $this->upgrader->new_plugin_data );
+
+               $install_actions = array();
+               $can_update      = true;
+
+               $blocked_message  = '<p>' . esc_html( __( 'The plugin cannot be updated due to the following:' ) ) . '</p>';
+               $blocked_message .= '<ul class="ul-disc">';
+
+               if (
+                       ! empty( $this->upgrader->new_plugin_data['RequiresPHP'] ) &&
+                       version_compare( phpversion(), $this->upgrader->new_plugin_data['RequiresPHP'], '<' )
+               ) {
+                       $error = sprintf(
+                               /* translators: 1: Current PHP version, 2: Version required by the uploaded plugin. */
+                               __( 'The PHP version on your server is %1$s, however the uploaded plugin requires %2$s.' ),
+                               phpversion(),
+                               $this->upgrader->new_plugin_data['RequiresPHP']
+                       );
+
+                       $blocked_message .= '<li>' . esc_html( $error ) . '</li>';
+                       $can_update       = false;
+               }
+
+               if (
+                       ! empty( $this->upgrader->new_plugin_data['RequiresWP'] ) &&
+                       version_compare( $GLOBALS['wp_version'], $this->upgrader->new_plugin_data['RequiresWP'], '<' )
+               ) {
+                       $error = sprintf(
+                               /* translators: 1: Current WordPress version, 2: Version required by the uploaded plugin. */
+                               __( 'Your WordPress version is %1$s, however the uploaded plugin requires %2$s.' ),
+                               $GLOBALS['wp_version'],
+                               $this->upgrader->new_plugin_data['RequiresWP']
+                       );
+
+                       $blocked_message .= '<li>' . esc_html( $error ) . '</li>';
+                       $can_update       = false;
+               }
+
+               $blocked_message .= '</ul>';
+
+               if ( $can_update ) {
+                       if ( $this->is_downgrading ) {
+                               $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.' );
+                       } else {
+                               $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.' );
+                       }
+
+                       echo '<p class="update-from-upload-notice">' . $warning . '</p>';
+
+                       $overwrite = $this->is_downgrading ? 'downgrade-plugin' : 'update-plugin';
+
+                       $install_actions['ovewrite_plugin'] = sprintf(
+                               '<a class="button button-primary" href="%s" target="_parent">%s</a>',
+                               wp_nonce_url( add_query_arg( 'overwrite', $overwrite, $this->url ), 'plugin-upload' ),
+                               esc_html( __( 'Replace current with uploaded' ) )
+                       );
+               } else {
+                       echo $blocked_message;
+               }
+
+               $install_actions['plugins_page'] = sprintf(
+                       '<a class="button" href="%s">%s</a>',
+                       self_admin_url( 'plugin-install.php' ),
+                       __( 'Cancel and go back' )
+               );
+
+               /**
+                * Filters the list of action links available following a single plugin installation failed but ovewrite is allowed.
+                *
+                * @since 5.5.0
+                *
+                * @param string[] $install_actions Array of plugin action links.
+                * @param object   $api             Object containing WordPress.org API plugin data.
+                * @param array    $new_plugin_data Array with uploaded plugin data.
+                */
+               $install_actions = apply_filters( 'install_plugin_ovewrite_actions', $install_actions, $this->api, $this->upgrader->new_plugin_data );
+
+               if ( ! empty( $install_actions ) ) {
+                       echo '<p class="update-from-upload-actions">' . implode( ' ', (array) $install_actions ) . '</p>';
+               }
+
+               return true;
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunksrcwpadminincludesclasspluginupgraderphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/class-plugin-upgrader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-plugin-upgrader.php     2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/includes/class-plugin-upgrader.php       2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -39,6 +39,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public $bulk = false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * New plugin info.
+        *
+        * @since 5.5.0
+        * @var array $new_plugin_data
+        *
+        * @see check_package()
+        */
+       public $new_plugin_data = array();
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Initialize the upgrade strings.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 2.8.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -54,6 +64,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['process_failed']       = __( 'Plugin update failed.' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['process_success']      = __( 'Plugin updated successfully.' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['process_bulk_success'] = __( 'Plugins updated successfully.' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               /* translators: 1: Plugin name, 2: Plugin version. */
+               $this->strings['process_success_specific'] = __( 'Successfully installed the plugin <strong>%1$s %2$s</strong>.' );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -67,9 +80,25 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['downloading_package'] = sprintf( __( 'Downloading installation package from %s&#8230;' ), '<span class="code">%s</span>' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['unpack_package']      = __( 'Unpacking the package&#8230;' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['installing_package']  = __( 'Installing the plugin&#8230;' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->strings['remove_old']          = __( 'Removing the current plugin&#8230;' );
+               $this->strings['remove_old_failed']   = __( 'Could not remove the current plugin.' );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->strings['no_files']            = __( 'The plugin contains no files.' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['process_failed']      = __( 'Plugin installation failed.' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['process_success']     = __( 'Plugin installed successfully.' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               if ( ! empty( $this->skin->overwrite ) ) {
+                       if ( 'update-plugin' === $this->skin->overwrite ) {
+                               $this->strings['installing_package'] = __( 'Updating the plugin&#8230;' );
+                               $this->strings['process_failed']     = __( 'Plugin update failed.' );
+                               $this->strings['process_success']    = __( 'Plugin updated successfully.' );
+                       }
+
+                       if ( 'downgrade-plugin' === $this->skin->overwrite ) {
+                               $this->strings['installing_package'] = __( 'Downgrading the plugin&#8230;' );
+                               $this->strings['process_failed']     = __( 'Plugin downgrade failed.' );
+                               $this->strings['process_success']    = __( 'Plugin downgraded successfully.' );
+                       }
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -88,9 +117,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return bool|WP_Error True if the installation was successful, false or a WP_Error otherwise.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function install( $package, $args = array() ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 $defaults    = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'clear_update_cache' => true,
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'overwrite_package'  => false, // Do not overwrite files.
</ins><span class="cx" style="display: block; padding: 0 10px">                 );
</span><span class="cx" style="display: block; padding: 0 10px">                $parsed_args = wp_parse_args( $args, $defaults );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -107,7 +136,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'package'           => $package,
</span><span class="cx" style="display: block; padding: 0 10px">                                'destination'       => WP_PLUGIN_DIR,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'clear_destination' => false, // Do not overwrite files.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'clear_destination' => $parsed_args['overwrite_package'],
</ins><span class="cx" style="display: block; padding: 0 10px">                                 'clear_working'     => true,
</span><span class="cx" style="display: block; padding: 0 10px">                                'hook_extra'        => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'type'   => 'plugin',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -126,6 +155,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // Force refresh of plugin update information.
</span><span class="cx" style="display: block; padding: 0 10px">                wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( $parsed_args['overwrite_package'] ) {
+                       /**
+                        * Fires when the upgrader has successfully overwritten a currently installed
+                        * plugin or theme with an uploaded zip package.
+                        *
+                        * @since 5.5.0
+                        *
+                        * @param string  $package          The package file.
+                        * @param array   $new_plugin_data  The new plugin data.
+                        * @param string  $package_type     The package type (plugin or theme).
+                        */
+                       do_action( 'upgrader_overwrote_package', $package, $this->new_plugin_data, 'plugin' );
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 return true;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -145,7 +188,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return bool|WP_Error True if the upgrade was successful, false or a WP_Error object otherwise.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function upgrade( $plugin, $args = array() ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 $defaults    = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'clear_update_cache' => true,
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -223,7 +265,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return array|false An array of results indexed by plugin file, or false if unable to connect to the filesystem.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function bulk_upgrade( $plugins, $args = array() ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 $defaults    = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'clear_update_cache' => true,
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -349,6 +390,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public function check_package( $source ) {
</span><span class="cx" style="display: block; padding: 0 10px">                global $wp_filesystem;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->new_plugin_data = array();
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( is_wp_error( $source ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        return $source;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -359,19 +402,18 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Check that the folder contains at least 1 valid plugin.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $plugins_found = false;
-               $files         = glob( $working_directory . '*.php' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $files = glob( $working_directory . '*.php' );
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( $files ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        foreach ( $files as $file ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $info = get_plugin_data( $file, false, false );
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( ! empty( $info['Name'] ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        $plugins_found = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 $this->new_plugin_data = $info;
</ins><span class="cx" style="display: block; padding: 0 10px">                                         break;
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( ! $plugins_found ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( empty( $this->new_plugin_data ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         return new WP_Error( 'incompatible_archive_no_plugins', $this->strings['incompatible_archive'], __( 'No valid plugins were found.' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpadminincludesclassthemeinstallerskinphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/class-theme-installer-skin.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-theme-installer-skin.php        2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/includes/class-theme-installer-skin.php  2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -18,22 +18,29 @@
</span><span class="cx" style="display: block; padding: 0 10px"> class Theme_Installer_Skin extends WP_Upgrader_Skin {
</span><span class="cx" style="display: block; padding: 0 10px">        public $api;
</span><span class="cx" style="display: block; padding: 0 10px">        public $type;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        public $url;
+       public $overwrite;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        private $is_downgrading = false;
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><span class="cx" style="display: block; padding: 0 10px">         * @param array $args
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function __construct( $args = array() ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $defaults = array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        'type'  => 'web',
-                       'url'   => '',
-                       'theme' => '',
-                       'nonce' => '',
-                       'title' => '',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 'type'      => 'web',
+                       'url'       => '',
+                       'theme'     => '',
+                       'nonce'     => '',
+                       'title'     => '',
+                       'overwrite' => '',
</ins><span class="cx" style="display: block; padding: 0 10px">                 );
</span><span class="cx" style="display: block; padding: 0 10px">                $args     = wp_parse_args( $args, $defaults );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->type = $args['type'];
-               $this->api  = isset( $args['api'] ) ? $args['api'] : array();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->type      = $args['type'];
+               $this->url       = $args['url'];
+               $this->api       = isset( $args['api'] ) ? $args['api'] : array();
+               $this->overwrite = $args['overwrite'];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                parent::__construct( $args );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -51,8 +58,32 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Hides the `process_failed` error when updating a theme by uploading a zip file.
+        *
+        * @since 5.5.0
+        *
+        * @param $wp_error WP_Error.
+        * @return bool
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        public function hide_process_failed( $wp_error ) {
+               if (
+                       'upload' === $this->type &&
+                       '' === $this->overwrite &&
+                       $wp_error->get_error_code() === 'folder_exists'
+               ) {
+                       return true;
+               }
+
+               return false;
+       }
+
+       /**
+        */
</ins><span class="cx" style="display: block; padding: 0 10px">         public function after() {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( $this->do_overwrite() ) {
+                       return;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $this->upgrader->result['destination_name'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        return;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -130,6 +161,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! $this->result || is_wp_error( $this->result ) || is_network_admin() || ! current_user_can( 'switch_themes' ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        unset( $install_actions['activate'], $install_actions['preview'] );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                } elseif ( get_option( 'template' ) === $stylesheet ) {
+                       unset( $install_actions['activate'] );
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -147,4 +180,177 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->feedback( implode( ' | ', (array) $install_actions ) );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * Check if the theme can be overwritten and output the HTML for overwriting a theme on upload.
+        *
+        * @since 5.5.0
+        *
+        * @return bool Whether the theme can be overwritten and HTML was outputted.
+        */
+       private function do_overwrite() {
+               if ( 'upload' !== $this->type || ! is_wp_error( $this->result ) || 'folder_exists' !== $this->result->get_error_code() ) {
+                       return false;
+               }
+
+               $folder = $this->result->get_error_data( 'folder_exists' );
+               $folder = rtrim( $folder, '/' );
+
+               $current_theme_data = false;
+               $all_themes         = wp_get_themes( array( 'errors' => null ) );
+
+               foreach ( $all_themes as $theme ) {
+                       if ( rtrim( $theme->get_stylesheet_directory(), '/' ) !== $folder ) {
+                               continue;
+                       }
+
+                       $current_theme_data = $theme;
+               }
+
+               if ( empty( $current_theme_data ) || empty( $this->upgrader->new_theme_data ) ) {
+                       return false;
+               }
+
+               echo '<h2 class="update-from-upload-heading">' . esc_html( __( 'This theme is already installed.' ) ) . '</h2>';
+
+               // Check errors for current theme
+               if ( is_wp_error( $current_theme_data->errors() ) ) {
+                       $this->feedback( 'current_theme_has_errors', $current_theme_data->errors()->get_error_message() );
+               }
+
+               $this->is_downgrading = version_compare( $current_theme_data['Version'], $this->upgrader->new_theme_data['Version'], '>' );
+
+               $is_invalid_parent = false;
+               if ( ! empty( $this->upgrader->new_theme_data['Template'] ) ) {
+                       $is_invalid_parent = ! in_array( $this->upgrader->new_theme_data['Template'], array_keys( $all_themes ), true );
+               }
+
+               $rows = array(
+                       'Name'        => __( 'Theme name' ),
+                       'Version'     => __( 'Version' ),
+                       'Author'      => __( 'Author' ),
+                       'RequiresWP'  => __( 'Required WordPress version' ),
+                       'RequiresPHP' => __( 'Required PHP version' ),
+                       'Template'    => __( 'Parent theme' ),
+               );
+
+               $table  = '<table class="update-from-upload-comparison"><tbody>';
+               $table .= '<tr><th></th><th>' . esc_html( __( 'Current' ) ) . '</th><th>' . esc_html( __( 'Uploaded' ) ) . '</th></tr>';
+
+               $is_same_theme = true; // Let's consider only these rows
+               foreach ( $rows as $field => $label ) {
+                       $old_value = $current_theme_data->display( $field, false );
+                       $old_value = $old_value ? $old_value : '-';
+
+                       $new_value = ! empty( $this->upgrader->new_theme_data[ $field ] ) ? $this->upgrader->new_theme_data[ $field ] : '-';
+
+                       if ( $old_value === $new_value && '-' === $new_value && 'Template' === $field ) {
+                               continue;
+                       }
+
+                       $is_same_theme = $is_same_theme && ( $old_value === $new_value );
+
+                       $diff_field     = ( 'Version' !== $field && $new_value !== $old_value );
+                       $diff_version   = ( 'Version' === $field && $this->is_downgrading );
+                       $invalid_parent = false;
+
+                       if ( 'Template' === $field && $is_invalid_parent ) {
+                               $invalid_parent = true;
+                               $new_value     .= ' ' . __( '(not found)' );
+                       }
+
+                       $table .= '<tr><td class="name-label">' . $label . '</td><td>' . esc_html( $old_value ) . '</td>';
+                       $table .= ( $diff_field || $diff_version || $invalid_parent ) ? '<td class="warning">' : '<td>';
+                       $table .= esc_html( $new_value ) . '</td></tr>';
+               }
+
+               $table .= '</tbody></table>';
+
+               /**
+                * Filters the compare table output for overwrite a theme package on upload.
+                *
+                * @since 5.5.0
+                *
+                * @param string   $table               The output table with Name, Version, Author, RequiresWP and RequiresPHP info.
+                * @param array    $current_theme_data  Array with current theme data.
+                * @param array    $new_theme_data      Array with uploaded theme data.
+                */
+               echo apply_filters( 'install_theme_overwrite_comparison', $table, $current_theme_data, $this->upgrader->new_theme_data );
+
+               $install_actions = array();
+               $can_update      = true;
+
+               $blocked_message  = '<p>' . esc_html( __( 'The theme cannot be updated due to the following:' ) ) . '</p>';
+               $blocked_message .= '<ul class="ul-disc">';
+
+               if ( ! empty( $this->upgrader->new_theme_data['RequiresPHP'] ) && version_compare( phpversion(), $this->upgrader->new_theme_data['RequiresPHP'], '<' ) ) {
+                       $error = sprintf(
+                               /* translators: 1: Current PHP version, 2: Version required by the uploaded theme. */
+                               __( 'The PHP version on your server is %1$s, however the uploaded theme requires %2$s.' ),
+                               phpversion(),
+                               $this->upgrader->new_theme_data['RequiresPHP']
+                       );
+
+                       $blocked_message .= '<li>' . esc_html( $error ) . '</li>';
+                       $can_update       = false;
+               }
+
+               if ( ! empty( $this->upgrader->new_theme_data['RequiresWP'] ) && version_compare( $GLOBALS['wp_version'], $this->upgrader->new_theme_data['RequiresWP'], '<' ) ) {
+                       $error = sprintf(
+                               /* translators: 1: Current WordPress version, 2: Version required by the uploaded theme. */
+                               __( 'Your WordPress version is %1$s, however the uploaded theme requires %2$s.' ),
+                               $GLOBALS['wp_version'],
+                               $this->upgrader->new_theme_data['RequiresWP']
+                       );
+
+                       $blocked_message .= '<li>' . esc_html( $error ) . '</li>';
+                       $can_update       = false;
+               }
+
+               $blocked_message .= '</ul>';
+
+               if ( $can_update ) {
+                       if ( $this->is_downgrading ) {
+                               $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.' );
+                       } else {
+                               $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.' );
+                       }
+
+                       echo '<p class="update-from-upload-notice">' . $warning . '</p>';
+
+                       $overwrite = $this->is_downgrading ? 'downgrade-theme' : 'update-theme';
+
+                       $install_actions['ovewrite_theme'] = sprintf(
+                               '<a class="button button-primary" href="%s" target="_parent">%s</a>',
+                               wp_nonce_url( add_query_arg( 'overwrite', $overwrite, $this->url ), 'theme-upload' ),
+                               esc_html( __( 'Replace current with uploaded' ) )
+                       );
+               } else {
+                       echo $blocked_message;
+               }
+
+               $install_actions['themes_page'] = sprintf(
+                       '<a class="button" href="%s" target="_parent">%s</a>',
+                       self_admin_url( 'theme-install.php' ),
+                       __( 'Cancel and go back' )
+               );
+
+               /**
+                * Filters the list of action links available following a single theme installation failed but ovewrite is allowed.
+                *
+                * @since 5.5.0
+                *
+                * @param string[] $install_actions Array of theme action links.
+                * @param object   $api             Object containing WordPress.org API theme data.
+                * @param array    $new_theme_data  Array with uploaded theme data.
+                */
+               $install_actions = apply_filters( 'install_theme_ovewrite_actions', $install_actions, $this->api, $this->upgrader->new_theme_data );
+
+               if ( ! empty( $install_actions ) ) {
+                       echo '<p class="update-from-upload-actions">' . implode( ' ', (array) $install_actions ) . '</p>';
+               }
+
+               return true;
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunksrcwpadminincludesclassthemeupgraderphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/class-theme-upgrader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-theme-upgrader.php      2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/includes/class-theme-upgrader.php        2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38,6 +38,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public $bulk = false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * New theme info.
+        *
+        * @since 5.5.0
+        * @var array $new_theme_data
+        *
+        * @see check_package()
+        */
+       public $new_theme_data = array();
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Initialize the upgrade strings.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 2.8.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -65,6 +75,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['downloading_package'] = sprintf( __( 'Downloading installation package from %s&#8230;' ), '<span class="code">%s</span>' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['unpack_package']      = __( 'Unpacking the package&#8230;' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['installing_package']  = __( 'Installing the theme&#8230;' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->strings['remove_old']          = __( 'Removing the old version of the theme&#8230;' );
+               $this->strings['remove_old_failed']   = __( 'Could not remove the old theme.' );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->strings['no_files']            = __( 'The theme contains no files.' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['process_failed']      = __( 'Theme installation failed.' );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['process_success']     = __( 'Theme installed successfully.' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -79,6 +91,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->strings['parent_theme_install_success'] = __( 'Successfully installed the parent theme, <strong>%1$s %2$s</strong>.' );
</span><span class="cx" style="display: block; padding: 0 10px">                /* translators: %s: Theme name. */
</span><span class="cx" style="display: block; padding: 0 10px">                $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>' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                /* translators: %s: Theme error. */
+               $this->strings['current_theme_has_errors'] = __( 'The current theme has the following error: "%s".' );
+
+               if ( 'update-theme' === $this->skin->overwrite ) {
+                       $this->strings['installing_package'] = __( 'Updating the theme&#8230;' );
+                       $this->strings['process_failed']     = __( 'Theme update failed.' );
+                       $this->strings['process_success']    = __( 'Theme updated successfully.' );
+               }
+
+               if ( 'downgrade-theme' === $this->skin->overwrite ) {
+                       $this->strings['installing_package'] = __( 'Downgrading the theme&#8230;' );
+                       $this->strings['process_failed']     = __( 'Theme downgrade failed.' );
+                       $this->strings['process_success']    = __( 'Theme downgraded successfully.' );
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -200,9 +226,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return bool|WP_Error True if the installation was successful, false or a WP_Error object otherwise.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function install( $package, $args = array() ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 $defaults    = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'clear_update_cache' => true,
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'overwrite_package'  => false, // Do not overwrite files.
</ins><span class="cx" style="display: block; padding: 0 10px">                 );
</span><span class="cx" style="display: block; padding: 0 10px">                $parsed_args = wp_parse_args( $args, $defaults );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -220,7 +246,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'package'           => $package,
</span><span class="cx" style="display: block; padding: 0 10px">                                'destination'       => get_theme_root(),
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'clear_destination' => false, // Do not overwrite files.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'clear_destination' => $args['overwrite_package'],
</ins><span class="cx" style="display: block; padding: 0 10px">                                 'clear_working'     => true,
</span><span class="cx" style="display: block; padding: 0 10px">                                'hook_extra'        => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                        'type'   => 'theme',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -240,6 +266,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // Refresh the Theme Update information.
</span><span class="cx" style="display: block; padding: 0 10px">                wp_clean_themes_cache( $parsed_args['clear_update_cache'] );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( $parsed_args['overwrite_package'] ) {
+                       /**
+                        * Fires when the upgrader has successfully overwritten a currently installed
+                        * plugin or theme with an uploaded zip package.
+                        *
+                        * @since 5.5.0
+                        *
+                        * @param string  $package          The package file.
+                        * @param array   $new_plugin_data  The new theme data.
+                        * @param string  $package_type     The package type (plugin or theme).
+                        */
+                       do_action( 'upgrader_overwrote_package', $package, $this->new_theme_data, 'theme' );
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 return true;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -259,7 +299,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return bool|WP_Error True if the upgrade was successful, false or a WP_Error object otherwise.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function upgrade( $theme, $args = array() ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 $defaults    = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'clear_update_cache' => true,
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -332,7 +371,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return array[]|false An array of results, or false if unable to connect to the filesystem.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function bulk_upgrade( $themes, $args = array() ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 $defaults    = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'clear_update_cache' => true,
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -461,6 +499,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public function check_package( $source ) {
</span><span class="cx" style="display: block; padding: 0 10px">                global $wp_filesystem;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->new_theme_data = array();
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( is_wp_error( $source ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        return $source;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -484,11 +524,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // All these headers are needed on Theme_Installer_Skin::do_overwrite().
</ins><span class="cx" style="display: block; padding: 0 10px">                 $info = get_file_data(
</span><span class="cx" style="display: block; padding: 0 10px">                        $working_directory . 'style.css',
</span><span class="cx" style="display: block; padding: 0 10px">                        array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'Name'     => 'Theme Name',
-                               'Template' => 'Template',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'Name'        => 'Theme Name',
+                               'Version'     => 'Version',
+                               'Author'      => 'Author',
+                               'Template'    => 'Template',
+                               'RequiresWP'  => 'Requires at least',
+                               'RequiresPHP' => 'Requires PHP',
</ins><span class="cx" style="display: block; padding: 0 10px">                         )
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -517,6 +562,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->new_theme_data = $info;
</ins><span class="cx" style="display: block; padding: 0 10px">                 return $source;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -640,7 +686,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">         *                        and the last result isn't set.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function theme_info( $theme = null ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 if ( empty( $theme ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( ! empty( $this->result['destination_name'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $theme = $this->result['destination_name'];
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -648,7 +693,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                return false;
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return wp_get_theme( $theme );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               $theme = wp_get_theme( $theme );
+               $theme->cache_delete();
+
+               return $theme;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunksrcwpadminincludesclasswpupgraderskinphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/class-wp-upgrader-skin.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-wp-upgrader-skin.php    2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/includes/class-wp-upgrader-skin.php      2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -205,4 +205,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function bulk_footer() {}
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * Hides the `process_failed` error message when updating by uploading a zip file.
+        *
+        * @since 5.5.0
+        *
+        * @param $wp_error WP_Error
+        * @return bool
+        */
+       public function hide_process_failed( $wp_error ) {
+               return false;
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunksrcwpadminincludesclasswpupgraderphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/class-wp-upgrader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-wp-upgrader.php 2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/includes/class-wp-upgrader.php   2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -798,7 +798,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->skin->set_result( $result );
</span><span class="cx" style="display: block; padding: 0 10px">                if ( is_wp_error( $result ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->skin->error( $result );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->skin->feedback( 'process_failed' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                       if ( ! method_exists( $this->skin, 'hide_process_failed' ) || ! $this->skin->hide_process_failed( $result ) ) {
+                               $this->skin->feedback( 'process_failed' );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                 } else {
</span><span class="cx" style="display: block; padding: 0 10px">                        // Installation succeeded.
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->skin->feedback( 'process_success' );
</span></span></pre></div>
<a id="trunksrcwpadminincludesplugininstallphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/plugin-install.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/plugin-install.php    2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/includes/plugin-install.php      2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -353,7 +353,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url( 'update.php?action=upload-plugin' ); ?>">
</span><span class="cx" style="display: block; padding: 0 10px">                <?php wp_nonce_field( 'plugin-upload' ); ?>
</span><span class="cx" style="display: block; padding: 0 10px">                <label class="screen-reader-text" for="pluginzip"><?php _e( 'Plugin zip file' ); ?></label>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <input type="file" id="pluginzip" name="pluginzip" />
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         <input type="file" id="pluginzip" name="pluginzip" accept=".zip" />
</ins><span class="cx" style="display: block; padding: 0 10px">                 <?php submit_button( __( 'Install Now' ), '', 'install-plugin-submit', false ); ?>
</span><span class="cx" style="display: block; padding: 0 10px">        </form>
</span><span class="cx" style="display: block; padding: 0 10px"> </div>
</span></span></pre></div>
<a id="trunksrcwpadminincludesthemeinstallphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/theme-install.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/theme-install.php     2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/includes/theme-install.php       2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -183,7 +183,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url( 'update.php?action=upload-theme' ); ?>">
</span><span class="cx" style="display: block; padding: 0 10px">        <?php wp_nonce_field( 'theme-upload' ); ?>
</span><span class="cx" style="display: block; padding: 0 10px">        <label class="screen-reader-text" for="themezip"><?php _e( 'Theme zip file' ); ?></label>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        <input type="file" id="themezip" name="themezip" />
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <input type="file" id="themezip" name="themezip" accept=".zip"/>
</ins><span class="cx" style="display: block; padding: 0 10px">         <?php submit_button( __( 'Install Now' ), '', 'install-theme-submit', false ); ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </form>
</span><span class="cx" style="display: block; padding: 0 10px">        <?php
</span></span></pre></div>
<a id="trunksrcwpadminupdatephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/update.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/update.php     2020-07-07 17:27:38 UTC (rev 48389)
+++ trunk/src/wp-admin/update.php       2020-07-07 17:47:37 UTC (rev 48390)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -157,14 +157,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                require_once ABSPATH . 'wp-admin/admin-header.php';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                /* translators: %s: File name. */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $title = sprintf( __( 'Installing Plugin from uploaded file: %s' ), esc_html( basename( $file_upload->filename ) ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $title = sprintf( __( 'Installing plugin from uploaded file: %s' ), esc_html( basename( $file_upload->filename ) ) );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $nonce = 'plugin-upload';
</span><span class="cx" style="display: block; padding: 0 10px">                $url   = add_query_arg( array( 'package' => $file_upload->id ), 'update.php?action=upload-plugin' );
</span><span class="cx" style="display: block; padding: 0 10px">                $type  = 'upload'; // Install plugin type, From Web or an Upload.
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $upgrader = new Plugin_Upgrader( new Plugin_Installer_Skin( compact( 'type', 'title', 'nonce', 'url' ) ) );
-               $result   = $upgrader->install( $file_upload->package );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $overwrite = isset( $_GET['overwrite'] ) ? sanitize_text_field( $_GET['overwrite'] ) : '';
+               $overwrite = in_array( $overwrite, array( 'update-plugin', 'downgrade-plugin' ), true ) ? $overwrite : '';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $upgrader = new Plugin_Upgrader( new Plugin_Installer_Skin( compact( 'type', 'title', 'nonce', 'url', 'overwrite' ) ) );
+               $result   = $upgrader->install( $file_upload->package, array( 'overwrite_package' => $overwrite ) );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( $result || is_wp_error( $result ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $file_upload->cleanup();
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -277,14 +280,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                require_once ABSPATH . 'wp-admin/admin-header.php';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                /* translators: %s: File name. */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $title = sprintf( __( 'Installing Theme from uploaded file: %s' ), esc_html( basename( $file_upload->filename ) ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $title = sprintf( __( 'Installing theme from uploaded file: %s' ), esc_html( basename( $file_upload->filename ) ) );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $nonce = 'theme-upload';
</span><span class="cx" style="display: block; padding: 0 10px">                $url   = add_query_arg( array( 'package' => $file_upload->id ), 'update.php?action=upload-theme' );
</span><span class="cx" style="display: block; padding: 0 10px">                $type  = 'upload'; // Install theme type, From Web or an Upload.
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $upgrader = new Theme_Upgrader( new Theme_Installer_Skin( compact( 'type', 'title', 'nonce', 'url' ) ) );
-               $result   = $upgrader->install( $file_upload->package );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $overwrite = isset( $_GET['overwrite'] ) ? sanitize_text_field( $_GET['overwrite'] ) : '';
+               $overwrite = in_array( $overwrite, array( 'update-theme', 'downgrade-theme' ), true ) ? $overwrite : '';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $upgrader = new Theme_Upgrader( new Theme_Installer_Skin( compact( 'type', 'title', 'nonce', 'url', 'overwrite' ) ) );
+               $result   = $upgrader->install( $file_upload->package, array( 'overwrite_package' => $overwrite ) );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( $result || is_wp_error( $result ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $file_upload->cleanup();
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span></span></pre>
</div>
</div>

</body>
</html>