PluginProbe
Performance Lab / 2.3.0
Performance Lab v2.3.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 2.3.0, at load.php

529 lines 15.9 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.1
7 * Requires PHP: 5.6
8 * Version: 2.3.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', '2.2.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/webp-support' => 'images/webp-support',
127 'images/dominant-color' => 'images/dominant-color-images',
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 $modules 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 * @since 2.2.0 Adds an additional check for standalone plugins.
174 *
175 * @param string $module Slug of the module.
176 * @return bool True if the module is active and valid, otherwise false.
177 */
178 function perflab_is_valid_module( $module ) {
179
180 if ( empty( $module ) ) {
181 return false;
182 }
183
184 // Do not load the module if it can be loaded by a separate plugin.
185 if ( perflab_is_standalone_plugin_loaded( $module ) ) {
186 return false;
187 }
188
189 // Do not load module if no longer exists.
190 $module_file = PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module . '/load.php';
191 if ( ! file_exists( $module_file ) ) {
192 return false;
193 }
194
195 // Do not load module if it cannot be loaded, e.g. if it was already merged and is available in WordPress core.
196 return perflab_can_load_module( $module );
197 }
198
199 /**
200 * Gets the content attribute for the generator tag for the Performance Lab plugin.
201 *
202 * This attribute is then used in {@see perflab_render_generator()}.
203 *
204 * @since 1.1.0
205 */
206 function perflab_get_generator_content() {
207 $active_and_valid_modules = array_filter( perflab_get_active_modules(), 'perflab_is_valid_module' );
208
209 return sprintf(
210 'Performance Lab %1$s; modules: %2$s',
211 PERFLAB_VERSION,
212 implode( ', ', $active_and_valid_modules )
213 );
214 }
215
216 /**
217 * Displays the HTML generator tag for the Performance Lab plugin.
218 *
219 * See {@see 'wp_head'}.
220 *
221 * @since 1.1.0
222 */
223 function perflab_render_generator() {
224 $content = perflab_get_generator_content();
225
226 echo '<meta name="generator" content="' . esc_attr( $content ) . '">' . "\n";
227 }
228 add_action( 'wp_head', 'perflab_render_generator' );
229
230 /**
231 * Checks whether the given module can be loaded in the current environment.
232 *
233 * @since 1.3.0
234 *
235 * @param string $module Slug of the module.
236 * @return bool Whether the module can be loaded or not.
237 */
238 function perflab_can_load_module( $module ) {
239 $module_load_file = PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module . '/can-load.php';
240
241 // If the `can-load.php` file does not exist, assume the module can be loaded.
242 if ( ! file_exists( $module_load_file ) ) {
243 return true;
244 }
245
246 // Require the file to get the closure for whether the module can load.
247 $module = require $module_load_file;
248
249 // If the `can-load.php` file is invalid and does not return a closure, assume the module can be loaded.
250 if ( ! is_callable( $module ) ) {
251 return true;
252 }
253
254 // Call the closure to determine whether the module can be loaded.
255 return (bool) $module();
256 }
257
258 /**
259 * Checks whether the given module has already been loaded by a separate plugin.
260 *
261 * @since 2.2.0
262 *
263 * @param string $module Slug of the module.
264 * @return bool Whether the module has already been loaded by a separate plugin.
265 */
266 function perflab_is_standalone_plugin_loaded( $module ) {
267 $standalone_plugins_constants = perflab_get_standalone_plugins_constants();
268 if (
269 isset( $standalone_plugins_constants[ $module ] ) &&
270 defined( $standalone_plugins_constants[ $module ] ) &&
271 ! str_starts_with( constant( $standalone_plugins_constants[ $module ] ), 'Performance Lab ' )
272 ) {
273 return true;
274 }
275 return false;
276 }
277
278 /**
279 * Gets the standalone plugin constants used for each module / plugin.
280 *
281 * @since 2.2.0
282 *
283 * @return array Map of module path to version constant used.
284 */
285 function perflab_get_standalone_plugins_constants() {
286 return array(
287 'images/dominant-color-images' => 'DOMINANT_COLOR_IMAGES_VERSION',
288 'images/fetchpriority' => 'FETCHPRIORITY_VERSION',
289 'images/webp-uploads' => 'WEBP_UPLOADS_VERSION',
290 );
291 }
292
293 /**
294 * Loads the active and valid performance modules.
295 *
296 * @since 1.0.0
297 * @since 1.3.0 Renamed to perflab_load_active_and_valid_modules().
298 */
299 function perflab_load_active_and_valid_modules() {
300 $active_and_valid_modules = array_filter( perflab_get_active_modules(), 'perflab_is_valid_module' );
301
302 foreach ( $active_and_valid_modules as $module ) {
303
304 require_once PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module . '/load.php';
305 }
306 }
307 add_action( 'plugins_loaded', 'perflab_load_active_and_valid_modules' );
308
309 /**
310 * Places the Performance Lab's object cache drop-in in the drop-ins folder.
311 *
312 * This only runs in WP Admin to not have any potential performance impact on
313 * the frontend.
314 *
315 * This function will short-circuit if the constant
316 * 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' is set as true.
317 *
318 * @since 1.8.0
319 * @since 2.1.0 No longer attempts to use two of the drop-ins together.
320 *
321 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
322 */
323 function perflab_maybe_set_object_cache_dropin() {
324 global $wp_filesystem;
325
326 // Bail if disabled via constant.
327 if ( defined( 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' ) && PERFLAB_DISABLE_OBJECT_CACHE_DROPIN ) {
328 return;
329 }
330
331 // Bail if already placed.
332 if ( PERFLAB_OBJECT_CACHE_DROPIN_VERSION ) {
333 return;
334 }
335
336 /**
337 * Filters whether the Perflab server timing drop-in should be set.
338 *
339 * @since 2.0.0
340 *
341 * @param bool Whether the server timing drop-in should be set.
342 */
343 if ( apply_filters( 'perflab_disable_object_cache_dropin', false ) ) {
344 return;
345 }
346
347 // Bail if already attempted before timeout has been completed.
348 // This is present in case placing the file fails for some reason, to avoid
349 // excessively retrying to place it on every request.
350 $timeout = get_transient( 'perflab_set_object_cache_dropin' );
351 if ( false !== $timeout ) {
352 return;
353 }
354
355 if ( $wp_filesystem || WP_Filesystem() ) {
356 $dropin_path = WP_CONTENT_DIR . '/object-cache.php';
357
358 /**
359 * If there is an actual object-cache.php file, do not replace it.
360 * Previous versions of the Performance Lab plugin were renaming the
361 * original object-cache.php file and then loading both. However, due
362 * to other plugins eagerly checking file headers, this caused too many
363 * problems across sites so it was decided to remove this layer.
364 * Only placing the drop-in file if no other one exists yet is the
365 * safest solution.
366 */
367 if ( $wp_filesystem->exists( $dropin_path ) ) {
368 // Set timeout of 1 day before retrying again (only in case the file already exists).
369 set_transient( 'perflab_set_object_cache_dropin', true, DAY_IN_SECONDS );
370 return;
371 }
372
373 $wp_filesystem->copy( PERFLAB_PLUGIN_DIR_PATH . 'server-timing/object-cache.copy.php', $dropin_path );
374 }
375
376 // Set timeout of 1 hour before retrying again (only relevant in case the above failed).
377 set_transient( 'perflab_set_object_cache_dropin', true, HOUR_IN_SECONDS );
378 }
379 add_action( 'admin_init', 'perflab_maybe_set_object_cache_dropin' );
380
381 /**
382 * Removes the Performance Lab's object cache drop-in from the drop-ins folder.
383 *
384 * This function should be run on plugin deactivation. For backward compatibility with
385 * an earlier implementation of `perflab_maybe_set_object_cache_dropin()`, this function
386 * checks whether there is an object-cache-plst-orig.php file, and if so restores it.
387 *
388 * This function will short-circuit if the constant
389 * 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' is set as true.
390 *
391 * @since 1.8.0
392 *
393 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
394 */
395 function perflab_maybe_remove_object_cache_dropin() {
396 global $wp_filesystem;
397
398 // Bail if disabled via constant.
399 if ( defined( 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' ) && PERFLAB_DISABLE_OBJECT_CACHE_DROPIN ) {
400 return;
401 }
402
403 // Bail if custom drop-in not present anyway.
404 if ( ! PERFLAB_OBJECT_CACHE_DROPIN_VERSION ) {
405 return;
406 }
407
408 if ( $wp_filesystem || WP_Filesystem() ) {
409 $dropin_path = WP_CONTENT_DIR . '/object-cache.php';
410 $dropin_backup_path = WP_CONTENT_DIR . '/object-cache-plst-orig.php';
411
412 /**
413 * If there is an object-cache-plst-orig.php file, restore it and
414 * override the Performance Lab file. This is only relevant for
415 * backward-compatibility with previous Performance Lab versions
416 * which were backing up the file and then loading both.
417 * Otherwise just delete the Performance Lab file.
418 */
419 if ( $wp_filesystem->exists( $dropin_backup_path ) ) {
420 $wp_filesystem->move( $dropin_backup_path, $dropin_path, true );
421 } else {
422 $wp_filesystem->delete( $dropin_path );
423 }
424 }
425
426 // Delete transient for drop-in check in case the plugin is reactivated shortly after.
427 delete_transient( 'perflab_set_object_cache_dropin' );
428 }
429 register_deactivation_hook( __FILE__, 'perflab_maybe_remove_object_cache_dropin' );
430
431 // Only load admin integration when in admin.
432 if ( is_admin() ) {
433 require_once PERFLAB_PLUGIN_DIR_PATH . 'admin/load.php';
434 }
435
436 /**
437 * Trigger actions when a module gets activated or deactivated.
438 *
439 * @since 1.8.0
440 *
441 * @param mixed $old_value Old value of the option.
442 * @param mixed $value New value of the option.
443 */
444 function perflab_run_module_activation_deactivation( $old_value, $value ) {
445 $old_value = (array) $old_value;
446 $value = (array) $value;
447
448 // Get the list of modules that were activated, and load the activate.php files if they exist.
449 if ( ! empty( $value ) ) {
450 foreach ( $value as $module => $module_settings ) {
451 if ( ! empty( $module_settings['enabled'] ) && ( empty( $old_value[ $module ] ) || empty( $old_value[ $module ]['enabled'] ) ) ) {
452 perflab_activate_module( PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module );
453 }
454 }
455 }
456
457 // Get the list of modules that were deactivated, and load the deactivate.php files if they exist.
458 if ( ! empty( $old_value ) ) {
459 foreach ( $old_value as $module => $module_settings ) {
460 if ( ! empty( $module_settings['enabled'] ) && ( empty( $value[ $module ] ) || empty( $value[ $module ]['enabled'] ) ) ) {
461 perflab_deactivate_module( PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module );
462 }
463 }
464 }
465
466 return $value;
467 }
468
469 /**
470 * Activate a module.
471 *
472 * Runs the activate.php file if it exists.
473 *
474 * @since 1.8.0
475 *
476 * @param string $module_dir_path The module's directory path.
477 */
478 function perflab_activate_module( $module_dir_path ) {
479 $module_activation_file = $module_dir_path . '/activate.php';
480 if ( ! file_exists( $module_activation_file ) ) {
481 return;
482 }
483 $module = require $module_activation_file;
484 if ( ! is_callable( $module ) ) {
485 return;
486 }
487 $module();
488 }
489
490 /**
491 * Deactivate a module.
492 *
493 * Runs the deactivate.php file if it exists.
494 *
495 * @since 1.8.0
496 *
497 * @param string $module_dir_path The module's directory path.
498 */
499 function perflab_deactivate_module( $module_dir_path ) {
500 $module_deactivation_file = $module_dir_path . '/deactivate.php';
501 if ( ! file_exists( $module_deactivation_file ) ) {
502 return;
503 }
504 $module = require $module_deactivation_file;
505 if ( ! is_callable( $module ) ) {
506 return;
507 }
508 $module();
509 }
510
511 // Run the module activation & deactivation actions when the option is updated.
512 add_action( 'update_option_' . PERFLAB_MODULES_SETTING, 'perflab_run_module_activation_deactivation', 10, 2 );
513
514 // Run the module activation & deactivation actions when the option is added.
515 add_action(
516 'add_option_' . PERFLAB_MODULES_SETTING,
517 /**
518 * Fires after the option has been added.
519 *
520 * @param string $option Name of the option to add.
521 * @param mixed $value Value of the option.
522 */
523 function( $option, $value ) {
524 perflab_run_module_activation_deactivation( perflab_get_modules_setting_default(), $value );
525 },
526 10,
527 2
528 );
529