Skip to content

Instantly share code, notes, and snippets.

@leepeterson
Forked from chasecmiller/plugin_debug.php
Created September 2, 2017 09:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leepeterson/5a81c104d13f58b753240a16c0188fe5 to your computer and use it in GitHub Desktop.
Save leepeterson/5a81c104d13f58b753240a16c0188fe5 to your computer and use it in GitHub Desktop.
Proof of concept of a WordPress mu-plugin to automatically disable plugins that start throwing errors.
<?php
/*
Plugin Name: Plugin Debugging Tool
Description: Proof of concept of a WordPress mu-plugin to automatically disable plugins that start throwing errors. Must be installed as mu-plugin. The first time a plugin errors, it will white screen or show an error. Next page load, it is disabled. There has not been any functionality to remove plugins from the black list. If you'd like to see it developed more, please email chase@crumbls.com Only tested on Apache running PHP7.
Author: Chase C. Miller
Author Email: chase@crumbls.com
Version: 1.0
Author URI: http://crumbls.com
*/
namespace Crumbls\Debug\Plugins;
class Plugin
{
protected static $errHandler = false;
protected static $errLog = [];
public function __construct()
{
}
public static function getInstance()
{
static $instance;
$class = get_called_class();
if (!$instance instanceof $class) {
$instance = new $class;
add_action('admin_enqueue_scripts', [get_called_class(), 'adminEnqueue'], 10, 1);
self::$errHandler = set_error_handler([get_called_class(), 'errorHandler']);
set_exception_handler([get_called_class(), 'errorHandler']);
error_reporting(E_ALL);
add_filter('option_active_plugins', [get_called_class(), 'filterActivePlugins'], PHP_INT_MAX, 1);
add_action('shutdown', [get_called_class(), 'wordpressShutdown'], PHP_INT_MAX);
register_shutdown_function([get_called_class(), 'systemShutdown']);
}
return $instance;
}
/**
* Tied to filter "option_active_plugins"
* @param array $plugins
* @return array
*/
public static function filterActivePlugins($plugins = [])
{
global $wp_object_cache;
if (!$dis = get_option('disabled_plugins', [])) {
return $plugins;
}
// TODO: If you want to re-enable plugins, this is the spot.
// Return plugins, with disabled not activated.
$plugins = array_diff($plugins, array_column($dis, 2));
return $plugins;
}
public static function wordpressShutdown()
{
// The following plugins gave a horrible error.
if (!self::$errLog) {
return true;
}
$option = get_option('disabled_plugins', []);
$option = array_column($option, null, 'f');
foreach (self::$errLog as $err) {
if (array_key_exists($err[2], $option)) {
continue;
}
$option[$err[2]] = $err;
}
update_option('disabled_plugins', $option, true);
return true;
}
/**
* Tied to register_shutdown_function
* Not currently used.
*/
public static function systemShutdown()
{
// echo __METHOD__;
}
/**
* Error handling.
*/
public static function errorHandler($n = null, $s = null, $f = null, $ln = null)
{
if (is_object($n) && get_class($n) == 'Exception') {
$s = $n->getMessage();
$f = $n->getFile();
$ln = $n->getLine();
$n = $n->getCode();
}
if (
strpos($f, WP_CONTENT_DIR) !== 0
||
strpos($f, WP_CONTENT_DIR . '/plugins/') !== 0
) {
// Send to default error handler.
$func = self::$errHandler;
return call_user_func($func, $n, $s, $f, $ln);
}
$f = substr($f, strlen(WP_CONTENT_DIR . '/plugins/'));
self::$errLog[] = [$n, $s, $f, $ln];
return true;
}
/**
* Enqueue special CSS
* @param null $hook
*/
public static function adminEnqueue($hook = null)
{
if ($hook != 'plugins.php') {
return;
}
if (!$option = get_option('disabled_plugins', [])) {
return;
}
echo '<style>';
foreach ($option as $e) {
printf('.plugins tr[data-plugin="%s"] { background-color: rgba(255,0,0,0.5) !important; }', $e[2]);
}
echo '</style>';
}
}
Plugin::getInstance();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment