Plugin Editor: Improve reliability of detecting PHP fatal errors when editing an active plugin.

* Invalidate PHP opcache after file is updated to ensure `include` will ''include'' the written changes.
* Define `WP_ADMIN` when activating plugin in sandbox so plugin code targeting admin will be loaded.
* Do actions that get triggered when loading the admin to ensure plugin code runs that could cause errors on plugin editor screen (and lock out access).
* Fix ability to re-activate a plugin after editing a PHP file other than the main plugin file, and ensure PHP fatal error will be displayed in such cases.
* Consolidate duplicated code into `plugin_sandbox_scrape()` and re-use in `activate_plugin()`.
* Show an error notice instead of a success notice when a file is updated but a plugin was deactivated due to a fatal error.
* Update style of warning when editing an active plugin to be styled as an actual warning notice.

See #12423, #21622.
Fixes #39766.


git-svn-id: https://develop.svn.wordpress.org/trunk@41560 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Weston Ruter
2017-09-22 01:35:09 +00:00
parent e92db998d2
commit f07591d1fd
3 changed files with 71 additions and 12 deletions

View File

@@ -555,10 +555,8 @@ function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silen
if ( !empty($redirect) )
wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), $redirect)); // we'll override this later if the plugin can be included without fatal error
ob_start();
wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
$_wp_plugin_file = $plugin;
include_once( WP_PLUGIN_DIR . '/' . $plugin );
$plugin = $_wp_plugin_file; // Avoid stomping of the $plugin variable in a plugin.
plugin_sandbox_scrape( $plugin );
if ( ! $silent ) {
/**
@@ -1881,9 +1879,42 @@ function wp_clean_plugins_cache( $clear_update_cache = true ) {
}
/**
* @param string $plugin
* Simulate loading the WordPress admin with a given plugin active to attempt to generate errors.
*
* Actions are re-triggered in the WP bootstrap process for the WP Admin, and the WP_ADMIN constant is defined.
*
* @since 3.0.0
* @since 4.4.0 Function was moved into the `wp-admin/includes/plugin.php` file.
* @since 4.9.0 Add defining of WP_ADMIN and triggering admin WP bootstrap actions.
*
* @global array $wp_actions
* @param string $plugin Plugin file to load.
*/
function plugin_sandbox_scrape( $plugin ) {
global $wp_actions;
wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
if ( ! defined( 'WP_ADMIN' ) ) {
define( 'WP_ADMIN', true );
}
$tested_actions = array(
'plugins_loaded' => array(),
'setup_theme' => array(),
'after_setup_theme' => array(),
'init' => array(),
'wp_loaded' => array(),
'admin_init' => array(),
);
$old_wp_actions = $wp_actions;
array_map( 'remove_all_actions', array_keys( $tested_actions ) );
include( WP_PLUGIN_DIR . '/' . $plugin );
// Trigger key actions that are done on the plugin editor to cause the relevant plugin hooks to fire and potentially cause errors.
foreach ( $tested_actions as $action => $args ) {
do_action_ref_array( $action, $args );
}
$wp_actions = $old_wp_actions; // Restore actions.
}