PluginProbe
Performance Lab / 1.8.0
Performance Lab v1.8.0
trunk 1.0.0 1.0.0-beta.1 1.0.0-beta.2 1.0.0-beta.3 1.0.0-rc.1 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 2.0.0 2.1.0 2.2.0 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.7.0 2.8.0 All 44 releases
performance-lab / load.php

load.php in Performance Lab 1.8.0, at load.php

459 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Performance Lab
4 * Plugin URI: https://github.com/WordPress/performance
5 * Description: Performance plugin from the WordPress Performance Team, which is a collection of standalone performance modules.
6 * Requires at least: 6.0
7 * Requires PHP: 5.6
8 * Version: 1.8.0
9 * Author: WordPress Performance Team
10 * Author URI: https://make.wordpress.org/performance/
11 * License: GPLv2 or later
12 * License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
13 * Text Domain: performance-lab
14 *
15 * @package performance-lab
16 */
17
18 define( 'PERFLAB_VERSION', '1.8.0' );
19 define( 'PERFLAB_MAIN_FILE', __FILE__ );
20 define( 'PERFLAB_PLUGIN_DIR_PATH', plugin_dir_path( PERFLAB_MAIN_FILE ) );
21 define( 'PERFLAB_MODULES_SETTING', 'perflab_modules_settings' );
22 define( 'PERFLAB_MODULES_SCREEN', 'perflab-modules' );
23
24 // If the constant isn't defined yet, it means the Performance Lab object cache file is not loaded.
25 if ( ! defined( 'PERFLAB_OBJECT_CACHE_DROPIN_VERSION' ) ) {
26 define( 'PERFLAB_OBJECT_CACHE_DROPIN_VERSION', false );
27 }
28
29 require_once PERFLAB_PLUGIN_DIR_PATH . 'server-timing/class-perflab-server-timing-metric.php';
30 require_once PERFLAB_PLUGIN_DIR_PATH . 'server-timing/class-perflab-server-timing.php';
31 require_once PERFLAB_PLUGIN_DIR_PATH . 'server-timing/load.php';
32 require_once PERFLAB_PLUGIN_DIR_PATH . 'server-timing/defaults.php';
33
34 /**
35 * Registers the performance modules setting.
36 *
37 * @since 1.0.0
38 */
39 function perflab_register_modules_setting() {
40 register_setting(
41 PERFLAB_MODULES_SCREEN,
42 PERFLAB_MODULES_SETTING,
43 array(
44 'type' => 'object',
45 'sanitize_callback' => 'perflab_sanitize_modules_setting',
46 'default' => perflab_get_modules_setting_default(),
47 )
48 );
49 }
50 add_action( 'init', 'perflab_register_modules_setting' );
51
52 /**
53 * Gets the default value for the performance modules setting.
54 *
55 * @since 1.0.0
56 *
57 * @return array Associative array of module settings keyed by module slug.
58 */
59 function perflab_get_modules_setting_default() {
60 // Since the default relies on some minimal logic that includes requiring an additional file,
61 // the result is "cached" in a static variable.
62 static $default_option = null;
63
64 if ( null === $default_option ) {
65 // To set the default value for which modules are enabled, rely on this generated file.
66 $default_enabled_modules = require PERFLAB_PLUGIN_DIR_PATH . 'default-enabled-modules.php';
67 $default_option = array_reduce(
68 $default_enabled_modules,
69 function( $module_settings, $module_dir ) {
70 $module_settings[ $module_dir ] = array( 'enabled' => true );
71 return $module_settings;
72 },
73 array()
74 );
75 }
76
77 return $default_option;
78 }
79
80 /**
81 * Sanitizes the performance modules setting.
82 *
83 * @since 1.0.0
84 *
85 * @param mixed $value Modules setting value.
86 * @return array Sanitized modules setting value.
87 */
88 function perflab_sanitize_modules_setting( $value ) {
89 if ( ! is_array( $value ) ) {
90 return array();
91 }
92
93 // Ensure that every element is an array with an 'enabled' key.
94 return array_filter(
95 array_map(
96 function( $module_settings ) {
97 if ( ! is_array( $module_settings ) ) {
98 return array();
99 }
100 return array_merge(
101 array( 'enabled' => false ),
102 $module_settings
103 );
104 },
105 $value
106 )
107 );
108 }
109
110 /**
111 * Gets the performance module settings.
112 *
113 * @since 1.0.0
114 *
115 * @return array Associative array of module settings keyed by module slug.
116 */
117 function perflab_get_module_settings() {
118 // Even though a default value is registered for this setting, the default must be explicitly
119 // passed here, to support scenarios where this function is called before the 'init' action,
120 // for example when loading the active modules.
121 $module_settings = (array) get_option( PERFLAB_MODULES_SETTING, perflab_get_modules_setting_default() );
122
123 $legacy_module_slugs = array(
124 'site-health/audit-autoloaded-options' => 'database/audit-autoloaded-options',
125 'site-health/audit-enqueued-assets' => 'js-and-css/audit-enqueued-assets',
126 'site-health/audit-full-page-cache' => 'object-cache/audit-full-page-cache',
127 'site-health/webp-support' => 'images/webp-support',
128 );
129
130 foreach ( $legacy_module_slugs as $legacy_slug => $current_slug ) {
131 if ( isset( $module_settings[ $legacy_slug ] ) ) {
132 $module_settings[ $current_slug ] = $module_settings[ $legacy_slug ];
133 unset( $module_settings[ $legacy_slug ] );
134 }
135 }
136
137 return $module_settings;
138 }
139
140 /**
141 * Gets the active performance modules.
142 *
143 * @since 1.0.0
144 *
145 * @return array List of active module slugs.
146 */
147 function perflab_get_active_modules() {
148 $modules = array_keys(
149 array_filter(
150 perflab_get_module_settings(),
151 function( $module_settings ) {
152 return isset( $module_settings['enabled'] ) && $module_settings['enabled'];
153 }
154 )
155 );
156
157 /**
158 * Filters active modules to allow programmatically control which modules are active.
159 *
160 * @since 1.0.0
161 *
162 * @param array An array of the currently active modules.
163 */
164 $modules = apply_filters( 'perflab_active_modules', $modules );
165
166 return $modules;
167 }
168
169 /**
170 * Gets the active and valid performance modules.
171 *
172 * @since 1.3.0
173 *
174 * @param string $module Slug of the module.
175 * @return bool True if the module is active and valid, otherwise false.
176 */
177 function perflab_is_valid_module( $module ) {
178
179 if ( empty( $module ) ) {
180 return false;
181 }
182
183 // Do not load module if no longer exists.
184 $module_file = PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module . '/load.php';
185 if ( ! file_exists( $module_file ) ) {
186 return false;
187 }
188
189 // Do not load module if it cannot be loaded, e.g. if it was already merged and is available in WordPress core.
190 return perflab_can_load_module( $module );
191 }
192
193 /**
194 * Gets the content attribute for the generator tag for the Performance Lab plugin.
195 *
196 * This attribute is then used in {@see perflab_render_generator()}.
197 *
198 * @since 1.1.0
199 */
200 function perflab_get_generator_content() {
201 $active_and_valid_modules = array_filter( perflab_get_active_modules(), 'perflab_is_valid_module' );
202
203 return sprintf(
204 'Performance Lab %1$s; modules: %2$s',
205 PERFLAB_VERSION,
206 implode( ', ', $active_and_valid_modules )
207 );
208 }
209
210 /**
211 * Displays the HTML generator tag for the Performance Lab plugin.
212 *
213 * See {@see 'wp_head'}.
214 *
215 * @since 1.1.0
216 */
217 function perflab_render_generator() {
218 $content = perflab_get_generator_content();
219
220 echo '<meta name="generator" content="' . esc_attr( $content ) . '">' . "\n";
221 }
222 add_action( 'wp_head', 'perflab_render_generator' );
223
224 /**
225 * Checks whether the given module can be loaded in the current environment.
226 *
227 * @since 1.3.0
228 *
229 * @param string $module Slug of the module.
230 * @return bool Whether the module can be loaded or not.
231 */
232 function perflab_can_load_module( $module ) {
233 $module_load_file = PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module . '/can-load.php';
234
235 // If the `can-load.php` file does not exist, assume the module can be loaded.
236 if ( ! file_exists( $module_load_file ) ) {
237 return true;
238 }
239
240 // Require the file to get the closure for whether the module can load.
241 $module = require $module_load_file;
242
243 // If the `can-load.php` file is invalid and does not return a closure, assume the module can be loaded.
244 if ( ! is_callable( $module ) ) {
245 return true;
246 }
247
248 // Call the closure to determine whether the module can be loaded.
249 return (bool) $module();
250 }
251
252 /**
253 * Loads the active and valid performance modules.
254 *
255 * @since 1.0.0
256 * @since 1.3.0 Renamed to perflab_load_active_and_valid_modules().
257 */
258 function perflab_load_active_and_valid_modules() {
259 $active_and_valid_modules = array_filter( perflab_get_active_modules(), 'perflab_is_valid_module' );
260
261 foreach ( $active_and_valid_modules as $module ) {
262
263 require_once PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module . '/load.php';
264 }
265 }
266 perflab_load_active_and_valid_modules();
267
268 /**
269 * Places the Performance Lab's object cache drop-in in the drop-ins folder.
270 *
271 * This only runs in WP Admin to not have any potential performance impact on
272 * the frontend.
273 *
274 * This function will short-circuit if the constant
275 * 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' is set as true.
276 *
277 * @since 1.8.0
278 *
279 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
280 */
281 function perflab_maybe_set_object_cache_dropin() {
282 global $wp_filesystem;
283
284 // Bail if disabled via constant.
285 if ( defined( 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' ) && PERFLAB_DISABLE_OBJECT_CACHE_DROPIN ) {
286 return;
287 }
288
289 // Bail if already placed.
290 if ( PERFLAB_OBJECT_CACHE_DROPIN_VERSION ) {
291 return;
292 }
293
294 // Bail if already attempted before timeout has been completed.
295 // This is present in case placing the file fails for some reason, to avoid
296 // excessively retrying to place it on every request.
297 $timeout = get_transient( 'perflab_set_object_cache_dropin' );
298 if ( false !== $timeout ) {
299 return;
300 }
301
302 if ( $wp_filesystem || WP_Filesystem() ) {
303 // If there is an actual object-cache.php file, rename it.
304 // The Performance Lab object-cache.php will still load it, so the
305 // behavior does not change.
306 if ( $wp_filesystem->exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
307 $wp_filesystem->move( WP_CONTENT_DIR . '/object-cache.php', WP_CONTENT_DIR . '/object-cache-plst-orig.php' );
308 }
309
310 $wp_filesystem->copy( PERFLAB_PLUGIN_DIR_PATH . 'server-timing/object-cache.copy.php', WP_CONTENT_DIR . '/object-cache.php' );
311 }
312
313 // Set timeout of 1 hour before retrying again (only in case of failure).
314 set_transient( 'perflab_set_object_cache_dropin', true, HOUR_IN_SECONDS );
315 }
316 add_action( 'admin_init', 'perflab_maybe_set_object_cache_dropin' );
317
318 /**
319 * Removes the Performance Lab's object cache drop-in from the drop-ins folder.
320 *
321 * This function should be run on plugin deactivation. If there was another original
322 * object-cache.php drop-in file (renamed in `perflab_maybe_set_object_cache_dropin()`
323 * to object-cache-plst-orig.php), it will be restored.
324 *
325 * This function will short-circuit if the constant
326 * 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' is set as true.
327 *
328 * @since 1.8.0
329 *
330 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
331 */
332 function perflab_maybe_remove_object_cache_dropin() {
333 global $wp_filesystem;
334
335 // Bail if disabled via constant.
336 if ( defined( 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' ) && PERFLAB_DISABLE_OBJECT_CACHE_DROPIN ) {
337 return;
338 }
339
340 // Bail if custom drop-in not present anyway.
341 if ( ! PERFLAB_OBJECT_CACHE_DROPIN_VERSION ) {
342 return;
343 }
344
345 if ( $wp_filesystem || WP_Filesystem() ) {
346 // If there is an actual object-cache.php file, restore it
347 // and override the Performance Lab file.
348 // Otherwise just delete the Performance Lab file.
349 if ( $wp_filesystem->exists( WP_CONTENT_DIR . '/object-cache-plst-orig.php' ) ) {
350 $wp_filesystem->move( WP_CONTENT_DIR . '/object-cache-plst-orig.php', WP_CONTENT_DIR . '/object-cache.php', true );
351 } else {
352 $wp_filesystem->delete( WP_CONTENT_DIR . '/object-cache.php' );
353 }
354 }
355
356 // Delete transient for drop-in check in case the plugin is reactivated shortly after.
357 delete_transient( 'perflab_set_object_cache_dropin' );
358 }
359 register_deactivation_hook( __FILE__, 'perflab_maybe_remove_object_cache_dropin' );
360
361 // Only load admin integration when in admin.
362 if ( is_admin() ) {
363 require_once PERFLAB_PLUGIN_DIR_PATH . 'admin/load.php';
364 }
365
366 /**
367 * Trigger actions when a module gets activated or deactivated.
368 *
369 * @since 1.8.0
370 *
371 * @param mixed $old_value Old value of the option.
372 * @param mixed $value New value of the option.
373 */
374 function perflab_run_module_activation_deactivation( $old_value, $value ) {
375 $old_value = (array) $old_value;
376 $value = (array) $value;
377
378 // Get the list of modules that were activated, and load the activate.php files if they exist.
379 if ( ! empty( $value ) ) {
380 foreach ( $value as $module => $module_settings ) {
381 if ( ! empty( $module_settings['enabled'] ) && ( empty( $old_value[ $module ] ) || empty( $old_value[ $module ]['enabled'] ) ) ) {
382 perflab_activate_module( PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module );
383 }
384 }
385 }
386
387 // Get the list of modules that were deactivated, and load the deactivate.php files if they exist.
388 if ( ! empty( $old_value ) ) {
389 foreach ( $old_value as $module => $module_settings ) {
390 if ( ! empty( $module_settings['enabled'] ) && ( empty( $value[ $module ] ) || empty( $value[ $module ]['enabled'] ) ) ) {
391 perflab_deactivate_module( PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module );
392 }
393 }
394 }
395
396 return $value;
397 }
398
399 /**
400 * Activate a module.
401 *
402 * Runs the activate.php file if it exists.
403 *
404 * @since 1.8.0
405 *
406 * @param string $module_dir_path The module's directory path.
407 */
408 function perflab_activate_module( $module_dir_path ) {
409 $module_activation_file = $module_dir_path . '/activate.php';
410 if ( ! file_exists( $module_activation_file ) ) {
411 return;
412 }
413 $module = require $module_activation_file;
414 if ( ! is_callable( $module ) ) {
415 return;
416 }
417 $module();
418 }
419
420 /**
421 * Deactivate a module.
422 *
423 * Runs the deactivate.php file if it exists.
424 *
425 * @since 1.8.0
426 *
427 * @param string $module_dir_path The module's directory path.
428 */
429 function perflab_deactivate_module( $module_dir_path ) {
430 $module_deactivation_file = $module_dir_path . '/deactivate.php';
431 if ( ! file_exists( $module_deactivation_file ) ) {
432 return;
433 }
434 $module = require $module_deactivation_file;
435 if ( ! is_callable( $module ) ) {
436 return;
437 }
438 $module();
439 }
440
441 // Run the module activation & deactivation actions when the option is updated.
442 add_action( 'update_option_' . PERFLAB_MODULES_SETTING, 'perflab_run_module_activation_deactivation', 10, 2 );
443
444 // Run the module activation & deactivation actions when the option is added.
445 add_action(
446 'add_option_' . PERFLAB_MODULES_SETTING,
447 /**
448 * Fires after the option has been added.
449 *
450 * @param string $option Name of the option to add.
451 * @param mixed $value Value of the option.
452 */
453 function( $option, $value ) {
454 perflab_run_module_activation_deactivation( perflab_get_modules_setting_default(), $value );
455 },
456 10,
457 2
458 );
459