| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 | <?php/** * Plugin Name:  Bedrock Autoloader * Plugin URI:   https://github.com/roots/bedrock/ * Description:  An autoloader that enables standard plugins to be required just like must-use plugins. The autoloaded plugins are included during mu-plugin loading. An asterisk (*) next to the name of the plugin designates the plugins that have been autoloaded. * Version:      1.0.1 * Author:       Roots * Author URI:   https://roots.io/ * License:      MIT License */namespace Roots\Bedrock;if (!is_blog_installed()) {    return;}/** * Class Autoloader * @package Roots\Bedrock * @author Roots * @link https://roots.io/ */class Autoloader{    /**     * Singleton instance.     *     * @var static     */    private static $instance;    /**     * Store Autoloader cache and site option.     *     * @var array     */    private $cache;    /**     * Autoloaded plugins.     *     * @var array     */    private $autoPlugins;    /**     * Autoloaded mu-plugins.     *     * @var array     */    private $muPlugins;    /**     * Number of plugins.     *     * @var int     */    private $count;    /**     * Newly activated plugins.     *     * @var array     */    private $activated;    /**     * Relative path to the mu-plugins directory.     *     * @var string     */    private $relativePath;    /**     * Create an instance of Autoloader.     *     * @return void     */    public function __construct()    {        if (isset(self::$instance)) {            return;        }        self::$instance = $this;        $this->relativePath = '/../' . basename(__DIR__);        if (is_admin()) {            add_filter('show_advanced_plugins', [$this, 'showInAdmin'], 0, 2);        }        $this->loadPlugins();    }   /**    * Run some checks then autoload our plugins.    *    * @return void    */    public function loadPlugins()    {        $this->checkCache();        $this->validatePlugins();        $this->countPlugins();        array_map(static function () {            include_once WPMU_PLUGIN_DIR . '/' . func_get_args()[0];        }, array_keys($this->cache['plugins']));        $this->pluginHooks();    }    /**     * Filter show_advanced_plugins to display the autoloaded plugins.     *     * @param  bool    $show Whether to show the advanced plugins for the specified plugin type.     * @param  string  $type The plugin type, i.e., `mustuse` or `dropins`     * @return bool    We return `false` to prevent WordPress from overriding our work     */    public function showInAdmin($show, $type)    {        $screen = get_current_screen();        $current = is_multisite() ? 'plugins-network' : 'plugins';        if ($screen->base !== $current || $type !== 'mustuse' || !current_user_can('activate_plugins')) {            return $show;        }        $this->updateCache();        $this->autoPlugins = array_map(function ($auto_plugin) {            $auto_plugin['Name'] .= ' *';            return $auto_plugin;        }, $this->autoPlugins);        $GLOBALS['plugins']['mustuse'] = array_unique(array_merge($this->autoPlugins, $this->muPlugins), SORT_REGULAR);        return false;    }    /**     * This sets the cache or calls for an update     *     * @return void     */    private function checkCache()    {        $cache = get_site_option('bedrock_autoloader');        if ($cache === false || (isset($cache['plugins'], $cache['count']) && count($cache['plugins']) !== $cache['count'])) {            $this->updateCache();            return;        }        $this->cache = $cache;    }    /**     * Update mu-plugin cache.     *     * Get the plugins and mu-plugins from the mu-plugin path and remove duplicates.     * Check cache against current plugins for newly activated plugins.     * After that, we can update the cache.     *     * @return void     */    private function updateCache()    {        require_once ABSPATH . 'wp-admin/includes/plugin.php';        $this->autoPlugins = get_plugins($this->relativePath);        $this->muPlugins   = get_mu_plugins();        $plugins           = array_diff_key($this->autoPlugins, $this->muPlugins);        $rebuild           = !(isset($this->cache['plugins']) && is_array($this->cache['plugins']));        $this->activated   = $rebuild ? $plugins : array_diff_key($plugins, $this->cache['plugins']);        $this->cache       = ['plugins' => $plugins, 'count' => $this->countPlugins()];        update_site_option('bedrock_autoloader', $this->cache);    }    /**     * Activate plugin hooks.     *     * This accounts for the plugin hooks that would run if the plugins were     * loaded as usual. Plugins are removed by deletion, so there's no way     * to deactivate or uninstall.     *     * @return void     */    private function pluginHooks()    {        if (!is_array($this->activated)) {            return;        }        foreach ($this->activated as $plugin_file => $plugin_info) {            do_action('activate_' . $plugin_file);        }    }    /**     * Check that the plugin file exists, if it doesn't update the cache.     *     * @return void     */    private function validatePlugins()    {        foreach ($this->cache['plugins'] as $plugin_file => $plugin_info) {            if (!file_exists(WPMU_PLUGIN_DIR . '/' . $plugin_file)) {                $this->updateCache();                break;            }        }    }    /**     * Count the number of autoloaded plugins.     *     * Count our plugins (but only once) by counting the top level folders in the     * mu-plugins dir. If it's more or less than last time, update the cache.     *     * @return int Number of autoloaded plugins.     */    private function countPlugins()    {        if (isset($this->count)) {            return $this->count;        }        $count = count(glob(WPMU_PLUGIN_DIR . '/*/', GLOB_ONLYDIR | GLOB_NOSORT));        if (!isset($this->cache['count']) || $count !== $this->cache['count']) {            $this->count = $count;            $this->updateCache();        }        return $this->count;    }}new Autoloader();
 |