├── bedrock-plugin-disabler.php ├── composer.json └── src ├── DisablePlugins.php └── Plugin.php /bedrock-plugin-disabler.php: -------------------------------------------------------------------------------- 1 | =5.6", 18 | "composer/installers": "^1.4|^2.0" 19 | }, 20 | "require-dev": { 21 | "roave/security-advisories": "dev-master", 22 | "squizlabs/php_codesniffer": "^3.5" 23 | }, 24 | "scripts": { 25 | "lint": "phpcs", 26 | "lint:fix": "phpcbf" 27 | }, 28 | "config": { 29 | "allow-plugins": { 30 | "composer/installers": true 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/DisablePlugins.php: -------------------------------------------------------------------------------- 1 | disable($disable); 30 | } 31 | } 32 | 33 | /** 34 | * Add the filters 35 | */ 36 | add_filter('option_active_plugins', [$this, 'doDisabling']); 37 | add_filter('site_option_active_sitewide_plugins', [$this, 'doNetworkDisabling']); 38 | 39 | /** 40 | * Allow other plugins to access this instance 41 | */ 42 | self::$instance = $this; 43 | } 44 | 45 | /** 46 | * Adds a filename to the list of plugins to disable 47 | */ 48 | public function disable($file) 49 | { 50 | $this->disabled[] = $file; 51 | } 52 | 53 | /** 54 | * Hooks in to the option_active_plugins filter and does the disabling 55 | * @param array $plugins WP-provided list of plugin filenames 56 | * @return array The filtered array of plugin filenames 57 | */ 58 | public function doDisabling($plugins) 59 | { 60 | if (count($this->disabled)) { 61 | foreach ((array)$this->disabled as $plugin) { 62 | $key = array_search($plugin, $plugins); 63 | if (false !== $key) { 64 | unset($plugins[$key]); 65 | } 66 | } 67 | } 68 | 69 | return $plugins; 70 | } 71 | 72 | /** 73 | * Hooks in to the site_option_active_sitewide_plugins filter and does the disabling 74 | * 75 | * @param array $plugins 76 | * 77 | * @return array 78 | */ 79 | public function doNetworkDisabling($plugins) 80 | { 81 | if (count($this->disabled)) { 82 | foreach ((array)$this->disabled as $plugin) { 83 | if (isset($plugins[$plugin])) { 84 | unset($plugins[$plugin]); 85 | } 86 | } 87 | } 88 | 89 | return $plugins; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Plugin.php: -------------------------------------------------------------------------------- 1 | plugin_file = $plugin_file; 23 | 24 | $is_mu_plugin = defined('WPMU_PLUGIN_DIR') && 25 | realpath(WPMU_PLUGIN_DIR) === realpath(dirname($plugin_file, 2)); 26 | if (! $is_mu_plugin) { 27 | // prevent activation as a regular plugin 28 | register_activation_hook($plugin_file, [$this, 'preventPluginActivation']); 29 | // print notice and deactivate as the plugin is already activated (for whatever reason) 30 | add_action('admin_notices', [$this, 'printNoticeAndDeactivate' ]); 31 | } 32 | 33 | // disable the specified plugins after all other must-use plugins are loaded 34 | add_action('muplugins_loaded', [$this, 'disablePlugins']); 35 | } 36 | 37 | /** 38 | * Get the disabled plugins. 39 | * 40 | * @return array 41 | */ 42 | public function getDisabledPlugins() 43 | { 44 | if (defined('DISABLED_PLUGINS') && !empty(DISABLED_PLUGINS)) { 45 | $plugins = is_string(DISABLED_PLUGINS) ? unserialize(DISABLED_PLUGINS, [false]) : DISABLED_PLUGINS; 46 | } 47 | return !empty($plugins) && is_array($plugins) ? $plugins : []; 48 | } 49 | 50 | /** 51 | * Prevent plugin to be activated as a regular plugin. 52 | * Used as the activation hook. 53 | */ 54 | public function preventPluginActivation() 55 | { 56 | wp_die( 57 | __('Plugin Disabler only works as a must-use plugin in a bedrock site.', 'plugin-disabler'), 58 | __('Plugin Disabler', 'plugin-disabler'), 59 | ['back_link' => true] 60 | ); 61 | } 62 | 63 | /** 64 | * Prints the admin notice that the plugin should be installed 65 | * as a must-use plugin and deactivates the plugin itself. 66 | */ 67 | public function printNoticeAndDeactivate() 68 | { 69 | $class = 'notice notice-error'; 70 | $message = __('Plugin Disabler only works as a must-use plugin in a bedrock site.', 'plugin-disabler'); 71 | printf('

%2$s

', esc_attr($class), esc_html($message)); 72 | 73 | // deactivate self 74 | deactivate_plugins(plugin_basename($this->plugin_file)); 75 | } 76 | 77 | /** 78 | * Run the Disabler. 79 | */ 80 | public function disablePlugins($plugins = null) 81 | { 82 | /** 83 | * Set disabled plugins. 84 | */ 85 | $this->disabled_plugins = $this->getDisabledPlugins(); 86 | 87 | /** 88 | * Run the disabler. 89 | */ 90 | if (empty($this->disabled_plugins)) { 91 | return; 92 | } 93 | 94 | // Disable the plugins. 95 | require_once(__DIR__ . '/DisablePlugins.php'); 96 | new DisablePlugins($this->disabled_plugins); 97 | 98 | /** 99 | * Add the disabled notice. 100 | */ 101 | if (! empty($this->disabled_plugins)) { 102 | add_action('pre_current_active_plugins', [$this, 'disabledNotice']); 103 | } 104 | } 105 | 106 | /** 107 | * Add the disabled plugins to the end of the list and add a notice. 108 | */ 109 | public function disabledNotice() 110 | { 111 | global $wp_list_table; 112 | foreach ($wp_list_table->items as $key => $val) { 113 | if (in_array($key, $this->disabled_plugins, true)) { 114 | $item = $wp_list_table->items[$key]; 115 | $item['Name'] = '[Disabled] ' . $item['Name']; 116 | $item['Description'] .= '
Disabled in this environment.'; 117 | unset($wp_list_table->items[$key]); 118 | $wp_list_table->items[$key] = $item; 119 | } 120 | } 121 | } 122 | } 123 | --------------------------------------------------------------------------------