Skip to content

Instantly share code, notes, and snippets.

@richaber
Forked from pbiron/enable-disable-plugins-when-doing-local-dev.php
Last active September 14, 2023 09:40
Show Gist options
  • Save richaber/79a9596e7e9d87a93470f286983a0687 to your computer and use it in GitHub Desktop.
Save richaber/79a9596e7e9d87a93470f286983a0687 to your computer and use it in GitHub Desktop.
MU plugin to enable/disable other plugins during local development.
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
/**
* Plugin Name: RA Local Dev Plugin
* Description: Install as an mu-plugin to enable and disable other plugins during local development.
* Version: 0.1.0
* License: GPL version 2 or any later version
* Author: Mark Jaquith, Andrey Savchenko, Paul Biron, Richard Aber
*
* Inspired by Paul Biron https://gist.github.com/pbiron/52bb63042cf220256ece89bc07fb57b0,
* who was inspired by Andrey Savchenko https://gist.github.com/Rarst/4402927,
* who was inspired by Mark Jaquith https://gist.github.com/markjaquith/1044546.
*
* @package RA\LocalDev
*/
namespace RA\LocalDev;
// phpcs:disable Generic.Arrays.DisallowShortArraySyntax
// phpcs:disable Generic.Files.OneObjectStructurePerFile
// phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
/**
* Class Config
*
* Config object containing plugins to enable and disable.
*
* @package RA\LocalDev
*/
class Config
{
/**
* Array of plugins to disable in local development.
*
* This is for plugins that could be hazardous in local development,
* such as plugins that send emails through a third-party service
* or interface with an external email server.
*
* These typically follow the format of directory name,
* followed by a slash /, followed by the main plugin file name.
*
* @var array
*/
public static $disable = [
'wp-mail-smtp/wp_mail_smtp.php',
];
/**
* Array of plugins to enable in local development.
*
* This is for plugins that are useful in local development,
* such as plugins that display debug information.
*
* 'network' is used for network activation in multisite,
* 'non-network' for standard activation.
*
* These typically follow the format of directory name,
* followed by a slash /, followed by the main plugin file name.
*
* @var array
*/
public static $enable = [
'network' => [],
'non-network' => [
'admin-bar-user-switching/admin-bar-user-switching.php',
'query-monitor/query-monitor.php',
'rewrite-rules-inspector/rewrite-rules-inspector.php',
'user-switching/user-switching.php',
'wp-crontrol/wp-crontrol.php',
],
];
/**
* Get the array of plugins to disable in local development.
*
* @return array
*/
public static function getPluginsToDisable(): array
{
return (array)self::$disable;
}
/**
* Get the array of plugins to enable in local development.
*
* @return array
*/
public static function getPluginsToEnable(): array
{
return (array)self::$enable;
}
}
/**
* Class Plugin
*
* The plugin class that handles enabling and disabling.
*
* @package RA\LocalDev
*/
class Plugin
{
/**
* The config used to create this instance.
*
* @var null|Config
*/
protected $config = null;
/**
* The array of disabled plugins.
*
* @var array
*/
protected $disabled = [];
/**
* The array of enabled plugins.
*
* @var array
*/
protected $enabled = [
'network' => [],
'non-network' => [],
];
/**
* Sets up the filters, and handles arrays of plugins to enable and disable.
*
* @param Config $config Config object.
*/
public function __construct(Config $config)
{
$this->config = $config;
foreach ($this->config::getPluginsToDisable() as $disable) {
$this->disable($disable);
}
foreach ($this->config::getPluginsToEnable() as $where => $_enables) {
if (is_array($_enables)) {
foreach ($_enables as $enable) {
$this->enable($enable, $where);
}
}
}
add_filter(
'option_active_plugins',
[$this, 'doDisabling']
);
add_filter(
'option_active_plugins',
[$this, 'doEnabling']
);
add_filter(
'site_option_active_sitewide_plugins',
[$this, 'doNetworkDisabling']
);
add_filter(
'site_option_active_sitewide_plugins',
[$this, 'doNetworkEnabling']
);
}
/**
* Adds a filename to the list of plugins to disable.
*
* @param string $file The plugin filename to disable.
*/
public function disable($file)
{
$this->disabled[] = $file;
}
/**
* Adds a filename to the list of plugins to enable.
*
* @param string $file The plugin filename to enable.
* @param null|string $where Network or non-network.
*
* @return void
*/
public function enable(string $file, $where = 'non-network')
{
if (
! is_multisite()
|| ! in_array($where, ['non-network', 'network'], true)
) {
$where = 'non-network';
}
$this->enabled[$where][] = $file;
}
/**
* Hooks in to the option_active_plugins filter and does the disabling.
*
* @param array $plugins The plugin filenames to disable.
*
* @return array The filtered array of plugin filenames.
*/
public function doDisabling($plugins)
{
if (count($this->disabled)) {
foreach ((array)$this->disabled as $plugin) {
$key = array_search($plugin, $plugins, true);
if (false !== $key) {
unset($plugins[$key]);
}
}
}
return $plugins;
}
/**
* Hooks in to the site_option_active_sitewide_plugins filter and does the disabling.
*
* @param array $plugins The plugin filenames to network disable.
*
* @return array The filtered array of plugin filenames.
*/
public function doNetworkDisabling(array $plugins)
{
if (count($this->disabled)) {
foreach ((array)$this->disabled as $plugin) {
if (isset($plugins[$plugin])) {
unset($plugins[$plugin]);
}
}
}
return $plugins;
}
/**
* Hooks in to the option_active_plugins filter and does the enabling.
*
* @param array $plugins List of plugin filenames.
*
* @return array The filtered array of plugin filenames
*/
public function doEnabling($plugins)
{
return array_merge($plugins, $this->enabled['non-network']);
}
/**
* Hooks in to the site_option_active_sitewide_plugins filter and does the enabling.
*
* @param array $plugins List of plugin filenames.
*
* @return array
*/
public function doNetworkEnabling($plugins)
{
foreach ($this->enabled['network'] as $file) {
$plugins[$file] = time();
}
return $plugins;
}
}
/**
* Class Factory
*
* The factory responsible for instantiating and returning the single Plugin instance.
*
* @package RA\LocalDev
*/
class Factory
{
/**
* Create and return an instance of Plugin.
*
* This always returns a shared instance.
* This way, outside code can always get access to the instance of the plugin.
*
* @return Plugin The plugin instance.
*/
public static function create(): Plugin
{
static $plugin = null;
if (null === $plugin) {
$plugin = new Plugin(
new Config()
);
}
return $plugin;
}
}
if (
(defined('WP_LOCAL_DEV') && WP_LOCAL_DEV)
|| (defined('WP_ENVIRONMENT_TYPE') && 'local' === WP_ENVIRONMENT_TYPE)
) {
Factory::create();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment