<!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>[47835] trunk/src: Security: Add user interface to auto-update themes and plugins.</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/47835">47835</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/47835","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>whyisjake</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2020-05-20 18:47:24 +0000 (Wed, 20 May 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'>Security: Add user interface to auto-update themes and plugins.

Building on core update mechanisms, this adds the ability to enable automatic updates for themes and plugins to the WordPress admin. 

Fixes: <a href="https://core.trac.wordpress.org/ticket/50052">#50052</a>.
Props: afercia, afragen, audrasjb, azaozz, bookdude13, davidperonne, desrosj, gmays, gmays, javiercasares, karmatosed, knutsp, mapk, mukesh27, netweb, nicolaskulka, nielsdeblaauw, paaljoachim, passoniate, pbiron, pedromendonca, whodunitagency, whyisjake, wpamitkumar, and xkon.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcjs_enqueueswpupdatesjs">trunk/src/js/_enqueues/wp/updates.js</a></li>
<li><a href="#trunksrcwpadminadminajaxphp">trunk/src/wp-admin/admin-ajax.php</a></li>
<li><a href="#trunksrcwpadmincsscommoncss">trunk/src/wp-admin/css/common.css</a></li>
<li><a href="#trunksrcwpadmincsslisttablescss">trunk/src/wp-admin/css/list-tables.css</a></li>
<li><a href="#trunksrcwpadmincssthemescss">trunk/src/wp-admin/css/themes.css</a></li>
<li><a href="#trunksrcwpadminincludesajaxactionsphp">trunk/src/wp-admin/includes/ajax-actions.php</a></li>
<li><a href="#trunksrcwpadminincludesclasswpautomaticupdaterphp">trunk/src/wp-admin/includes/class-wp-automatic-updater.php</a></li>
<li><a href="#trunksrcwpadminincludesclasswpdebugdataphp">trunk/src/wp-admin/includes/class-wp-debug-data.php</a></li>
<li><a href="#trunksrcwpadminincludesclasswpmsthemeslisttablephp">trunk/src/wp-admin/includes/class-wp-ms-themes-list-table.php</a></li>
<li><a href="#trunksrcwpadminincludesclasswppluginslisttablephp">trunk/src/wp-admin/includes/class-wp-plugins-list-table.php</a></li>
<li><a href="#trunksrcwpadminincludesthemephp">trunk/src/wp-admin/includes/theme.php</a></li>
<li><a href="#trunksrcwpadminincludesupdatephp">trunk/src/wp-admin/includes/update.php</a></li>
<li><a href="#trunksrcwpadminnetworkthemesphp">trunk/src/wp-admin/network/themes.php</a></li>
<li><a href="#trunksrcwpadminpluginsphp">trunk/src/wp-admin/plugins.php</a></li>
<li><a href="#trunksrcwpadminthemesphp">trunk/src/wp-admin/themes.php</a></li>
<li><a href="#trunksrcwpadminupdatecorephp">trunk/src/wp-admin/update-core.php</a></li>
<li><a href="#trunksrcwpincludesscriptloaderphp">trunk/src/wp-includes/script-loader.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcjs_enqueueswpupdatesjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/js/_enqueues/wp/updates.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/js/_enqueues/wp/updates.js      2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/js/_enqueues/wp/updates.js        2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -409,6 +409,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 4.2.0
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 4.6.0 More accurately named `updatePluginSuccess`.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 5.5.0 Auto-update "time to next update" text cleared.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param {object} response            Response from the server.
</span><span class="cx" style="display: block; padding: 0 10px">         * @param {string} response.slug       Slug of the plugin to be updated.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -431,6 +432,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        // Update the version number in the row.
</span><span class="cx" style="display: block; padding: 0 10px">                        newText = $pluginRow.find( '.plugin-version-author-uri' ).html().replace( response.oldVersion, response.newVersion );
</span><span class="cx" style="display: block; padding: 0 10px">                        $pluginRow.find( '.plugin-version-author-uri' ).html( newText );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                       // Clear the "time to next auto-update" text.
+                       $pluginRow.find( '.auto-update-time' ).empty();
</ins><span class="cx" style="display: block; padding: 0 10px">                 } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $updateMessage = $( '.plugin-card-' + response.slug ).find( '.update-now' )
</span><span class="cx" style="display: block; padding: 0 10px">                                .removeClass( 'updating-message' )
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -969,6 +973,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Updates the UI appropriately after a successful theme update.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 4.6.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @since 5.5.0 Auto-update "time to next update" text cleared.
</ins><span class="cx" style="display: block; padding: 0 10px">          *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param {object} response
</span><span class="cx" style="display: block; padding: 0 10px">         * @param {string} response.slug       Slug of the theme to be updated.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1002,6 +1007,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        // Update the version number in the row.
</span><span class="cx" style="display: block; padding: 0 10px">                        newText = $theme.find( '.theme-version-author-uri' ).html().replace( response.oldVersion, response.newVersion );
</span><span class="cx" style="display: block; padding: 0 10px">                        $theme.find( '.theme-version-author-uri' ).html( newText );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                       // Clear the "time to next auto-update" text.
+                       $theme.find( '.auto-update-time' ).empty();
</ins><span class="cx" style="display: block; padding: 0 10px">                 } else {
</span><span class="cx" style="display: block; padding: 0 10px">                        $notice = $( '.theme-info .notice' ).add( $theme.find( '.update-message' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1008,6 +1016,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        // Focus on Customize button after updating.
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( isModalOpen ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $( '.load-customize:visible' ).focus();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                $( '.theme-info .theme-autoupdate' ).find( '.auto-update-time' ).empty();
</ins><span class="cx" style="display: block; padding: 0 10px">                         } else {
</span><span class="cx" style="display: block; padding: 0 10px">                                $theme.find( '.load-customize' ).focus();
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2461,5 +2470,144 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 * @since 4.2.0
</span><span class="cx" style="display: block; padding: 0 10px">                 */
</span><span class="cx" style="display: block; padding: 0 10px">                $( window ).on( 'beforeunload', wp.updates.beforeunload );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               /**
+                * Click handler for enabling and disabling plugin and theme auto-updates.
+                *
+                * @since 5.5.0
+                */
+               $document.on( 'click', '.column-auto-updates a.toggle-auto-update, .theme-overlay a.toggle-auto-update', function( event ) {
+                       var data, asset, type, $parent;
+                       var $anchor = $( this ),
+                               action = $anchor.attr( 'data-wp-action' ),
+                               $label = $anchor.find( '.label' );
+
+                       if ( 'themes' !== pagenow ) {
+                               $parent = $anchor.closest( '.column-auto-updates' );
+                       } else {
+                               $parent = $anchor.closest( '.theme-autoupdate' );
+                       }
+
+                       event.preventDefault();
+
+                       // Prevent multiple simultaneous requests.
+                       if ( $anchor.attr( 'data-doing-ajax' ) === 'yes' ) {
+                               return;
+                       }
+
+                       $anchor.attr( 'data-doing-ajax', 'yes' );
+
+                       switch ( pagenow ) {
+                               case 'plugins':
+                               case 'plugins-network':
+                                       type = 'plugin';
+                                       asset = $anchor.closest( 'tr' ).attr( 'data-plugin' );
+                                       break;
+                               case 'themes-network':
+                                       type = 'theme';
+                                       asset = $anchor.closest( 'tr' ).attr( 'data-slug' );
+                                       break;
+                               case 'themes':
+                                       type = 'theme';
+                                       asset = $anchor.attr( 'data-slug' );
+                                       break;
+                       }
+
+                       // Clear any previous errors.
+                       $parent.find( '.notice.error' ).addClass( 'hidden' );
+
+                       // Show loading status.
+                       if ( 'enable' === action ) {
+                               $label.text( wp.updates.l10n.autoUpdatesEnabling );
+                       } else {
+                               $label.text( wp.updates.l10n.autoUpdatesDisabling );
+                       }
+
+                       $anchor.find( '.dashicons-update' ).removeClass( 'hidden' );
+
+                       data = {
+                               action: 'toggle-auto-updates',
+                               _ajax_nonce: settings.ajax_nonce,
+                               state: action,
+                               type: type,
+                               asset: asset
+                       };
+
+                       $.post( window.ajaxurl, data )
+                               .done( function( response ) {
+                                       var $enabled, $disabled, enabledNumber, disabledNumber, errorMessage;
+                                       var href = $anchor.attr( 'href' );
+
+                                       if ( ! response.success ) {
+                                               // if WP returns 0 for response (which can happen in a few cases),
+                                               // output the general error message since we won't have response.data.error.
+                                               if ( response.data && response.data.error ) {
+                                                       errorMessage = response.data.error;
+                                               } else {
+                                                       errorMessage = wp.updates.l10n.autoUpdatesError;
+                                               }
+
+                                               $parent.find( '.notice.error' ).removeClass( 'hidden' ).find( 'p' ).text( errorMessage );
+                                               wp.a11y.speak( errorMessage, 'polite' );
+                                               return;
+                                       }
+
+                                       // Update the counts in the enabled/disabled views if on a screen
+                                       // with a list table.
+                                       if ( 'themes' !== pagenow ) {
+                                               $enabled       = $( '.auto-update-enabled span' );
+                                               $disabled      = $( '.auto-update-disabled span' );
+                                               enabledNumber  = parseInt( $enabled.text().replace( /[^\d]+/g, '' ), 10 ) || 0;
+                                               disabledNumber = parseInt( $disabled.text().replace( /[^\d]+/g, '' ), 10 ) || 0;
+
+                                               switch ( action ) {
+                                                       case 'enable':
+                                                               ++enabledNumber;
+                                                               --disabledNumber;
+                                                               break;
+                                                       case 'disable':
+                                                               --enabledNumber;
+                                                               ++disabledNumber;
+                                                               break;
+                                               }
+
+                                               enabledNumber = Math.max( 0, enabledNumber );
+                                               disabledNumber = Math.max( 0, disabledNumber );
+
+                                               $enabled.text( '(' + enabledNumber + ')' );
+                                               $disabled.text( '(' + disabledNumber + ')' );
+                                       }
+
+                                       if ( 'enable' === action ) {
+                                               href = href.replace( 'action=enable-auto-update', 'action=disable-auto-update' );
+                                               $anchor.attr( {
+                                                       'data-wp-action': 'disable',
+                                                       href: href
+                                               } );
+
+                                               $label.text( wp.updates.l10n.autoUpdatesDisable );
+                                               $parent.find( '.auto-update-time' ).removeClass( 'hidden' );
+                                               wp.a11y.speak( wp.updates.l10n.autoUpdatesEnabled, 'polite' );
+                                       } else {
+                                               href = href.replace( 'action=disable-auto-update', 'action=enable-auto-update' );
+                                               $anchor.attr( {
+                                                       'data-wp-action': 'enable',
+                                                       href: href
+                                               } );
+
+                                               $label.text( wp.updates.l10n.autoUpdatesEnable );
+                                               $parent.find( '.auto-update-time' ).addClass( 'hidden' );
+                                               wp.a11y.speak( wp.updates.l10n.autoUpdatesDisabled, 'polite' );
+                                       }
+                               } )
+                               .fail( function() {
+                                       $parent.find( '.notice.error' ).removeClass( 'hidden' ).find( 'p' ).text( wp.updates.l10n.autoUpdatesError );
+                                       wp.a11y.speak( wp.updates.l10n.autoUpdatesError, 'polite' );
+                               } )
+                               .always( function() {
+                                       $anchor.removeAttr( 'data-doing-ajax' ).find( '.dashicons-update' ).addClass( 'hidden' );
+                               } );
+                       }
+               );
</ins><span class="cx" style="display: block; padding: 0 10px">         } );
</span><span class="cx" style="display: block; padding: 0 10px"> })( jQuery, window.wp, window._wpUpdatesSettings );
</span></span></pre></div>
<a id="trunksrcwpadminadminajaxphp"></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/admin-ajax.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/admin-ajax.php 2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/admin-ajax.php   2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -139,6 +139,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        'health-check-background-updates',
</span><span class="cx" style="display: block; padding: 0 10px">        'health-check-loopback-requests',
</span><span class="cx" style="display: block; padding: 0 10px">        'health-check-get-sizes',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        'toggle-auto-updates',
</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"> // Deprecated.
</span></span></pre></div>
<a id="trunksrcwpadmincsscommoncss"></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/common.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/css/common.css 2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/css/common.css   2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1524,7 +1524,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> .updating-message p:before,
</span><span class="cx" style="display: block; padding: 0 10px"> .import-php .updating-message:before,
</span><span class="cx" style="display: block; padding: 0 10px"> .button.updating-message:before,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.button.installing:before {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.button.installing:before,
+.plugins .column-auto-updates .dashicons-update.spin,
+.theme-overlay .theme-autoupdate .dashicons-update.spin {
</ins><span class="cx" style="display: block; padding: 0 10px">         animation: rotation 2s infinite linear;
</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="trunksrcwpadmincsslisttablescss"></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/list-tables.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/css/list-tables.css    2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/css/list-tables.css      2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1236,6 +1236,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">        width: 85px;
</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">+.plugins .column-auto-updates {
+       width: 14.2em;
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> .plugins .inactive .plugin-title strong {
</span><span class="cx" style="display: block; padding: 0 10px">        font-weight: 400;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<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-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/css/themes.css   2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -679,7 +679,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">        line-height: inherit;
</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">-.theme-overlay .theme-author a {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.theme-overlay .theme-author a,
+.theme-overlay .theme-autoupdate a {
</ins><span class="cx" style="display: block; padding: 0 10px">         text-decoration: none;
</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="trunksrcwpadminincludesajaxactionsphp"></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/ajax-actions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/ajax-actions.php      2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/includes/ajax-actions.php        2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4567,6 +4567,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> function wp_ajax_search_plugins() {
</span><span class="cx" style="display: block; padding: 0 10px">        check_ajax_referer( 'updates' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // Ensure after_plugin_row_{$plugin_file} gets hooked.
+       wp_plugin_update_rows();
+
</ins><span class="cx" style="display: block; padding: 0 10px">         $pagenow = isset( $_POST['pagenow'] ) ? sanitize_key( $_POST['pagenow'] ) : '';
</span><span class="cx" style="display: block; padding: 0 10px">        if ( 'plugins-network' === $pagenow || 'plugins' === $pagenow ) {
</span><span class="cx" style="display: block; padding: 0 10px">                set_current_screen( $pagenow );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5267,3 +5270,73 @@
</span><span class="cx" style="display: block; padding: 0 10px"> function wp_ajax_rest_nonce() {
</span><span class="cx" style="display: block; padding: 0 10px">        exit( wp_create_nonce( 'wp_rest' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+/**
+ * Ajax handler to enable or disable plugin and theme auto-updates.
+ *
+ * @since 5.5.0
+ */
+function wp_ajax_toggle_auto_updates() {
+       check_ajax_referer( 'updates' );
+
+       if ( empty( $_POST['type'] ) || empty( $_POST['asset'] ) || empty( $_POST['state'] ) ) {
+               wp_send_json_error( array( 'error' => __( 'Invalid data. No selected item.' ) ) );
+       }
+
+       $asset = sanitize_text_field( urldecode( $_POST['asset'] ) );
+
+       if ( 'enable' !== $_POST['state'] && 'disable' !== $_POST['state'] ) {
+               wp_send_json_error( array( 'error' => __( 'Invalid data. Unknown state.' ) ) );
+       }
+       $state = $_POST['state'];
+
+       if ( 'plugin' !== $_POST['type'] && 'theme' !== $_POST['type'] ) {
+               wp_send_json_error( array( 'error' => __( 'Invalid data. Unknown type.' ) ) );
+       }
+       $type = $_POST['type'];
+
+       switch ( $type ) {
+               case 'plugin':
+                       if ( ! current_user_can( 'update_plugins' ) ) {
+                               $error_message = __( 'You do not have permission to modify plugins.' );
+                               wp_send_json_error( array( 'error' => $error_message ) );
+                       }
+
+                       $option = 'auto_update_plugins';
+                       /** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */
+                       $all_items = apply_filters( 'all_plugins', get_plugins() );
+                       break;
+               case 'theme':
+                       if ( ! current_user_can( 'update_themes' ) ) {
+                               $error_message = __( 'You do not have permission to modify themes.' );
+                               wp_send_json_error( array( 'error' => $error_message ) );
+                       }
+
+                       $option    = 'auto_update_themes';
+                       $all_items = wp_get_themes();
+                       break;
+               default:
+                       wp_send_json_error( array( 'error' => __( 'Invalid data. Unknown type.' ) ) );
+       }
+
+       if ( ! array_key_exists( $asset, $all_items ) ) {
+               $error_message = __( 'Invalid data. The item does not exist.' );
+               wp_send_json_error( array( 'error' => $error_message ) );
+       }
+
+       $auto_updates = (array) get_site_option( $option, array() );
+
+       if ( 'disable' === $state ) {
+               $auto_updates = array_diff( $auto_updates, array( $asset ) );
+       } else {
+               $auto_updates[] = $asset;
+               $auto_updates   = array_unique( $auto_updates );
+       }
+
+       // Remove items that have been deleted since the site option was last updated.
+       $auto_updates = array_intersect( $auto_updates, array_keys( $all_items ) );
+
+       update_site_option( $option, $auto_updates );
+
+       wp_send_json_success();
+}
</ins></span></pre></div>
<a id="trunksrcwpadminincludesclasswpautomaticupdaterphp"></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-automatic-updater.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-wp-automatic-updater.php        2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/includes/class-wp-automatic-updater.php  2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -158,6 +158,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // Next up, is this an item we can update?
</span><span class="cx" style="display: block; padding: 0 10px">                if ( 'core' === $type ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $update = Core_Upgrader::should_update_to_version( $item->current );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                } elseif ( 'plugin' === $type || 'theme' === $type ) {
+                       $update = ! empty( $item->autoupdate );
+
+                       if ( ! $update && wp_is_auto_update_enabled_for_type( $type ) ) {
+                               // Check if the site admin has enabled auto-updates by default for the specific item.
+                               $auto_updates = (array) get_site_option( "auto_update_{$type}s", array() );
+                               $update       = in_array( $item->{$type}, $auto_updates, true );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                 } else {
</span><span class="cx" style="display: block; padding: 0 10px">                        $update = ! empty( $item->autoupdate );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -501,6 +509,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( ! empty( $this->update_results['core'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $this->after_core_update( $this->update_results['core'][0] );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        } elseif ( ! empty( $this->update_results['plugin'] ) || ! empty( $this->update_results['theme'] ) ) {
+                               $this->after_plugin_theme_update( $this->update_results );
</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">@@ -854,7 +864,187 @@
</span><span class="cx" style="display: block; padding: 0 10px">                wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] );
</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">+
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * If we tried to perform plugin or theme updates, check if we should send an email.
+        *
+        * @since 5.5.0
+        *
+        * @param object $results The result of updates tasks.
+        */
+       protected function after_plugin_theme_update( $update_results ) {
+               $successful_updates = array();
+               $failed_updates     = array();
+
+               /**
+                * Filters whether to send an email following an automatic background plugin update.
+                *
+                * @since 5.5.0
+                *
+                * @param bool $enabled True if plugins notifications are enabled, false otherwise.
+                */
+               $notifications_enabled = apply_filters( 'auto_plugin_update_send_email', true );
+
+               if ( ! empty( $update_results['plugin'] ) && $notifications_enabled ) {
+                       foreach ( $update_results['plugin'] as $update_result ) {
+                               if ( true === $update_result->result ) {
+                                       $successful_updates['plugin'][] = $update_result;
+                               } else {
+                                       $failed_updates['plugin'][] = $update_result;
+                               }
+                       }
+               }
+
+               /**
+                * Filters whether to send an email following an automatic background theme update.
+                *
+                * @since 5.5.0
+                *
+                * @param bool $enabled True if notifications are enabled, false otherwise.
+                */
+               $notifications_enabled = apply_filters( 'send_theme_auto_update_email', true );
+
+               if ( ! empty( $update_results['theme'] ) && $notifications_enabled ) {
+                       foreach ( $update_results['theme'] as $update_result ) {
+                               if ( true === $update_result->result ) {
+                                       $successful_updates['theme'][] = $update_result;
+                               } else {
+                                       $failed_updates['theme'][] = $update_result;
+                               }
+                       }
+               }
+
+               if ( empty( $successful_updates ) && empty( $failed_updates ) ) {
+                       return;
+               }
+
+               if ( empty( $failed_updates ) ) {
+                       $this->send_plugin_theme_email( 'success', $successful_updates, $failed_updates );
+               } elseif ( empty( $successful_updates ) ) {
+                       $this->send_plugin_theme_email( 'fail', $successful_updates, $failed_updates );
+               } else {
+                       $this->send_plugin_theme_email( 'mixed', $successful_updates, $failed_updates );
+               }
+       }
+
+       /**
+        * Sends an email upon the completion or failure of a plugin or theme background update.
+        *
+        * @since 5.5.0
+        *
+        * @param string $type               The type of email to send. Can be one of 'success', 'failure', 'mixed'.
+        * @param array  $successful_updates A list of updates that succeeded.
+        * @param array  $failed_updates     A list of updates that failed.
+        */
+       protected function send_plugin_theme_email( $type, $successful_updates, $failed_updates ) {
+               // No updates were attempted.
+               if ( empty( $successful_updates ) && empty( $failed_updates ) ) {
+                       return;
+               }
+               $body = array();
+
+               switch ( $type ) {
+                       case 'success':
+                               /* translators: %s: Site title. */
+                               $subject = __( '[%s] Some plugins or themes were automatically updated' );
+                               break;
+                       case 'fail':
+                               /* translators: %s: Site title. */
+                               $subject = __( '[%s] Some plugins or themes have failed to update' );
+                               $body[]  = sprintf(
+                                       /* translators: %s: Home URL. */
+                                       __( 'Howdy! Failures occurred when attempting to update plugins/themes on your site at %s.' ),
+                                       home_url()
+                               );
+                               $body[] = "\n";
+                               $body[] = __( 'Please check out your site now. It’s possible that everything is working. If it says you need to update, you should do so.' );
+                               break;
+                       case 'mixed':
+                               /* translators: %s: Site title. */
+                               $subject = __( '[%s] Some plugins or themes were automatically updated' );
+                               $body[]  = sprintf(
+                                       /* translators: %s: Home URL. */
+                                       __( 'Howdy! Failures occurred when attempting to update plugins/themes on your site at %s.' ),
+                                       home_url()
+                               );
+                               $body[] = "\n";
+                               $body[] = __( 'Please check out your site now. It’s possible that everything is working. If it says you need to update, you should do so.' );
+                               $body[] = "\n";
+                               break;
+               }
+
+               // Get failed plugin updates.
+               if ( in_array( $type, array( 'fail', 'mixed' ), true ) && ! empty( $failed_updates['plugin'] ) ) {
+                       $body[] = __( 'The following plugins failed to update:' );
+                       // List failed updates.
+                       foreach ( $failed_updates['plugin'] as $item ) {
+                               $body[] = "- {$item->name}";
+                       }
+                       $body[] = "\n";
+               }
+               // Get failed theme updates.
+               if ( in_array( $type, array( 'fail', 'mixed' ), true ) && ! empty( $failed_updates['theme'] ) ) {
+                       $body[] = __( 'The following themes failed to update:' );
+                       // List failed updates.
+                       foreach ( $failed_updates['theme'] as $item ) {
+                               $body[] = "- {$item->name}";
+                       }
+                       $body[] = "\n";
+               }
+               // Get successful plugin updates.
+               if ( in_array( $type, array( 'success', 'mixed' ), true ) && ! empty( $successful_updates['plugin'] ) ) {
+                       $body[] = __( 'The following plugins were successfully updated:' );
+                       // List successful updates.
+                       foreach ( $successful_updates['plugin'] as $item ) {
+                               $body[] = "- {$item->name}";
+                       }
+                       $body[] = "\n";
+               }
+               // Get successful theme updates.
+               if ( in_array( $type, array( 'success', 'mixed' ), true ) && ! empty( $successful_updates['theme'] ) ) {
+                       $body[] = __( 'The following themes were successfully updated:' );
+                       // List successful updates.
+                       foreach ( $successful_updates['theme'] as $item ) {
+                               $body[] = "- {$item->name}";
+                       }
+                       $body[] = "\n";
+               }
+               $body[] = "\n";
+
+               // Add a note about the support forums.
+               $body[] = __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' );
+               $body[] = __( 'https://wordpress.org/support/forums/' );
+               $body[] = "\n" . __( 'The WordPress Team' );
+
+               $body    = implode( "\n", $body );
+               $to      = get_site_option( 'admin_email' );
+               $subject = sprintf( $subject, wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) );
+               $headers = '';
+
+               $email = compact( 'to', 'subject', 'body', 'headers' );
+
+               /**
+                * Filters the email sent following an automatic background plugin update.
+                *
+                * @param array $email {
+                *     Array of email arguments that will be passed to wp_mail().
+                *
+                *     @type string $to      The email recipient. An array of emails
+                *                           can be returned, as handled by wp_mail().
+                *     @type string $subject The email's subject.
+                *     @type string $body    The email message body.
+                *     @type string $headers Any email headers, defaults to no headers.
+                * }
+                * @param string $type               The type of email being sent. Can be one of
+                *                                   'success', 'fail', 'mixed'.
+                * @param object $successful_updates The updates that succeeded.
+                * @param object $failed_updates     The updates that failed.
+                */
+               $email = apply_filters( 'auto_plugin_theme_update_email', $email, $type, $successful_updates, $failed_updates );
+               wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Prepares and sends an email of a full log of background update results, useful for debugging and geekery.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 3.7.0
</span></span></pre></div>
<a id="trunksrcwpadminincludesclasswpdebugdataphp"></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-debug-data.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-wp-debug-data.php       2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/includes/class-wp-debug-data.php 2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -858,7 +858,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // List all available plugins.
</span><span class="cx" style="display: block; padding: 0 10px">                $plugins        = get_plugins();
</span><span class="cx" style="display: block; padding: 0 10px">                $plugin_updates = get_plugin_updates();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $auto_updates   = array();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $auto_updates_enabled      = wp_is_auto_update_enabled_for_type( 'plugin' );
+               $auto_updates_enabled_str  = __( 'Auto-updates enabled' );
+               $auto_updates_disabled_str = __( 'Auto-updates disabled' );
+
+               if ( $auto_updates_enabled ) {
+                       $auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 foreach ( $plugins as $plugin_path => $plugin ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $plugin_part = ( is_plugin_active( $plugin_path ) ) ? 'wp-plugins-active' : 'wp-plugins-inactive';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -892,6 +901,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                $plugin_version_string_debug .= sprintf( ' (latest version: %s)', $plugin_updates[ $plugin_path ]->update->new_version );
</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">+                        if ( $auto_updates_enabled ) {
+                               if ( in_array( $plugin_path, $auto_updates, true ) ) {
+                                       $plugin_version_string       .= ' | ' . $auto_updates_enabled_str;
+                                       $plugin_version_string_debug .= ', ' . $auto_updates_enabled_str;
+                               } else {
+                                       $plugin_version_string       .= ' | ' . $auto_updates_disabled_str;
+                                       $plugin_version_string_debug .= ', ' . $auto_updates_disabled_str;
+                               }
+                       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         $info[ $plugin_part ]['fields'][ sanitize_text_field( $plugin['Name'] ) ] = array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'label' => $plugin['Name'],
</span><span class="cx" style="display: block; padding: 0 10px">                                'value' => $plugin_version_string,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -915,6 +934,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $active_theme_version       = $active_theme->version;
</span><span class="cx" style="display: block; padding: 0 10px">                $active_theme_version_debug = $active_theme_version;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $auto_updates         = array();
+               $auto_updates_enabled = wp_is_auto_update_enabled_for_type( 'theme' );
+               if ( $auto_updates_enabled ) {
+                       $auto_updates = (array) get_site_option( 'auto_update_themes', array() );
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( array_key_exists( $active_theme->stylesheet, $theme_updates ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $theme_update_new_version = $theme_updates[ $active_theme->stylesheet ]->update['new_version'];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -980,7 +1005,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                'value' => get_stylesheet_directory(),
</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">+                if ( $auto_updates_enabled ) {
+                       if ( in_array( $active_theme->stylesheet, $auto_updates ) ) {
+                               $theme_auto_update_string = __( 'Enabled' );
+                       } else {
+                               $theme_auto_update_string = __( 'Disabled' );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        $info['wp-active-theme']['fields']['auto_update'] = array(
+                               'label' => __( 'Auto-update' ),
+                               'value' => $theme_auto_update_string,
+                               'debug' => $theme_auto_update_string,
+                       );
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">                 $parent_theme = $active_theme->parent();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $parent_theme ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1026,6 +1063,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        'value' => get_template_directory(),
</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">+                        if ( $auto_updates_enabled ) {
+                               if ( in_array( $parent_theme->stylesheet, $auto_updates ) ) {
+                                       $parent_theme_auto_update_string = __( 'Enabled' );
+                               } else {
+                                       $parent_theme_auto_update_string = __( 'Disabled' );
+                               }
+
+                               $info['wp-parent-theme']['fields']['auto_update'] = array(
+                                       'label' => __( 'Auto-update' ),
+                                       'value' => $parent_theme_auto_update_string,
+                                       'debug' => $parent_theme_auto_update_string,
+                               );
+                       }
</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">                // Populate a list of all themes available in the install.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1075,6 +1125,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                $theme_version_string_debug .= sprintf( ' (latest version: %s)', $theme_updates[ $theme_slug ]->update['new_version'] );
</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">+                        if ( $auto_updates_enabled ) {
+                               if ( in_array( $theme_slug, $auto_updates ) ) {
+                                       $theme_version_string       .= ' | ' . $auto_updates_enabled_str;
+                                       $theme_version_string_debug .= ',' . $auto_updates_enabled_str;
+                               } else {
+                                       $theme_version_string       .= ' | ' . $auto_updates_disabled_str;
+                                       $theme_version_string_debug .= ', ' . $auto_updates_disabled_str;
+                               }
+                       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         $info['wp-themes-inactive']['fields'][ sanitize_text_field( $theme->name ) ] = array(
</span><span class="cx" style="display: block; padding: 0 10px">                                'label' => sprintf(
</span><span class="cx" style="display: block; padding: 0 10px">                                        /* translators: 1: Theme name. 2: Theme slug. */
</span></span></pre></div>
<a id="trunksrcwpadminincludesclasswpmsthemeslisttablephp"></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-ms-themes-list-table.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-wp-ms-themes-list-table.php     2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/includes/class-wp-ms-themes-list-table.php       2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -23,6 +23,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">        private $has_items;
</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">+         * Whether to show the auto-updates UI.
+        *
+        * @since 5.5.0
+        *
+        * @var bool True if auto-updates UI is to be shown, false otherwise.
+        */
+       protected $show_autoupdates = true;
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Constructor.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 3.1.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -45,7 +54,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">                $status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( ! in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken' ), true ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( ! in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken', 'auto-update-enabled', 'auto-update-disabled' ), true ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         $status = 'all';
</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">@@ -56,6 +65,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $this->is_site_themes ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
</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->show_autoupdates = wp_is_auto_update_enabled_for_type( 'theme' ) &&
+                       ! $this->is_site_themes && current_user_can( 'update_themes' );
</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">@@ -107,6 +119,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        'broken'   => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ),
</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">+                if ( $this->show_autoupdates ) {
+                       $auto_updates = (array) get_site_option( 'auto_update_themes', array() );
+
+                       $themes['auto-update-enabled']  = array();
+                       $themes['auto-update-disabled'] = array();
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( $this->is_site_themes ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' );
</span><span class="cx" style="display: block; padding: 0 10px">                        $allowed_where   = 'site';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -131,6 +150,14 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        $filter                    = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled';
</span><span class="cx" style="display: block; padding: 0 10px">                        $themes[ $filter ][ $key ] = $themes['all'][ $key ];
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                       if ( $this->show_autoupdates ) {
+                               if ( in_array( $key, $auto_updates, true ) ) {
+                                       $themes['auto-update-enabled'][ $key ] = $themes['all'][ $key ];
+                               } else {
+                                       $themes['auto-update-disabled'][ $key ] = $themes['all'][ $key ];
+                               }
+                       }
</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">                if ( $s ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -257,11 +284,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return array
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function get_columns() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return array(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $columns = array(
</ins><span class="cx" style="display: block; padding: 0 10px">                         'cb'          => '<input type="checkbox" />',
</span><span class="cx" style="display: block; padding: 0 10px">                        'name'        => __( 'Theme' ),
</span><span class="cx" style="display: block; padding: 0 10px">                        'description' => __( 'Description' ),
</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 ( $this->show_autoupdates ) {
+                       $columns['auto-updates'] = __( 'Automatic Updates' );
+               }
+
+               return $columns;
</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">@@ -344,6 +377,22 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                                'themes'
</span><span class="cx" style="display: block; padding: 0 10px">                                        );
</span><span class="cx" style="display: block; padding: 0 10px">                                        break;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                case 'auto-update-enabled':
+                                       /* translators: %s: Number of themes. */
+                                       $text = _n(
+                                               'Auto-updates Enabled <span class="count">(%s)</span>',
+                                               'Auto-updates Enabled <span class="count">(%s)</span>',
+                                               $count
+                                       );
+                                       break;
+                               case 'auto-update-disabled':
+                                       /* translators: %s: Number of themes. */
+                                       $text = _n(
+                                               'Auto-updates Disabled <span class="count">(%s)</span>',
+                                               'Auto-updates Disabled <span class="count">(%s)</span>',
+                                               $count
+                                       );
+                                       break;
</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">                        if ( $this->is_site_themes ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -388,6 +437,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                $actions['delete-selected'] = __( 'Delete' );
</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">+
+               if ( $this->show_autoupdates ) {
+                       if ( 'auto-update-enabled' !== $status ) {
+                               $actions['enable-auto-update-selected'] = __( 'Enable Auto-updates' );
+                       }
+
+                       if ( 'auto-update-disabled' !== $status ) {
+                               $actions['disable-auto-update-selected'] = __( 'Disable Auto-updates' );
+                       }
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 return $actions;
</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,6 +700,70 @@
</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">+         * Handles the auto-updates column output.
+        *
+        * @since 5.5.0
+        *
+        * @global string $status
+        * @global int  $page
+        *
+        * @param WP_Theme $theme The current WP_Theme object.
+        */
+       public function column_autoupdates( $theme ) {
+               global $status, $page;
+
+               static $auto_updates, $available_updates;
+
+               if ( ! $auto_updates ) {
+                       $auto_updates = (array) get_site_option( 'auto_update_themes', array() );
+               }
+               if ( ! $available_updates ) {
+                       $available_updates = get_site_transient( 'update_themes' );
+               }
+
+               $stylesheet = $theme->get_stylesheet();
+
+               if ( in_array( $stylesheet, $auto_updates, true ) ) {
+                       $text       = __( 'Disable auto-updates' );
+                       $action     = 'disable';
+                       $time_class = '';
+               } else {
+                       $text       = __( 'Enable auto-updates' );
+                       $action     = 'enable';
+                       $time_class = ' hidden';
+               }
+
+               $query_args = array(
+                       'action'       => "{$action}-auto-update",
+                       'theme'        => $stylesheet,
+                       'paged'        => $page,
+                       'theme_status' => $status,
+               );
+
+               $url = add_query_arg( $query_args, 'themes.php' );
+
+               printf(
+                       '<a href="%s" class="toggle-auto-update" data-wp-action="%s">',
+                       wp_nonce_url( $url, 'updates' ),
+                       $action
+               );
+
+               echo '<span class="dashicons dashicons-update spin hidden"></span>';
+               echo '<span class="label">' . $text . '</span>';
+               echo '</a>';
+
+               $available_updates = get_site_transient( 'update_themes' );
+               if ( isset( $available_updates->response[ $stylesheet ] ) ) {
+                       printf(
+                               '<div class="auto-update-time%s">%s</div>',
+                               $time_class,
+                               wp_get_auto_update_message()
+                       );
+               }
+               echo '<div class="auto-updates-error inline notice error hidden"><p></p></div>';
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Handles default column output.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 4.3.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -721,6 +845,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        echo '</td>';
</span><span class="cx" style="display: block; padding: 0 10px">                                        break;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                case 'auto-updates':
+                                       echo "<td class='column-auto-updates{$extra_classes}'>";
+
+                                       $this->column_autoupdates( $item );
+
+                                       echo '</td>';
+                                       break;
</ins><span class="cx" style="display: block; padding: 0 10px">                                 default:
</span><span class="cx" style="display: block; padding: 0 10px">                                        echo "<td class='$column_name column-$column_name{$extra_classes}'>";
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpadminincludesclasswppluginslisttablephp"></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-plugins-list-table.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-wp-plugins-list-table.php       2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/includes/class-wp-plugins-list-table.php 2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -16,6 +16,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @see WP_List_Table
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> class WP_Plugins_List_Table extends WP_List_Table {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * Whether to show the auto-updates UI.
+        *
+        * @since 5.5.0
+        *
+        * @var bool True if auto-updates UI is to be shown, false otherwise.
+        */
+       protected $show_autoupdates = true;
</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">         * Constructor.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -39,7 +47,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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $status_whitelist = array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search', 'paused' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $status_whitelist = array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search', 'paused', 'auto-update-enabled', 'auto-update-disabled' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $status = 'all';
</span><span class="cx" style="display: block; padding: 0 10px">                if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], $status_whitelist, true ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -51,6 +59,10 @@
</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">                $page = $this->get_pagenum();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               $this->show_autoupdates = wp_is_auto_update_enabled_for_type( 'plugin' ) &&
+                       current_user_can( 'update_plugins' ) &&
+                       ( ! is_multisite() || $this->screen->in_admin( 'network' ) );
</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">@@ -103,7 +115,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        'dropins'            => array(),
</span><span class="cx" style="display: block; padding: 0 10px">                        'paused'             => array(),
</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 ( $this->show_autoupdates ) {
+                       $auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        $plugins['auto-update-enabled']  = array();
+                       $plugins['auto-update-disabled'] = array();
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $screen = $this->screen;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! is_multisite() || ( $screen->in_admin( 'network' ) && current_user_can( 'manage_network_plugins' ) ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -233,6 +251,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                // Populate the inactive list with plugins that aren't activated.
</span><span class="cx" style="display: block; padding: 0 10px">                                $plugins['inactive'][ $plugin_file ] = $plugin_data;
</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 ( $this->show_autoupdates ) {
+                               if ( in_array( $plugin_file, $auto_updates, true ) ) {
+                                       $plugins['auto-update-enabled'][ $plugin_file ] = $plugins['all'][ $plugin_file ];
+                               } else {
+                                       $plugins['auto-update-disabled'][ $plugin_file ] = $plugins['all'][ $plugin_file ];
+                               }
+                       }
</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">                if ( strlen( $s ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -399,11 +425,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public function get_columns() {
</span><span class="cx" style="display: block; padding: 0 10px">                global $status;
</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 array(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $columns = array(
</ins><span class="cx" style="display: block; padding: 0 10px">                         'cb'          => ! in_array( $status, array( 'mustuse', 'dropins' ), true ) ? '<input type="checkbox" />' : '',
</span><span class="cx" style="display: block; padding: 0 10px">                        'name'        => __( 'Plugin' ),
</span><span class="cx" style="display: block; padding: 0 10px">                        'description' => __( 'Description' ),
</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 ( $this->show_autoupdates ) {
+                       $columns['auto-updates'] = __( 'Automatic Updates' );
+               }
+
+               return $columns;
</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">@@ -493,6 +525,22 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                                $count
</span><span class="cx" style="display: block; padding: 0 10px">                                        );
</span><span class="cx" style="display: block; padding: 0 10px">                                        break;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                case 'auto-update-enabled':
+                                       /* translators: %s: Number of plugins. */
+                                       $text = _n(
+                                               'Auto-updates Enabled <span class="count">(%s)</span>',
+                                               'Auto-updates Enabled <span class="count">(%s)</span>',
+                                               $count
+                                       );
+                                       break;
+                               case 'auto-update-disabled':
+                                       /* translators: %s: Number of plugins. */
+                                       $text = _n(
+                                               'Auto-updates Disabled <span class="count">(%s)</span>',
+                                               'Auto-updates Disabled <span class="count">(%s)</span>',
+                                               $count
+                                       );
+                                       break;
</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">                        if ( 'search' !== $type ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -533,6 +581,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( current_user_can( 'delete_plugins' ) && ( 'active' !== $status ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                $actions['delete-selected'] = __( 'Delete' );
</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 ( $this->show_autoupdates ) {
+                               if ( 'auto-update-enabled' !== $status ) {
+                                       $actions['enable-auto-update-selected'] = __( 'Enable Auto-updates' );
+                               }
+                               if ( 'auto-update-disabled' !== $status ) {
+                                       $actions['disable-auto-update-selected'] = __( 'Disable Auto-updates' );
+                               }
+                       }
</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">                return $actions;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -882,6 +939,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $auto_updates      = (array) get_site_option( 'auto_update_plugins', array() );
+               $available_updates = get_site_transient( 'update_plugins' );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 foreach ( $columns as $column_name => $column_display_name ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $extra_classes = '';
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( in_array( $column_name, $hidden, true ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -974,6 +1034,56 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                        echo '</td>';
</span><span class="cx" style="display: block; padding: 0 10px">                                        break;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                case 'auto-updates':
+                                       if ( ! $this->show_autoupdates ) {
+                                               break;
+                                       }
+
+                                       echo "<td class='column-auto-updates{$extra_classes}'>";
+
+                                       if ( in_array( $plugin_file, $auto_updates, true ) ) {
+                                               $text       = __( 'Disable auto-updates' );
+                                               $action     = 'disable';
+                                               $time_class = '';
+                                       } else {
+                                               $text       = __( 'Enable auto-updates' );
+                                               $action     = 'enable';
+                                               $time_class = ' hidden';
+                                       }
+
+                                       $query_args = array(
+                                               'action'        => "{$action}-auto-update",
+                                               'plugin'        => $plugin_file,
+                                               'paged'         => $page,
+                                               'plugin_status' => $status,
+                                       );
+
+                                       $url = add_query_arg( $query_args, 'plugins.php' );
+
+                                       printf(
+                                               '<a href="%s" class="toggle-auto-update" data-wp-action="%s">',
+                                               wp_nonce_url( $url, 'updates' ),
+                                               $action
+                                       );
+
+                                       echo '<span class="dashicons dashicons-update spin hidden"></span>';
+                                       echo '<span class="label">' . $text . '</span>';
+                                       echo '</a>';
+
+                                       $available_updates = get_site_transient( 'update_plugins' );
+
+                                       if ( isset( $available_updates->response[ $plugin_file ] ) ) {
+                                               printf(
+                                                       '<div class="auto-update-time%s">%s</div>',
+                                                       $time_class,
+                                                       wp_get_auto_update_message()
+                                               );
+                                       }
+
+                                       echo '<div class="inline notice error hidden"><p></p></div>';
+                                       echo '</td>';
+
+                                       break;
</ins><span class="cx" style="display: block; padding: 0 10px">                                 default:
</span><span class="cx" style="display: block; padding: 0 10px">                                        $classes = "$column_name column-$column_name $class";
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1000,12 +1110,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 * Fires after each row in the Plugins list table.
</span><span class="cx" style="display: block; padding: 0 10px">                 *
</span><span class="cx" style="display: block; padding: 0 10px">                 * @since 2.3.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 * @since 5.5.0 Added 'Auto-updates Enabled' and 'Auto-updates Disabled' `$status`.
</ins><span class="cx" style="display: block; padding: 0 10px">                  *
</span><span class="cx" style="display: block; padding: 0 10px">                 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
</span><span class="cx" style="display: block; padding: 0 10px">                 * @param array  $plugin_data An array of plugin data.
</span><span class="cx" style="display: block; padding: 0 10px">                 * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
</span><span class="cx" style="display: block; padding: 0 10px">                 *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                 *                            'Drop-ins', 'Search', 'Paused'.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          *                            'Drop-ins', 'Search', 'Paused', 'Auto-updates Enabled',
+                *                            'Auto-updates Disabled'.
</ins><span class="cx" style="display: block; padding: 0 10px">                  */
</span><span class="cx" style="display: block; padding: 0 10px">                do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1016,12 +1128,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 * to the plugin file, relative to the plugins directory.
</span><span class="cx" style="display: block; padding: 0 10px">                 *
</span><span class="cx" style="display: block; padding: 0 10px">                 * @since 2.7.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 * @since 5.5.0 Added 'Auto-updates Enabled' and 'Auto-updates Disabled' `$status`.
</ins><span class="cx" style="display: block; padding: 0 10px">                  *
</span><span class="cx" style="display: block; padding: 0 10px">                 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
</span><span class="cx" style="display: block; padding: 0 10px">                 * @param array  $plugin_data An array of plugin data.
</span><span class="cx" style="display: block; padding: 0 10px">                 * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
</span><span class="cx" style="display: block; padding: 0 10px">                 *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                 *                            'Drop-ins', 'Search', 'Paused'.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          *                            'Drop-ins', 'Search', 'Paused', 'Auto-updates Enabled',
+                *                            'Auto-updates Disabled'.
</ins><span class="cx" style="display: block; padding: 0 10px">                  */
</span><span class="cx" style="display: block; padding: 0 10px">                do_action( "after_plugin_row_{$plugin_file}", $plugin_file, $plugin_data, $status );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span></span></pre></div>
<a id="trunksrcwpadminincludesthemephp"></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.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/theme.php     2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/includes/theme.php       2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -660,6 +660,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $parents = array();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $auto_updates = (array) get_site_option( 'auto_update_themes', array() );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         foreach ( $themes as $theme ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $slug         = $theme->get_stylesheet();
</span><span class="cx" style="display: block; padding: 0 10px">                $encoded_slug = urlencode( $slug );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -683,6 +685,9 @@
</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">+                $auto_update        = in_array( $slug, $auto_updates, true );
+               $auto_update_action = $auto_update ? 'disable-auto-update' : 'enable-auto-update';
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $prepared_themes[ $slug ] = array(
</span><span class="cx" style="display: block; padding: 0 10px">                        'id'            => $slug,
</span><span class="cx" style="display: block; padding: 0 10px">                        'name'          => $theme->display( 'Name' ),
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -699,10 +704,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        'hasUpdate'     => isset( $updates[ $slug ] ),
</span><span class="cx" style="display: block; padding: 0 10px">                        'hasPackage'    => isset( $updates[ $slug ] ) && ! empty( $updates[ $slug ]['package'] ),
</span><span class="cx" style="display: block; padding: 0 10px">                        'update'        => get_theme_update_available( $theme ),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'autoupdate'    => $auto_update,
</ins><span class="cx" style="display: block; padding: 0 10px">                         'actions'       => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'activate'  => current_user_can( 'switch_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=activate&amp;stylesheet=' . $encoded_slug ), 'switch-theme_' . $slug ) : null,
-                               'customize' => $customize_action,
-                               'delete'    => current_user_can( 'delete_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=delete&amp;stylesheet=' . $encoded_slug ), 'delete-theme_' . $slug ) : null,
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'activate'   => current_user_can( 'switch_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=activate&amp;stylesheet=' . $encoded_slug ), 'switch-theme_' . $slug ) : null,
+                               'customize'  => $customize_action,
+                               'delete'     => current_user_can( 'delete_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=delete&amp;stylesheet=' . $encoded_slug ), 'delete-theme_' . $slug ) : null,
+                               'autoupdate' => wp_is_auto_update_enabled_for_type( 'theme' ) && ! is_multisite() && current_user_can( 'update_themes' )
+                                       ? wp_nonce_url( admin_url( 'themes.php?action=' . $auto_update_action . '&amp;stylesheet=' . $encoded_slug ), 'updates' )
+                                       : null,
</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="trunksrcwpadminincludesupdatephp"></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/update.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/update.php    2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/includes/update.php      2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -435,7 +435,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $details_url = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $response->slug . '&section=changelog&TB_iframe=true&width=600&height=800' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /** @var WP_Plugins_List_Table $wp_list_table */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $wp_list_table = _get_list_table(
+               'WP_Plugins_List_Table',
+               array(
+                       'screen' => get_current_screen(),
+               )
+       );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( is_network_admin() || ! is_multisite() ) {
</span><span class="cx" style="display: block; padding: 0 10px">                if ( is_network_admin() ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -933,3 +938,76 @@
</span><span class="cx" style="display: block; padding: 0 10px">        </div>
</span><span class="cx" style="display: block; padding: 0 10px">        <?php
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+/**
+ * Checks whether auto-updates are enabled.
+ *
+ * @since 5.5.0
+ *
+ * @param string $type    The type of update being checked: 'theme' or 'plugin'.
+ * @return bool True if auto-updates are enabled for `$type`, false otherwise.
+ */
+function wp_is_auto_update_enabled_for_type( $type ) {
+       switch ( $type ) {
+               case 'plugin':
+                       /**
+                        * Filters whether plugins manual auto-update is enabled.
+                        *
+                        * @since 5.5.0
+                        *
+                        * @param bool $enabled True if plugins auto-update is enabled, false otherwise.
+                        */
+                       return apply_filters( 'wp_plugins_auto_update_enabled', true );
+               case 'theme':
+                       /**
+                        * Filters whether plugins manual auto-update is enabled.
+                        *
+                        * @since 5.5.0
+                        *
+                        * @param bool True if themes auto-update is enabled, false otherwise.
+                        */
+                       return apply_filters( 'wp_themes_auto_update_enabled', true );
+       }
+
+       return false;
+}
+
+/**
+ * Determines the appropriate update message to be displayed.
+ *
+ * @since 5.5.0
+ *
+ * @return string The update message to be shown.
+ */
+function wp_get_auto_update_message() {
+       $next_update_time = wp_next_scheduled( 'wp_version_check' );
+
+       // Check if event exists.
+       if ( false === $next_update_time ) {
+               return __( 'There may be a problem with WP-Cron. Automatic update not scheduled.' );
+       }
+
+       // See if cron is disabled
+       $cron_disabled = defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON;
+       if ( $cron_disabled ) {
+               return __( 'WP-Cron is disabled. Automatic updates not available.' );
+       }
+
+       $time_to_next_update = human_time_diff( intval( $next_update_time ) );
+
+       // See if cron is overdue.
+       $overdue = ( time() - $next_update_time ) > 0;
+       if ( $overdue ) {
+               return sprintf(
+                       /* translators: Duration that WP-Cron has been overdue. */
+                       __( 'There may be a problem with WP-Cron. Automatic update overdue by %s.' ),
+                       $time_to_next_update
+               );
+       } else {
+               return sprintf(
+                       /* translators: Time until the next update. */
+                       __( 'Auto-update scheduled in %s.' ),
+                       $time_to_next_update
+               );
+       }
+}
</ins></span></pre></div>
<a id="trunksrcwpadminnetworkthemesphp"></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/network/themes.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/network/themes.php     2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/network/themes.php       2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -22,7 +22,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $s = isset( $_REQUEST['s'] ) ? $_REQUEST['s'] : '';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // Clean up request URI from temporary args for screen options/paging uri's to work as expected.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-$temp_args              = array( 'enabled', 'disabled', 'deleted', 'error' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+$temp_args = array(
+       'enabled',
+       'disabled',
+       'deleted',
+       'error',
+       'enabled-auto-update',
+       'disabled-auto-update',
+);
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $_SERVER['REQUEST_URI'] = remove_query_arg( $temp_args, $_SERVER['REQUEST_URI'] );
</span><span class="cx" style="display: block; padding: 0 10px"> $referer                = remove_query_arg( $temp_args, wp_get_referer() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -123,8 +131,8 @@
</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">                                $themes_to_delete = count( $themes );
</span><span class="cx" style="display: block; padding: 0 10px">                                ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        <div class="wrap">
-                               <?php if ( 1 == $themes_to_delete ) : ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         <div class="wrap">
+                               <?php if ( 1 === $themes_to_delete ) : ?>
</ins><span class="cx" style="display: block; padding: 0 10px">                                         <h1><?php _e( 'Delete Theme' ); ?></h1>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <div class="error"><p><strong><?php _e( 'Caution:' ); ?></strong> <?php _e( 'This theme may be active on other sites in the network.' ); ?></p></div>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <p><?php _e( 'You are about to remove the following theme:' ); ?></p>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -145,7 +153,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">                                        </ul>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                <?php if ( 1 == $themes_to_delete ) : ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         <?php if ( 1 === $themes_to_delete ) : ?>
</ins><span class="cx" style="display: block; padding: 0 10px">                                         <p><?php _e( 'Are you sure you want to delete this theme?' ); ?></p>
</span><span class="cx" style="display: block; padding: 0 10px">                                <?php else : ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <p><?php _e( 'Are you sure you want to delete these themes?' ); ?></p>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -154,27 +162,28 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        <input type="hidden" name="verify-delete" value="1" />
</span><span class="cx" style="display: block; padding: 0 10px">                                        <input type="hidden" name="action" value="delete-selected" />
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                         foreach ( (array) $themes as $theme ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                                echo '<input type="hidden" name="checked[]" value="' . esc_attr( $theme ) . '" />';
</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">-                                                wp_nonce_field( 'bulk-themes' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 wp_nonce_field( 'bulk-themes' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        if ( 1 == $themes_to_delete ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 if ( 1 === $themes_to_delete ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 submit_button( __( 'Yes, delete this theme' ), '', 'submit', false );
</span><span class="cx" style="display: block; padding: 0 10px">                                        } else {
</span><span class="cx" style="display: block; padding: 0 10px">                                                submit_button( __( 'Yes, delete these themes' ), '', 'submit', false );
</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">                                         ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                </form>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                <?php
-                               $referer = wp_get_referer();
-                               ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         <?php $referer = wp_get_referer(); ?>
</ins><span class="cx" style="display: block; padding: 0 10px">                                 <form method="post" action="<?php echo $referer ? esc_url( $referer ) : ''; ?>" style="display:inline;">
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php submit_button( __( 'No, return me to the theme list' ), '', 'submit', false ); ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                </form>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        </div>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         </div>
</ins><span class="cx" style="display: block; padding: 0 10px">                                 <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                 require_once ABSPATH . 'wp-admin/admin-footer.php';
</span><span class="cx" style="display: block; padding: 0 10px">                                exit;
</span><span class="cx" style="display: block; padding: 0 10px">                        } // End if verify-delete.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -208,6 +217,58 @@
</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">                        exit;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                case 'enable-auto-update':
+               case 'disable-auto-update':
+               case 'enable-auto-update-selected':
+               case 'disable-auto-update-selected':
+                       if ( ! ( current_user_can( 'update_themes' ) && wp_is_auto_update_enabled_for_type( 'theme' ) ) ) {
+                               wp_die( __( 'Sorry, you are not allowed to change themes automatic update settings.' ) );
+                       }
+
+                       if ( 'enable-auto-update' === $action || 'disable-auto-update' === $action ) {
+                               check_admin_referer( 'updates' );
+                       } else {
+                               if ( empty( $_POST['checked'] ) ) {
+                                       // Nothing to do.
+                                       wp_safe_redirect( add_query_arg( 'error', 'none', $referer ) );
+                                       exit;
+                               }
+
+                               check_admin_referer( 'bulk-themes' );
+                       }
+
+                       $auto_updates = (array) get_site_option( 'auto_update_themes', array() );
+
+                       if ( 'enable-auto-update' === $action ) {
+                               $auto_updates[] = $_GET['theme'];
+                               $auto_updates   = array_unique( $auto_updates );
+                               $referer        = add_query_arg( 'enabled-auto-update', 1, $referer );
+                       } elseif ( 'disable-auto-update' === $action ) {
+                               $auto_updates = array_diff( $auto_updates, array( $_GET['theme'] ) );
+                               $referer      = add_query_arg( 'disabled-auto-update', 1, $referer );
+                       } else {
+                               // Bulk enable/disable.
+                               $themes = (array) wp_unslash( $_POST['checked'] );
+
+                               if ( 'enable-auto-update-selected' === $action ) {
+                                       $auto_updates = array_merge( $auto_updates, $themes );
+                                       $auto_updates = array_unique( $auto_updates );
+                                       $referer      = add_query_arg( 'enabled-auto-update', count( $themes ), $referer );
+                               } else {
+                                       $auto_updates = array_diff( $auto_updates, $themes );
+                                       $referer      = add_query_arg( 'disabled-auto-update', count( $themes ), $referer );
+                               }
+                       }
+
+                       $all_items = wp_get_themes();
+
+                       // Remove themes that don't exist or have been deleted since the option was last updated.
+                       $auto_updates = array_intersect( $auto_updates, array_keys( $all_items ) );
+
+                       update_site_option( 'auto_update_themes', $auto_updates );
+
+                       wp_safe_redirect( $referer );
+                       exit;
</ins><span class="cx" style="display: block; padding: 0 10px">                 default:
</span><span class="cx" style="display: block; padding: 0 10px">                        $themes = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( empty( $themes ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -284,7 +345,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="cx" style="display: block; padding: 0 10px"> if ( isset( $_GET['enabled'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">        $enabled = absint( $_GET['enabled'] );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if ( 1 == $enabled ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( 1 === $enabled ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 $message = __( 'Theme enabled.' );
</span><span class="cx" style="display: block; padding: 0 10px">        } else {
</span><span class="cx" style="display: block; padding: 0 10px">                /* translators: %s: Number of themes. */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -293,7 +354,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        echo '<div id="message" class="updated notice is-dismissible"><p>' . sprintf( $message, number_format_i18n( $enabled ) ) . '</p></div>';
</span><span class="cx" style="display: block; padding: 0 10px"> } elseif ( isset( $_GET['disabled'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">        $disabled = absint( $_GET['disabled'] );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if ( 1 == $disabled ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( 1 === $disabled ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 $message = __( 'Theme disabled.' );
</span><span class="cx" style="display: block; padding: 0 10px">        } else {
</span><span class="cx" style="display: block; padding: 0 10px">                /* translators: %s: Number of themes. */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -302,7 +363,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        echo '<div id="message" class="updated notice is-dismissible"><p>' . sprintf( $message, number_format_i18n( $disabled ) ) . '</p></div>';
</span><span class="cx" style="display: block; padding: 0 10px"> } elseif ( isset( $_GET['deleted'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">        $deleted = absint( $_GET['deleted'] );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if ( 1 == $deleted ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( 1 === $deleted ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 $message = __( 'Theme deleted.' );
</span><span class="cx" style="display: block; padding: 0 10px">        } else {
</span><span class="cx" style="display: block; padding: 0 10px">                /* translators: %s: Number of themes. */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -309,9 +370,27 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $message = _n( '%s theme deleted.', '%s themes deleted.', $deleted );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px">        echo '<div id="message" class="updated notice is-dismissible"><p>' . sprintf( $message, number_format_i18n( $deleted ) ) . '</p></div>';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-} elseif ( isset( $_GET['error'] ) && 'none' == $_GET['error'] ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+} elseif ( isset( $_GET['enabled-auto-update'] ) ) {
+       $enabled = absint( $_GET['enabled-auto-update'] );
+       if ( 1 === $enabled ) {
+               $message = __( 'Theme will be auto-updated.' );
+       } else {
+               /* translators: %s: Number of themes. */
+               $message = _n( '%s theme will be auto-updated.', '%s themes will be auto-updated.', $enabled );
+       }
+       echo '<div id="message" class="updated notice is-dismissible"><p>' . sprintf( $message, number_format_i18n( $enabled ) ) . '</p></div>';
+} elseif ( isset( $_GET['disabled-auto-update'] ) ) {
+       $disabled = absint( $_GET['disabled-auto-update'] );
+       if ( 1 === $disabled ) {
+               $message = __( 'Theme will no longer be auto-updated.' );
+       } else {
+               /* translators: %s: Number of themes. */
+               $message = _n( '%s theme will no longer be auto-updated.', '%s themes will no longer be auto-updated.', $disabled );
+       }
+       echo '<div id="message" class="updated notice is-dismissible"><p>' . sprintf( $message, number_format_i18n( $disabled ) ) . '</p></div>';
+} elseif ( isset( $_GET['error'] ) && 'none' === $_GET['error'] ) {
</ins><span class="cx" style="display: block; padding: 0 10px">         echo '<div id="message" class="error notice is-dismissible"><p>' . __( 'No theme selected.' ) . '</p></div>';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-} elseif ( isset( $_GET['error'] ) && 'main' == $_GET['error'] ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+} elseif ( isset( $_GET['error'] ) && 'main' === $_GET['error'] ) {
</ins><span class="cx" style="display: block; padding: 0 10px">         echo '<div class="error notice is-dismissible"><p>' . __( 'You cannot delete a theme while it is active on the main site.' ) . '</p></div>';
</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">@@ -324,7 +403,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="cx" style="display: block; padding: 0 10px"> $wp_list_table->views();
</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 ( 'broken' == $status ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+if ( 'broken' === $status ) {
</ins><span class="cx" style="display: block; padding: 0 10px">         echo '<p class="clear">' . __( 'The following themes are installed but incomplete.' ) . '</p>';
</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="trunksrcwpadminpluginsphp"></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/plugins.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/plugins.php    2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/plugins.php      2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -22,8 +22,22 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $s      = isset( $_REQUEST['s'] ) ? urlencode( wp_unslash( $_REQUEST['s'] ) ) : '';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // Clean up request URI from temporary args for screen options/paging uri's to work as expected.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-$_SERVER['REQUEST_URI'] = remove_query_arg( array( 'error', 'deleted', 'activate', 'activate-multi', 'deactivate', 'deactivate-multi', '_error_nonce' ), $_SERVER['REQUEST_URI'] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+$query_args_to_remove = array(
+       'error',
+       'deleted',
+       'activate',
+       'activate-multi',
+       'deactivate',
+       'deactivate-multi',
+       'enabled-auto-update',
+       'disabled-auto-update',
+       'enabled-auto-update-multi',
+       'disabled-auto-update-multi',
+       '_error_nonce',
+);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+$_SERVER['REQUEST_URI'] = remove_query_arg( $query_args_to_remove, $_SERVER['REQUEST_URI'] );
+
</ins><span class="cx" style="display: block; padding: 0 10px"> wp_enqueue_script( 'updates' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> if ( $action ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -284,11 +298,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( ! isset( $_REQUEST['verify-delete'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                wp_enqueue_script( 'jquery' );
</span><span class="cx" style="display: block; padding: 0 10px">                                require_once ABSPATH . 'wp-admin/admin-header.php';
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                 ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        <div class="wrap">
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         <div class="wrap">
</ins><span class="cx" style="display: block; padding: 0 10px">                                 <?php
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        $plugin_info              = array();
-                                       $have_non_network_plugins = false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                               $plugin_info              = array();
+                               $have_non_network_plugins = false;
+
</ins><span class="cx" style="display: block; padding: 0 10px">                                 foreach ( (array) $plugins as $plugin ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        $plugin_slug = dirname( $plugin );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -315,9 +332,11 @@
</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">-                                        $plugins_to_delete = count( $plugin_info );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                               $plugins_to_delete = count( $plugin_info );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                                 ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                <?php if ( 1 == $plugins_to_delete ) : ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         <?php if ( 1 === $plugins_to_delete ) : ?>
</ins><span class="cx" style="display: block; padding: 0 10px">                                         <h1><?php _e( 'Delete Plugin' ); ?></h1>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php if ( $have_non_network_plugins && is_network_admin() ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                                <div class="error"><p><strong><?php _e( 'Caution:' ); ?></strong> <?php _e( 'This plugin may be active on other sites in the network.' ); ?></p></div>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -332,7 +351,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                <?php endif; ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <ul class="ul-disc">
</span><span class="cx" style="display: block; padding: 0 10px">                                                <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 $data_to_delete = false;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 foreach ( $plugin_info as $plugin ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                                        if ( $plugin['is_uninstallable'] ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                                                /* translators: 1: Plugin name, 2: Plugin author. */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -343,15 +364,18 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                                                echo '<li>', sprintf( _x( '%1$s by %2$s', 'plugin' ), '<strong>' . $plugin['Name'] . '</strong>', '<em>' . $plugin['AuthorName'] ) . '</em>', '</li>';
</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">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                        </ul>
</span><span class="cx" style="display: block; padding: 0 10px">                                <p>
</span><span class="cx" style="display: block; padding: 0 10px">                                <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                 if ( $data_to_delete ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        _e( 'Are you sure you want to delete these files and data?' );
</span><span class="cx" style="display: block; padding: 0 10px">                                } else {
</span><span class="cx" style="display: block; padding: 0 10px">                                        _e( 'Are you sure you want to delete these files?' );
</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">                                 ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                </p>
</span><span class="cx" style="display: block; padding: 0 10px">                                <form method="post" action="<?php echo esc_url( $_SERVER['REQUEST_URI'] ); ?>" style="display:inline;">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -358,21 +382,26 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        <input type="hidden" name="verify-delete" value="1" />
</span><span class="cx" style="display: block; padding: 0 10px">                                        <input type="hidden" name="action" value="delete-selected" />
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                         foreach ( (array) $plugins as $plugin ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                                echo '<input type="hidden" name="checked[]" value="' . esc_attr( $plugin ) . '" />';
</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">                                         ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php wp_nonce_field( 'bulk-plugins' ); ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php submit_button( $data_to_delete ? __( 'Yes, delete these files and data' ) : __( 'Yes, delete these files' ), '', '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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                 $referer = wp_get_referer();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                 ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                <form method="post" action="<?php echo $referer ? esc_url( $referer ) : ''; ?>" style="display:inline;">
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php submit_button( __( 'No, return me to the plugin list' ), '', 'submit', false ); ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                </form>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        </div>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         </div>
</ins><span class="cx" style="display: block; padding: 0 10px">                                 <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                 require_once ABSPATH . 'wp-admin/admin-footer.php';
</span><span class="cx" style="display: block; padding: 0 10px">                                exit;
</span><span class="cx" style="display: block; padding: 0 10px">                        } else {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -385,7 +414,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        set_transient( 'plugins_delete_result_' . $user_ID, $delete_result );
</span><span class="cx" style="display: block; padding: 0 10px">                        wp_redirect( self_admin_url( "plugins.php?deleted=$plugins_to_delete&plugin_status=$status&paged=$page&s=$s" ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        exit;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 case 'clear-recent-list':
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( ! is_network_admin() ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                update_option( 'recently_activated', array() );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -392,8 +420,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        } else {
</span><span class="cx" style="display: block; padding: 0 10px">                                update_site_option( 'recently_activated', array() );
</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">                         break;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 case 'resume':
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( is_multisite() ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                return;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -413,7 +441,78 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        wp_redirect( self_admin_url( "plugins.php?resume=true&plugin_status=$status&paged=$page&s=$s" ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        exit;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                case 'enable-auto-update':
+               case 'disable-auto-update':
+               case 'enable-auto-update-selected':
+               case 'disable-auto-update-selected':
+                       if ( ! current_user_can( 'update_plugins' ) || ! wp_is_auto_update_enabled_for_type( 'plugin' ) ) {
+                               wp_die( __( 'Sorry, you are not allowed to manage plugins automatic updates.' ) );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        if ( is_multisite() && ! is_network_admin() ) {
+                               wp_die( __( 'Please connect to your network admin to manage plugins automatic updates.' ) );
+                       }
+
+                       $redirect = self_admin_url( "plugins.php?plugin_status={$status}&paged={$page}&s={$s}" );
+
+                       if ( 'enable-auto-update' === $action || 'disable-auto-update' === $action ) {
+                               if ( empty( $plugin ) ) {
+                                       wp_redirect( $redirect );
+                                       exit;
+                               }
+
+                               check_admin_referer( 'updates' );
+                       } else {
+                               if ( empty( $_POST['checked'] ) ) {
+                                       wp_redirect( $redirect );
+                                       exit;
+                               }
+
+                               check_admin_referer( 'bulk-plugins' );
+                       }
+
+                       $auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
+
+                       if ( 'enable-auto-update' === $action ) {
+                               $auto_updates[] = $plugin;
+                               $auto_updates   = array_unique( $auto_updates );
+                               $redirect       = add_query_arg( array( 'enabled-auto-update' => 'true' ), $redirect );
+                       } elseif ( 'disable-auto-update' === $action ) {
+                               $auto_updates = array_diff( $auto_updates, array( $plugin ) );
+                               $redirect     = add_query_arg( array( 'disabled-auto-update' => 'true' ), $redirect );
+                       } else {
+                               $plugins = (array) wp_unslash( $_POST['checked'] );
+
+                               if ( 'enable-auto-update-selected' === $action ) {
+                                       $new_auto_updates = array_merge( $auto_updates, $plugins );
+                                       $new_auto_updates = array_unique( $new_auto_updates );
+                                       $query_args       = array( 'enabled-auto-update-multi' => 'true' );
+                               } else {
+                                       $new_auto_updates = array_diff( $auto_updates, $plugins );
+                                       $query_args       = array( 'disabled-auto-update-multi' => 'true' );
+                               }
+
+                               // Return early if all selected plugins already have auto-updates enabled or disabled.
+                               // Must use non-strict comparison, so that array order is not treated as significant.
+                               if ( $new_auto_updates == $auto_updates ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
+                                       wp_redirect( $redirect );
+                                       exit;
+                               }
+
+                               $auto_updates = $new_auto_updates;
+                               $redirect     = add_query_arg( $query_args, $redirect );
+                       }
+
+                       /** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */
+                       $all_items = apply_filters( 'all_plugins', get_plugins() );
+
+                       // Remove plugins that don't exist or have been deleted since the option was last updated.
+                       $auto_updates = array_intersect( $auto_updates, array_keys( $all_items ) );
+
+                       update_site_option( 'auto_update_plugins', $auto_updates );
+
+                       wp_redirect( $redirect );
+                       exit;
</ins><span class="cx" style="display: block; padding: 0 10px">                 default:
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( isset( $_POST['checked'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                check_admin_referer( 'bulk-plugins' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -498,9 +597,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                echo '</p></div>';
</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">-?>
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
</del><span class="cx" style="display: block; padding: 0 10px"> if ( isset( $_GET['error'] ) ) :
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( isset( $_GET['main'] ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -521,9 +618,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">        } else {
</span><span class="cx" style="display: block; padding: 0 10px">                $errmsg = __( 'Plugin could not be activated because it triggered a <strong>fatal error</strong>.' );
</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">         ?>
</span><span class="cx" style="display: block; padding: 0 10px">        <div id="message" class="error"><p><?php echo $errmsg; ?></p>
</span><span class="cx" style="display: block; padding: 0 10px">        <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">         if ( ! isset( $_GET['main'] ) && ! isset( $_GET['charsout'] ) && wp_verify_nonce( $_GET['_error_nonce'], 'plugin-activation-error_' . $plugin ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $iframe_url = add_query_arg(
</span><span class="cx" style="display: block; padding: 0 10px">                        array(
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -533,17 +632,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        ),
</span><span class="cx" style="display: block; padding: 0 10px">                        admin_url( 'plugins.php' )
</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">                 ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        <iframe style="border:0" width="100%" height="70px" src="<?php echo esc_url( $iframe_url ); ?>"></iframe>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         <iframe style="border:0" width="100%" height="70px" src="<?php echo esc_url( $iframe_url ); ?>"></iframe>
</ins><span class="cx" style="display: block; padding: 0 10px">                 <?php
</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">         ?>
</span><span class="cx" style="display: block; padding: 0 10px">        </div>
</span><span class="cx" style="display: block; padding: 0 10px">        <?php
</span><span class="cx" style="display: block; padding: 0 10px"> elseif ( isset( $_GET['deleted'] ) ) :
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $delete_result = get_transient( 'plugins_delete_result_' . $user_ID );
-               // Delete it once we're done.
-               delete_transient( 'plugins_delete_result_' . $user_ID );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $delete_result = get_transient( 'plugins_delete_result_' . $user_ID );
+       // Delete it once we're done.
+       delete_transient( 'plugins_delete_result_' . $user_ID );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( is_wp_error( $delete_result ) ) :
</span><span class="cx" style="display: block; padding: 0 10px">                ?>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -562,7 +663,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                <div id="message" class="updated notice is-dismissible">
</span><span class="cx" style="display: block; padding: 0 10px">                        <p>
</span><span class="cx" style="display: block; padding: 0 10px">                                <?php
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                if ( 1 == (int) $_GET['deleted'] ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         if ( 1 === (int) $_GET['deleted'] ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                         _e( 'The selected plugin has been deleted.' );
</span><span class="cx" style="display: block; padding: 0 10px">                                } else {
</span><span class="cx" style="display: block; padding: 0 10px">                                        _e( 'The selected plugins have been deleted.' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -570,7 +671,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                ?>
</span><span class="cx" style="display: block; padding: 0 10px">                        </p>
</span><span class="cx" style="display: block; padding: 0 10px">                </div>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <?php endif; ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php endif; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php elseif ( isset( $_GET['activate'] ) ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px">        <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin activated.' ); ?></p></div>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php elseif ( isset( $_GET['activate-multi'] ) ) : ?>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -583,6 +684,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">        <div id="message" class="updated notice is-dismissible"><p><?php _e( 'All selected plugins are up to date.' ); ?></p></div>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php elseif ( isset( $_GET['resume'] ) ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px">        <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin resumed.' ); ?></p></div>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php elseif ( isset( $_GET['enabled-auto-update'] ) ) : ?>
+       <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin will be auto-updated.' ); ?></p></div>
+<?php elseif ( isset( $_GET['disabled-auto-update'] ) ) : ?>
+       <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin will no longer be auto-updated.' ); ?></p></div>
+<?php elseif ( isset( $_GET['enabled-auto-update-multi'] ) ) : ?>
+       <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Selected plugins will be auto-updated.' ); ?></p></div>
+<?php elseif ( isset( $_GET['disabled-auto-update-multi'] ) ) : ?>
+       <div id="message" class="updated notice is-dismissible"><p><?php _e( 'Selected plugins will no longer be auto-updated.' ); ?></p></div>
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php endif; ?>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> <div class="wrap">
</span></span></pre></div>
<a id="trunksrcwpadminthemesphp"></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/themes.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/themes.php     2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/themes.php       2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -81,6 +81,45 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        wp_redirect( admin_url( 'themes.php?deleted=true' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">                exit;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        } elseif ( 'enable-auto-update' === $_GET['action'] ) {
+               if ( ! ( current_user_can( 'update_themes' ) && wp_is_auto_update_enabled_for_type( 'theme' ) ) ) {
+                       wp_die( __( 'Sorry, you are not allowed to enable themes automatic updates.' ) );
+               }
+
+               check_admin_referer( 'updates' );
+
+               $all_items    = wp_get_themes();
+               $auto_updates = (array) get_site_option( 'auto_update_themes', array() );
+
+               $auto_updates[] = $_GET['stylesheet'];
+               $auto_updates   = array_unique( $auto_updates );
+               // Remove themes that have been deleted since the site option was last updated.
+               $auto_updates = array_intersect( $auto_updates, array_keys( $all_items ) );
+
+               update_site_option( 'auto_update_themes', $auto_updates );
+
+               wp_redirect( admin_url( 'themes.php?enabled-auto-update=true' ) );
+
+               exit;
+       } elseif ( 'disable-auto-update' === $_GET['action'] ) {
+               if ( ! ( current_user_can( 'update_themes' ) && wp_is_auto_update_enabled_for_type( 'theme' ) ) ) {
+                       wp_die( __( 'Sorry, you are not allowed to disable themes automatic updates.' ) );
+               }
+
+               check_admin_referer( 'updates' );
+
+               $all_items    = wp_get_themes();
+               $auto_updates = (array) get_site_option( 'auto_update_themes', array() );
+
+               $auto_updates = array_diff( $auto_updates, array( $_GET['stylesheet'] ) );
+               // Remove themes that have been deleted since the site option was last updated.
+               $auto_updates = array_intersect( $auto_updates, array_keys( $all_items ) );
+
+               update_site_option( 'auto_update_themes', $auto_updates );
+
+               wp_redirect( admin_url( 'themes.php?disabled-auto-update=true' ) );
+
+               exit;
</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">@@ -228,6 +267,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">        ?>
</span><span class="cx" style="display: block; padding: 0 10px">        <div id="message6" class="error"><p><?php _e( 'Theme could not be resumed because it triggered a <strong>fatal error</strong>.' ); ?></p></div>
</span><span class="cx" style="display: block; padding: 0 10px">        <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+} elseif ( isset( $_GET['enabled-auto-update'] ) ) {
+       ?>
+       <div id="message7" class="updated notice is-dismissible"><p><?php _e( 'Theme will be auto-updated.' ); ?></p></div>
+       <?php
+} elseif ( isset( $_GET['disabled-auto-update'] ) ) {
+       ?>
+       <div id="message8" class="updated notice is-dismissible"><p><?php _e( 'Theme will no longer be auto-updated.' ); ?></p></div>
+       <?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"> $ct = wp_get_theme();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -581,7 +628,31 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                </p>
</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 ( data.actions.autoupdate ) { #>
+                               <p class="theme-autoupdate">
+                               <# if ( data.autoupdate ) { #>
+                                       <a href="{{{ data.actions.autoupdate }}}" class="toggle-auto-update" data-slug="{{ data.id }}" data-wp-action="disable">
+                                               <span class="dashicons dashicons-update spin hidden"></span>
+                                               <span class="label"><?php _e( 'Disable auto-updates' ); ?></span>
+                                       </a>
+                               <# } else { #>
+                                       <a href="{{{ data.actions.autoupdate }}}" class="toggle-auto-update" data-slug="{{ data.id }}" data-wp-action="enable">
+                                               <span class="dashicons dashicons-update spin hidden"></span>
+                                               <span class="label"><?php _e( 'Enable auto-updates' ); ?></span>
+                                       </a>
+                               <# } #>
</ins><span class="cx" style="display: block; padding: 0 10px">                                 <# if ( data.hasUpdate ) { #>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        <# if ( data.autoupdate) { #>
+                                       <span class="auto-update-time"><br /><?php echo wp_get_auto_update_message(); ?></span>
+                                       <# } else { #>
+                                       <span class="auto-update-time hidden"><br /><?php echo wp_get_auto_update_message(); ?></span>
+                                       <# } #>
+                               <# } #>
+                                       <span class="auto-updates-error hidden"><p></p></span>
+                               </p>
+                               <# } #>
+
+                               <# if ( data.hasUpdate ) { #>
</ins><span class="cx" style="display: block; padding: 0 10px">                                 <div class="notice notice-warning notice-alt notice-large">
</span><span class="cx" style="display: block; padding: 0 10px">                                        <h3 class="notice-title"><?php _e( 'Update Available' ); ?></h3>
</span><span class="cx" style="display: block; padding: 0 10px">                                        {{{ data.update }}}
</span></span></pre></div>
<a id="trunksrcwpadminupdatecorephp"></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-core.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/update-core.php        2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-admin/update-core.php  2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -328,6 +328,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <tbody class="plugins">
</span><span class="cx" style="display: block; padding: 0 10px">        <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       $auto_updates = array();
+       if ( wp_is_auto_update_enabled_for_type( 'plugin' ) ) {
+               $auto_updates       = (array) get_site_option( 'auto_update_plugins', array() );
+               $auto_update_notice = ' | ' . wp_get_auto_update_message();
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         foreach ( (array) $plugins as $plugin_file => $plugin_data ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $plugin_data = (object) _get_plugin_data_markup_translate( $plugin_file, (array) $plugin_data, false, true );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -419,6 +426,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                $plugin_data->update->new_version
</span><span class="cx" style="display: block; padding: 0 10px">                        );
</span><span class="cx" style="display: block; padding: 0 10px">                        echo ' ' . $details . $compat . $upgrade_notice;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        if ( in_array( $plugin_file, $auto_updates, true ) ) {
+                               echo $auto_update_notice;
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                         ?>
</span><span class="cx" style="display: block; padding: 0 10px">                </p></td>
</span><span class="cx" style="display: block; padding: 0 10px">        </tr>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -478,8 +488,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <tbody class="plugins">
</span><span class="cx" style="display: block; padding: 0 10px">        <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $auto_updates = array();
+       if ( wp_is_auto_update_enabled_for_type( 'theme' ) ) {
+               $auto_updates       = (array) get_site_option( 'auto_update_themes', array() );
+               $auto_update_notice = ' | ' . wp_get_auto_update_message();
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         foreach ( $themes as $stylesheet => $theme ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $checkbox_id = 'checkbox_' . md5( $theme->get( 'Name' ) );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                 ?>
</span><span class="cx" style="display: block; padding: 0 10px">        <tr>
</span><span class="cx" style="display: block; padding: 0 10px">                <td class="check-column">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -501,6 +518,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                $theme->display( 'Version' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                $theme->update['new_version']
</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 ( in_array( $stylesheet, $auto_updates, true ) ) {
+                               echo $auto_update_notice;
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                         ?>
</span><span class="cx" style="display: block; padding: 0 10px">                </p></td>
</span><span class="cx" style="display: block; padding: 0 10px">        </tr>
</span></span></pre></div>
<a id="trunksrcwpincludesscriptloaderphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/script-loader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/script-loader.php   2020-05-20 13:31:32 UTC (rev 47834)
+++ trunk/src/wp-includes/script-loader.php     2020-05-20 18:47:24 UTC (rev 47835)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1520,6 +1520,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        /* translators: %s: Number of plugins. */
</span><span class="cx" style="display: block; padding: 0 10px">                                        'pluginsFound'             => __( 'Number of plugins found: %d' ),
</span><span class="cx" style="display: block; padding: 0 10px">                                        'noPluginsFound'           => __( 'No plugins found. Try a different search.' ),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        'autoUpdatesEnable'        => __( 'Enable auto-updates' ),
+                                       'autoUpdatesEnabling'      => __( 'Enabling...' ),
+                                       'autoUpdatesEnabled'       => __( 'Auto-updates enabled' ),
+                                       'autoUpdatesDisable'       => __( 'Disable auto-updates' ),
+                                       'autoUpdatesDisabling'     => __( 'Disabling...' ),
+                                       'autoUpdatesDisabled'      => __( 'Auto-updates disabled' ),
+                                       'autoUpdatesError'         => __( 'The request could not be completed.' ),
</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>
</div>

</body>
</html>