WordPress.org

Make WordPress Core


Ignore:
Timestamp:
01/30/2019 11:00:30 AM (3 years ago)
Author:
flixos90
Message:

Bootstrap/Load: Revert fatal error recovery mechanism from 5.1 to polish for 5.2.

Due to the high number of follow-up tickets and associated security concerns, it was decided to reschedule the fatal error recovery feature for WordPress 5.2, in order to address these issues properly. The feature will continue to be developed, with iterations being merged into trunk early in the 5.2 release cycle.

Fixes #46141. See #44458, #45932, #45940, #46038, #46047, #46068.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/plugin.php

    r44675 r44717  
    469469function _get_dropins() {
    470470    $dropins = array(
    471         'advanced-cache.php'      => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
    472         'db.php'                  => array( __( 'Custom database class.' ), true ), // auto on load
    473         'db-error.php'            => array( __( 'Custom database error message.' ), true ), // auto on error
    474         'install.php'             => array( __( 'Custom installation script.' ), true ), // auto on installation
    475         'maintenance.php'         => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
    476         'object-cache.php'        => array( __( 'External object cache.' ), true ), // auto on load
    477         'php-error.php'           => array( __( 'Custom PHP error message.' ), true ), // auto on error
    478         'fatal-error-handler.php' => array( __( 'Custom PHP fatal error handler.' ), true ), // auto on error
     471        'advanced-cache.php' => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
     472        'db.php'             => array( __( 'Custom database class.' ), true ), // auto on load
     473        'db-error.php'       => array( __( 'Custom database error message.' ), true ), // auto on error
     474        'install.php'        => array( __( 'Custom installation script.' ), true ), // auto on installation
     475        'maintenance.php'    => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
     476        'object-cache.php'   => array( __( 'External object cache.' ), true ), // auto on load
    479477    );
    480478
     
    527525function is_plugin_inactive( $plugin ) {
    528526    return ! is_plugin_active( $plugin );
    529 }
    530 
    531 /**
    532  * Determines whether a plugin is technically active but was paused while
    533  * loading.
    534  *
    535  * For more information on this and similar theme functions, check out
    536  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
    537  * Conditional Tags} article in the Theme Developer Handbook.
    538  *
    539  * @since 5.1.0
    540  *
    541  * @param string $plugin Path to the plugin file relative to the plugins directory.
    542  * @return bool True, if in the list of paused plugins. False, not in the list.
    543  */
    544 function is_plugin_paused( $plugin ) {
    545     if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
    546         return false;
    547     }
    548 
    549     if ( ! is_plugin_active( $plugin ) && ! is_plugin_active_for_network( $plugin ) ) {
    550         return false;
    551     }
    552 
    553     list( $plugin ) = explode( '/', $plugin );
    554 
    555     return array_key_exists( $plugin, $GLOBALS['_paused_plugins'] );
    556 }
    557 
    558 /**
    559  * Gets the error that was recorded for a paused plugin.
    560  *
    561  * @since 5.1.0
    562  *
    563  * @param string $plugin Path to the plugin file relative to the plugins
    564  *                       directory.
    565  * @return array|false Array of error information as it was returned by
    566  *                     `error_get_last()`, or false if none was recorded.
    567  */
    568 function wp_get_plugin_error( $plugin ) {
    569     if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
    570         return false;
    571     }
    572 
    573     list( $plugin ) = explode( '/', $plugin );
    574 
    575     if ( ! array_key_exists( $plugin, $GLOBALS['_paused_plugins'] ) ) {
    576         return false;
    577     }
    578 
    579     return $GLOBALS['_paused_plugins'][ $plugin ];
    580 }
    581 
    582 /**
    583  * Gets the number of sites on which a specific plugin is paused.
    584  *
    585  * @since 5.1.0
    586  *
    587  * @param string $plugin Path to the plugin file relative to the plugins directory.
    588  * @return int Site count.
    589  */
    590 function count_paused_plugin_sites_for_network( $plugin ) {
    591     if ( ! is_multisite() ) {
    592         return is_plugin_paused( $plugin ) ? 1 : 0;
    593     }
    594 
    595     list( $plugin ) = explode( '/', $plugin );
    596 
    597     $query_args = array(
    598         'count'      => true,
    599         'number'     => 0,
    600         'network_id' => get_current_network_id(),
    601         'meta_query' => array(
    602             wp_paused_plugins()->get_site_meta_query_clause( $plugin ),
    603         ),
    604     );
    605 
    606     return get_sites( $query_args );
    607527}
    608528
     
    802722        if ( ! is_plugin_active( $plugin ) ) {
    803723            continue;
    804         }
    805 
    806         // Clean up the database before deactivating the plugin.
    807         if ( is_plugin_paused( $plugin ) ) {
    808             resume_plugin( $plugin );
    809724        }
    810725
     
    1003918        }
    1004919
    1005         // Clean up the database before removing the plugin.
    1006         if ( is_plugin_paused( $plugin_file ) ) {
    1007             resume_plugin( $plugin_file );
    1008         }
    1009 
    1010920        /**
    1011921         * Fires immediately before a plugin deletion attempt.
     
    1080990
    1081991        return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) );
    1082     }
    1083 
    1084     return true;
    1085 }
    1086 
    1087 /**
    1088  * Tries to resume a single plugin.
    1089  *
    1090  * If a redirect was provided, we first ensure the plugin does not throw fatal
    1091  * errors anymore.
    1092  *
    1093  * The way it works is by setting the redirection to the error before trying to
    1094  * include the plugin file. If the plugin fails, then the redirection will not
    1095  * be overwritten with the success message and the plugin will not be resumed.
    1096  *
    1097  * @since 5.1.0
    1098  *
    1099  * @param string $plugin       Single plugin to resume.
    1100  * @param string $redirect     Optional. URL to redirect to. Default empty string.
    1101  * @param bool   $network_wide Optional. Whether to resume the plugin for the entire
    1102  *                             network. Default false.
    1103  * @return bool|WP_Error True on success, false if `$plugin` was not paused,
    1104  *                       `WP_Error` on failure.
    1105  */
    1106 function resume_plugin( $plugin, $redirect = '', $network_wide = false ) {
    1107     /*
    1108      * We'll override this later if the plugin could be included without
    1109      * creating a fatal error.
    1110      */
    1111     if ( ! empty( $redirect ) ) {
    1112         wp_redirect(
    1113             add_query_arg(
    1114                 '_error_nonce',
    1115                 wp_create_nonce( 'plugin-resume-error_' . $plugin ),
    1116                 $redirect
    1117             )
    1118         );
    1119 
    1120         // Load the plugin to test whether it throws a fatal error.
    1121         ob_start();
    1122         plugin_sandbox_scrape( $plugin );
    1123         ob_clean();
    1124     }
    1125 
    1126     $result = wp_forget_extension_error( 'plugins', $plugin, $network_wide );
    1127 
    1128     if ( ! $result ) {
    1129         return new WP_Error(
    1130             'could_not_resume_plugin',
    1131             __( 'Could not resume the plugin.' )
    1132         );
    1133992    }
    1134993
     
    22432102    WP_Privacy_Policy_Content::add( $plugin_name, $policy_text );
    22442103}
    2245 
    2246 /**
    2247  * Renders an admin notice in case some plugins have been paused due to errors.
    2248  *
    2249  * @since 5.1.0
    2250  */
    2251 function paused_plugins_notice() {
    2252     if ( 'plugins.php' === $GLOBALS['pagenow'] ) {
    2253         return;
    2254     }
    2255 
    2256     if ( ! current_user_can( 'deactivate_plugins' ) ) {
    2257         return;
    2258     }
    2259 
    2260     if ( ! isset( $GLOBALS['_paused_plugins'] ) || empty( $GLOBALS['_paused_plugins'] ) ) {
    2261         return;
    2262     }
    2263 
    2264     printf(
    2265         '<div class="notice notice-error"><p><strong>%s</strong><br>%s</p><p>%s</p></div>',
    2266         __( 'One or more plugins failed to load properly.' ),
    2267         __( 'You can find more details and make changes on the Plugins screen.' ),
    2268         sprintf(
    2269             '<a href="%s">%s</a>',
    2270             admin_url( 'plugins.php?plugin_status=paused' ),
    2271             'Go to the Plugins screen'
    2272         )
    2273     );
    2274 }
Note: See TracChangeset for help on using the changeset viewer.