21 * @author Roots |
21 * @author Roots |
22 * @link https://roots.io/ |
22 * @link https://roots.io/ |
23 */ |
23 */ |
24 class Autoloader |
24 class Autoloader |
25 { |
25 { |
|
26 /** @var static Singleton instance */ |
|
27 private static $instance; |
|
28 |
26 /** @var array Store Autoloader cache and site option */ |
29 /** @var array Store Autoloader cache and site option */ |
27 private static $cache; |
30 private $cache; |
28 |
31 |
29 /** @var array Autoloaded plugins */ |
32 /** @var array Autoloaded plugins */ |
30 private static $auto_plugins; |
33 private $autoPlugins; |
31 |
34 |
32 /** @var array Autoloaded mu-plugins */ |
35 /** @var array Autoloaded mu-plugins */ |
33 private static $mu_plugins; |
36 private $muPlugins; |
34 |
37 |
35 /** @var int Number of plugins */ |
38 /** @var int Number of plugins */ |
36 private static $count; |
39 private $count; |
37 |
40 |
38 /** @var array Newly activated plugins */ |
41 /** @var array Newly activated plugins */ |
39 private static $activated; |
42 private $activated; |
40 |
43 |
41 /** @var string Relative path to the mu-plugins dir */ |
44 /** @var string Relative path to the mu-plugins dir */ |
42 private static $relative_path; |
45 private $relativePath; |
43 |
|
44 /** @var static Singleton instance */ |
|
45 private static $_single; |
|
46 |
46 |
47 /** |
47 /** |
48 * Create singleton, populate vars, and set WordPress hooks |
48 * Create singleton, populate vars, and set WordPress hooks |
49 */ |
49 */ |
50 public function __construct() |
50 public function __construct() |
51 { |
51 { |
52 if (isset(self::$_single)) { |
52 if (isset(self::$instance)) { |
53 return; |
53 return; |
54 } |
54 } |
55 |
55 |
56 self::$_single = $this; |
56 self::$instance = $this; |
57 self::$relative_path = '/../' . basename(__DIR__); |
57 |
|
58 $this->relativePath = '/../' . basename(__DIR__); |
58 |
59 |
59 if (is_admin()) { |
60 if (is_admin()) { |
60 add_filter('show_advanced_plugins', [$this, 'showInAdmin'], 0, 2); |
61 add_filter('show_advanced_plugins', [$this, 'showInAdmin'], 0, 2); |
61 } |
62 } |
62 |
63 |
72 $this->validatePlugins(); |
73 $this->validatePlugins(); |
73 $this->countPlugins(); |
74 $this->countPlugins(); |
74 |
75 |
75 array_map(static function () { |
76 array_map(static function () { |
76 include_once WPMU_PLUGIN_DIR . '/' . func_get_args()[0]; |
77 include_once WPMU_PLUGIN_DIR . '/' . func_get_args()[0]; |
77 }, array_keys(self::$cache['plugins'])); |
78 }, array_keys($this->cache['plugins'])); |
78 |
79 |
79 $this->pluginHooks(); |
80 $this->pluginHooks(); |
80 } |
81 } |
81 |
82 |
82 /** |
83 /** |
95 return $show; |
96 return $show; |
96 } |
97 } |
97 |
98 |
98 $this->updateCache(); |
99 $this->updateCache(); |
99 |
100 |
100 self::$auto_plugins = array_map(function ($auto_plugin) { |
101 $this->autoPlugins = array_map(function ($auto_plugin) { |
101 $auto_plugin['Name'] .= ' *'; |
102 $auto_plugin['Name'] .= ' *'; |
102 return $auto_plugin; |
103 return $auto_plugin; |
103 }, self::$auto_plugins); |
104 }, $this->autoPlugins); |
104 |
105 |
105 $GLOBALS['plugins']['mustuse'] = array_unique(array_merge(self::$auto_plugins, self::$mu_plugins), SORT_REGULAR); |
106 $GLOBALS['plugins']['mustuse'] = array_unique(array_merge($this->autoPlugins, $this->muPlugins), SORT_REGULAR); |
106 |
107 |
107 return false; |
108 return false; |
108 } |
109 } |
109 |
110 |
110 /** |
111 /** |
112 */ |
113 */ |
113 private function checkCache() |
114 private function checkCache() |
114 { |
115 { |
115 $cache = get_site_option('bedrock_autoloader'); |
116 $cache = get_site_option('bedrock_autoloader'); |
116 |
117 |
117 if ($cache === false) { |
118 if ($cache === false || (isset($cache['plugins'], $cache['count']) && count($cache['plugins']) !== $cache['count'])) { |
118 $this->updateCache(); |
119 $this->updateCache(); |
119 return; |
120 return; |
120 } |
121 } |
121 |
122 |
122 self::$cache = $cache; |
123 $this->cache = $cache; |
123 } |
124 } |
124 |
125 |
125 /** |
126 /** |
126 * Get the plugins and mu-plugins from the mu-plugin path and remove duplicates. |
127 * Get the plugins and mu-plugins from the mu-plugin path and remove duplicates. |
127 * Check cache against current plugins for newly activated plugins. |
128 * Check cache against current plugins for newly activated plugins. |
129 */ |
130 */ |
130 private function updateCache() |
131 private function updateCache() |
131 { |
132 { |
132 require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
133 require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
133 |
134 |
134 self::$auto_plugins = get_plugins(self::$relative_path); |
135 $this->autoPlugins = get_plugins($this->relativePath); |
135 self::$mu_plugins = get_mu_plugins(); |
136 $this->muPlugins = get_mu_plugins(); |
136 $plugins = array_diff_key(self::$auto_plugins, self::$mu_plugins); |
137 $plugins = array_diff_key($this->autoPlugins, $this->muPlugins); |
137 $rebuild = !is_array(self::$cache['plugins']); |
138 $rebuild = !is_array($this->cache['plugins']); |
138 self::$activated = $rebuild ? $plugins : array_diff_key($plugins, self::$cache['plugins']); |
139 $this->activated = $rebuild ? $plugins : array_diff_key($plugins, $this->cache['plugins']); |
139 self::$cache = ['plugins' => $plugins, 'count' => $this->countPlugins()]; |
140 $this->cache = ['plugins' => $plugins, 'count' => $this->countPlugins()]; |
140 |
141 |
141 update_site_option('bedrock_autoloader', self::$cache); |
142 update_site_option('bedrock_autoloader', $this->cache); |
142 } |
143 } |
143 |
144 |
144 /** |
145 /** |
145 * This accounts for the plugin hooks that would run if the plugins were |
146 * This accounts for the plugin hooks that would run if the plugins were |
146 * loaded as usual. Plugins are removed by deletion, so there's no way |
147 * loaded as usual. Plugins are removed by deletion, so there's no way |
147 * to deactivate or uninstall. |
148 * to deactivate or uninstall. |
148 */ |
149 */ |
149 private function pluginHooks() |
150 private function pluginHooks() |
150 { |
151 { |
151 if (!is_array(self::$activated)) { |
152 if (!is_array($this->activated)) { |
152 return; |
153 return; |
153 } |
154 } |
154 |
155 |
155 foreach (self::$activated as $plugin_file => $plugin_info) { |
156 foreach ($this->activated as $plugin_file => $plugin_info) { |
156 do_action('activate_' . $plugin_file); |
157 do_action('activate_' . $plugin_file); |
157 } |
158 } |
158 } |
159 } |
159 |
160 |
160 /** |
161 /** |
161 * Check that the plugin file exists, if it doesn't update the cache. |
162 * Check that the plugin file exists, if it doesn't update the cache. |
162 */ |
163 */ |
163 private function validatePlugins() |
164 private function validatePlugins() |
164 { |
165 { |
165 foreach (self::$cache['plugins'] as $plugin_file => $plugin_info) { |
166 foreach ($this->cache['plugins'] as $plugin_file => $plugin_info) { |
166 if (!file_exists(WPMU_PLUGIN_DIR . '/' . $plugin_file)) { |
167 if (!file_exists(WPMU_PLUGIN_DIR . '/' . $plugin_file)) { |
167 $this->updateCache(); |
168 $this->updateCache(); |
168 break; |
169 break; |
169 } |
170 } |
170 } |
171 } |
178 * |
179 * |
179 * @return int Number of autoloaded plugins. |
180 * @return int Number of autoloaded plugins. |
180 */ |
181 */ |
181 private function countPlugins() |
182 private function countPlugins() |
182 { |
183 { |
183 if (isset(self::$count)) { |
184 if (isset($this->count)) { |
184 return self::$count; |
185 return $this->count; |
185 } |
186 } |
186 |
187 |
187 $count = count(glob(WPMU_PLUGIN_DIR . '/*/', GLOB_ONLYDIR | GLOB_NOSORT)); |
188 $count = count(glob(WPMU_PLUGIN_DIR . '/*/', GLOB_ONLYDIR | GLOB_NOSORT)); |
188 |
189 |
189 if (!isset(self::$cache['count']) || $count !== self::$cache['count']) { |
190 if (!isset($this->cache['count']) || $count !== $this->cache['count']) { |
190 self::$count = $count; |
191 $this->count = $count; |
191 $this->updateCache(); |
192 $this->updateCache(); |
192 } |
193 } |
193 |
194 |
194 return self::$count; |
195 return $this->count; |
195 } |
196 } |
196 } |
197 } |
197 |
198 |
198 new Autoloader(); |
199 new Autoloader(); |