<!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>[47275] trunk/src/wp-admin/includes/class-plugin-upgrader.php: Upgrade/Install: Enable maintenance mode when plugins are auto-updated.</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/47275">47275</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/47275","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>desrosj</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2020-02-11 20:12:52 +0000 (Tue, 11 Feb 2020)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Upgrade/Install: Enable maintenance mode when plugins are auto-updated.

When an attempt is made to update an active plugin automatically, there is the potential currently for two negative scenarios:

- The plugin can be deactivated if the Plugins admin screen is loaded when the plugin update is incomplete, causing a PHP error.
- The WSOD protection could be triggered, sending a false alarm email to the site administrator.

By enabling maintenance mode before an active plugin update is attempted, these scenarios can be avoided.

This change implements the same approach as the `Theme_Upgrader` class of using the `upgrader_pre_install` and `upgrader_post_install` hooks to toggle maintenance mode.

Props desrosj, SergeyBiryukov.
Fixes <a href="https://core.trac.wordpress.org/ticket/49400">#49400</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadminincludesclasspluginupgraderphp">trunk/src/wp-admin/includes/class-plugin-upgrader.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadminincludesclasspluginupgraderphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/class-plugin-upgrader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/class-plugin-upgrader.php     2020-02-11 19:45:46 UTC (rev 47274)
+++ trunk/src/wp-admin/includes/class-plugin-upgrader.php       2020-02-11 20:12:52 UTC (rev 47275)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -167,7 +167,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $r = $current->response[ $plugin ];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                add_filter( 'upgrader_pre_install', array( $this, 'deactivate_plugin_before_upgrade' ), 10, 2 );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                add_filter( 'upgrader_pre_install', array( $this, 'active_before' ), 10, 2 );
</ins><span class="cx" style="display: block; padding: 0 10px">                 add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ), 10, 4 );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                add_filter( 'upgrader_post_install', array( $this, 'active_after' ), 10, 2 );
</ins><span class="cx" style="display: block; padding: 0 10px">                 // There's a Trac ticket to move up the directory for zips which are made a bit differently, useful for non-.org plugins.
</span><span class="cx" style="display: block; padding: 0 10px">                // 'source_selection' => array( $this, 'source_selection' ),
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $parsed_args['clear_update_cache'] ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -192,7 +194,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // Cleanup our hooks, in case something else does a upgrade on this connection.
</span><span class="cx" style="display: block; padding: 0 10px">                remove_action( 'upgrader_process_complete', 'wp_clean_plugins_cache', 9 );
</span><span class="cx" style="display: block; padding: 0 10px">                remove_filter( 'upgrader_pre_install', array( $this, 'deactivate_plugin_before_upgrade' ) );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                remove_filter( 'upgrader_pre_install', array( $this, 'active_before' ) );
</ins><span class="cx" style="display: block; padding: 0 10px">                 remove_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ) );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                remove_filter( 'upgrader_post_install', array( $this, 'active_after' ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! $this->result || is_wp_error( $this->result ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        return $this->result;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -440,6 +444,76 @@
</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">+         * Turn on maintenance mode before attempting to background update an active plugin.
+        *
+        * Hooked to the {@see 'upgrader_pre_install'} filter by Plugin_Upgrader::upgrade().
+        *
+        * @since 5.4.0
+        *
+        * @param bool|WP_Error  $return
+        * @param array          $plugin
+        * @return bool|WP_Error
+        */
+       public function active_before( $return, $plugin ) {
+               if ( is_wp_error( $return ) ) {
+                       return $return;
+               }
+
+               // Only enable maintenance mode when in cron (background update).
+               if ( ! wp_doing_cron() ) {
+                       return $return;
+               }
+
+               $plugin = isset( $plugin['plugin'] ) ? $plugin['plugin'] : '';
+
+               if ( ! is_plugin_active( $plugin ) ) { // If not active.
+                       return $return;
+               }
+
+               // Bulk edit handles maintenance mode separately.
+               if ( ! $this->bulk ) {
+                       $this->maintenance_mode( true );
+               }
+
+               return $return;
+       }
+
+       /**
+        * Turn off maintenance mode after upgrading an active plugin.
+        *
+        * Hooked to the {@see 'upgrader_post_install'} filter by Plugin_Upgrader::upgrade().
+        *
+        * @since 5.4.0
+        *
+        * @param bool|WP_Error  $return
+        * @param array          $plugin
+        * @return bool|WP_Error
+        */
+       public function active_after( $return, $plugin ) {
+               if ( is_wp_error( $return ) ) {
+                       return $return;
+               }
+
+               // Only disable maintenance mode when in cron (background update).
+               if ( ! wp_doing_cron() ) {
+                       return $return;
+               }
+
+               $plugin = isset( $plugin['plugin'] ) ? $plugin['plugin'] : '';
+
+               if ( ! is_plugin_active( $plugin ) ) { // If not active.
+                       return $return;
+               }
+
+               // Bulk edit handles maintenance mode separately.
+               if ( ! $this->bulk ) {
+                       $this->maintenance_mode( false );
+               }
+
+               return $return;
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Delete the old plugin during an upgrade.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * Hooked to the {@see 'upgrader_clear_destination'} filter by
</span></span></pre>
</div>
</div>

</body>
</html>