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

540 lines 16.3 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.6.1
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 if ( ! defined( 'ABSPATH' ) ) {
19 exit; // Exit if accessed directly.
20 }
21
22 define( 'PERFLAB_VERSION', '2.6.1' );
23 define( 'PERFLAB_MAIN_FILE', __FILE__ );
24 define( 'PERFLAB_PLUGIN_DIR_PATH', plugin_dir_path( PERFLAB_MAIN_FILE ) );
25 define( 'PERFLAB_MODULES_SETTING', 'perflab_modules_settings' );
26 define( 'PERFLAB_MODULES_SCREEN', 'perflab-modules' );
27
28 // If the constant isn't defined yet, it means the Performance Lab object cache file is not loaded.
29 if ( ! defined( 'PERFLAB_OBJECT_CACHE_DROPIN_VERSION' ) ) {
30 define( 'PERFLAB_OBJECT_CACHE_DROPIN_VERSION', false );
31 }
32
33 require_once PERFLAB_PLUGIN_DIR_PATH . 'server-timing/class-perflab-server-timing-metric.php';
34 require_once PERFLAB_PLUGIN_DIR_PATH . 'server-timing/class-perflab-server-timing.php';
35 require_once PERFLAB_PLUGIN_DIR_PATH . 'server-timing/load.php';
36 require_once PERFLAB_PLUGIN_DIR_PATH . 'server-timing/defaults.php';
37
38 /**
39 * Registers the performance modules setting.
40 *
41 * @since 1.0.0
42 */
43 function perflab_register_modules_setting() {
44 register_setting(
45 PERFLAB_MODULES_SCREEN,
46 PERFLAB_MODULES_SETTING,
47 array(
48 'type' => 'object',
49 'sanitize_callback' => 'perflab_sanitize_modules_setting',
50 'default' => perflab_get_modules_setting_default(),
51 )
52 );
53 }
54 add_action( 'init', 'perflab_register_modules_setting' );
55
56 /**
57 * Gets the default value for the performance modules setting.
58 *
59 * @since 1.0.0
60 *
61 * @return array Associative array of module settings keyed by module slug.
62 */
63 function perflab_get_modules_setting_default() {
64 // Since the default relies on some minimal logic that includes requiring an additional file,
65 // the result is "cached" in a static variable.
66 static $default_option = null;
67
68 if ( null === $default_option ) {
69 // To set the default value for which modules are enabled, rely on this generated file.
70 $default_enabled_modules = require PERFLAB_PLUGIN_DIR_PATH . 'default-enabled-modules.php';
71 $default_option = array_reduce(
72 $default_enabled_modules,
73 static function ( $module_settings, $module_dir ) {
74 $module_settings[ $module_dir ] = array( 'enabled' => true );
75 return $module_settings;
76 },
77 array()
78 );
79 }
80
81 return $default_option;
82 }
83
84 /**
85 * Sanitizes the performance modules setting.
86 *
87 * @since 1.0.0
88 *
89 * @param mixed $value Modules setting value.
90 * @return array Sanitized modules setting value.
91 */
92 function perflab_sanitize_modules_setting( $value ) {
93 if ( ! is_array( $value ) ) {
94 return array();
95 }
96
97 // Ensure that every element is an array with an 'enabled' key.
98 return array_filter(
99 array_map(
100 static function ( $module_settings ) {
101 if ( ! is_array( $module_settings ) ) {
102 return array();
103 }
104 return array_merge(
105 array( 'enabled' => false ),
106 $module_settings
107 );
108 },
109 $value
110 )
111 );
112 }
113
114 /**
115 * Gets the performance module settings.
116 *
117 * @since 1.0.0
118 *
119 * @return array Associative array of module settings keyed by module slug.
120 */
121 function perflab_get_module_settings() {
122 // Even though a default value is registered for this setting, the default must be explicitly
123 // passed here, to support scenarios where this function is called before the 'init' action,
124 // for example when loading the active modules.
125 $module_settings = (array) get_option( PERFLAB_MODULES_SETTING, perflab_get_modules_setting_default() );
126
127 $legacy_module_slugs = array(
128 'site-health/audit-autoloaded-options' => 'database/audit-autoloaded-options',
129 'site-health/audit-enqueued-assets' => 'js-and-css/audit-enqueued-assets',
130 'site-health/webp-support' => 'images/webp-support',
131 'images/dominant-color' => 'images/dominant-color-images',
132 );
133
134 foreach ( $legacy_module_slugs as $legacy_slug => $current_slug ) {
135 if ( isset( $module_settings[ $legacy_slug ] ) ) {
136 $module_settings[ $current_slug ] = $module_settings[ $legacy_slug ];
137 unset( $module_settings[ $legacy_slug ] );
138 }
139 }
140
141 return $module_settings;
142 }
143
144 /**
145 * Gets the active performance modules.
146 *
147 * @since 1.0.0
148 *
149 * @return array List of active module slugs.
150 */
151 function perflab_get_active_modules() {
152 $modules = array_keys(
153 array_filter(
154 perflab_get_module_settings(),
155 static function ( $module_settings ) {
156 return isset( $module_settings['enabled'] ) && $module_settings['enabled'];
157 }
158 )
159 );
160
161 /**
162 * Filters active modules to allow programmatically control which modules are active.
163 *
164 * @since 1.0.0
165 *
166 * @param array $modules An array of the currently active modules.
167 */
168 $modules = apply_filters( 'perflab_active_modules', $modules );
169
170 return $modules;
171 }
172
173 /**
174 * Gets the active and valid performance modules.
175 *
176 * @since 1.3.0
177 * @since 2.2.0 Adds an additional check for standalone plugins.
178 *
179 * @param string $module Slug of the module.
180 * @return bool True if the module is active and valid, otherwise false.
181 */
182 function perflab_is_valid_module( $module ) {
183
184 if ( empty( $module ) ) {
185 return false;
186 }
187
188 // Do not load the module if it can be loaded by a separate plugin.
189 if ( perflab_is_standalone_plugin_loaded( $module ) ) {
190 return false;
191 }
192
193 // Do not load module if no longer exists.
194 $module_file = PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module . '/load.php';
195 if ( ! file_exists( $module_file ) ) {
196 return false;
197 }
198
199 // Do not load module if it cannot be loaded, e.g. if it was already merged and is available in WordPress core.
200 return perflab_can_load_module( $module );
201 }
202
203 /**
204 * Gets the content attribute for the generator tag for the Performance Lab plugin.
205 *
206 * This attribute is then used in {@see perflab_render_generator()}.
207 *
208 * @since 1.1.0
209 */
210 function perflab_get_generator_content() {
211 $active_and_valid_modules = array_filter( perflab_get_active_modules(), 'perflab_is_valid_module' );
212
213 return sprintf(
214 'Performance Lab %1$s; modules: %2$s',
215 PERFLAB_VERSION,
216 implode( ', ', $active_and_valid_modules )
217 );
218 }
219
220 /**
221 * Displays the HTML generator tag for the Performance Lab plugin.
222 *
223 * See {@see 'wp_head'}.
224 *
225 * @since 1.1.0
226 */
227 function perflab_render_generator() {
228 $content = perflab_get_generator_content();
229
230 echo '<meta name="generator" content="' . esc_attr( $content ) . '">' . "\n";
231 }
232 add_action( 'wp_head', 'perflab_render_generator' );
233
234 /**
235 * Checks whether the given module can be loaded in the current environment.
236 *
237 * @since 1.3.0
238 *
239 * @param string $module Slug of the module.
240 * @return bool Whether the module can be loaded or not.
241 */
242 function perflab_can_load_module( $module ) {
243 $module_load_file = PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module . '/can-load.php';
244
245 // If the `can-load.php` file does not exist, assume the module can be loaded.
246 if ( ! file_exists( $module_load_file ) ) {
247 return true;
248 }
249
250 // Require the file to get the closure for whether the module can load.
251 $module = require $module_load_file;
252
253 // If the `can-load.php` file is invalid and does not return a closure, assume the module can be loaded.
254 if ( ! is_callable( $module ) ) {
255 return true;
256 }
257
258 // Call the closure to determine whether the module can be loaded.
259 return (bool) $module();
260 }
261
262 /**
263 * Checks whether the given module has already been loaded by a separate plugin.
264 *
265 * @since 2.2.0
266 *
267 * @param string $module Slug of the module.
268 * @return bool Whether the module has already been loaded by a separate plugin.
269 */
270 function perflab_is_standalone_plugin_loaded( $module ) {
271 $standalone_plugins_constants = perflab_get_standalone_plugins_constants();
272 if (
273 isset( $standalone_plugins_constants[ $module ] ) &&
274 defined( $standalone_plugins_constants[ $module ] ) &&
275 ! str_starts_with( constant( $standalone_plugins_constants[ $module ] ), 'Performance Lab ' )
276 ) {
277 return true;
278 }
279 return false;
280 }
281
282 /**
283 * Gets the standalone plugin constants used for each module / plugin.
284 *
285 * @since 2.2.0
286 *
287 * @return array Map of module path to version constant used.
288 */
289 function perflab_get_standalone_plugins_constants() {
290 return array(
291 'images/dominant-color-images' => 'DOMINANT_COLOR_IMAGES_VERSION',
292 'images/fetchpriority' => 'FETCHPRIORITY_VERSION',
293 'images/webp-uploads' => 'WEBP_UPLOADS_VERSION',
294 );
295 }
296
297 /**
298 * Loads the active and valid performance modules.
299 *
300 * @since 1.0.0
301 * @since 1.3.0 Renamed to perflab_load_active_and_valid_modules().
302 */
303 function perflab_load_active_and_valid_modules() {
304 $active_and_valid_modules = array_filter( perflab_get_active_modules(), 'perflab_is_valid_module' );
305
306 foreach ( $active_and_valid_modules as $module ) {
307
308 require_once PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module . '/load.php';
309 }
310 }
311 add_action( 'plugins_loaded', 'perflab_load_active_and_valid_modules' );
312
313 /**
314 * Places the Performance Lab's object cache drop-in in the drop-ins folder.
315 *
316 * This only runs in WP Admin to not have any potential performance impact on
317 * the frontend.
318 *
319 * This function will short-circuit if at least one of the constants
320 * 'PERFLAB_DISABLE_SERVER_TIMING' or 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' is
321 * set as true.
322 *
323 * @since 1.8.0
324 * @since 2.1.0 No longer attempts to use two of the drop-ins together.
325 *
326 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
327 */
328 function perflab_maybe_set_object_cache_dropin() {
329 global $wp_filesystem;
330
331 // Bail if Server-Timing is disabled entirely.
332 if ( defined( 'PERFLAB_DISABLE_SERVER_TIMING' ) && PERFLAB_DISABLE_SERVER_TIMING ) {
333 return;
334 }
335
336 // Bail if disabled via constant.
337 if ( defined( 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' ) && PERFLAB_DISABLE_OBJECT_CACHE_DROPIN ) {
338 return;
339 }
340
341 // Bail if already placed.
342 if ( PERFLAB_OBJECT_CACHE_DROPIN_VERSION ) {
343 return;
344 }
345
346 /**
347 * Filters whether the Perflab server timing drop-in should be set.
348 *
349 * @since 2.0.0
350 *
351 * @param bool $disabled Whether to disable the server timing drop-in. Default false.
352 */
353 if ( apply_filters( 'perflab_disable_object_cache_dropin', false ) ) {
354 return;
355 }
356
357 // Bail if already attempted before timeout has been completed.
358 // This is present in case placing the file fails for some reason, to avoid
359 // excessively retrying to place it on every request.
360 $timeout = get_transient( 'perflab_set_object_cache_dropin' );
361 if ( false !== $timeout ) {
362 return;
363 }
364
365 if ( $wp_filesystem || WP_Filesystem() ) {
366 $dropin_path = WP_CONTENT_DIR . '/object-cache.php';
367
368 /**
369 * If there is an actual object-cache.php file, do not replace it.
370 * Previous versions of the Performance Lab plugin were renaming the
371 * original object-cache.php file and then loading both. However, due
372 * to other plugins eagerly checking file headers, this caused too many
373 * problems across sites so it was decided to remove this layer.
374 * Only placing the drop-in file if no other one exists yet is the
375 * safest solution.
376 */
377 if ( $wp_filesystem->exists( $dropin_path ) ) {
378 // Set timeout of 1 day before retrying again (only in case the file already exists).
379 set_transient( 'perflab_set_object_cache_dropin', true, DAY_IN_SECONDS );
380 return;
381 }
382
383 $wp_filesystem->copy( PERFLAB_PLUGIN_DIR_PATH . 'server-timing/object-cache.copy.php', $dropin_path );
384 }
385
386 // Set timeout of 1 hour before retrying again (only relevant in case the above failed).
387 set_transient( 'perflab_set_object_cache_dropin', true, HOUR_IN_SECONDS );
388 }
389 add_action( 'admin_init', 'perflab_maybe_set_object_cache_dropin' );
390
391 /**
392 * Removes the Performance Lab's object cache drop-in from the drop-ins folder.
393 *
394 * This function should be run on plugin deactivation. For backward compatibility with
395 * an earlier implementation of `perflab_maybe_set_object_cache_dropin()`, this function
396 * checks whether there is an object-cache-plst-orig.php file, and if so restores it.
397 *
398 * This function will short-circuit if the constant
399 * 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' is set as true.
400 *
401 * @since 1.8.0
402 *
403 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
404 */
405 function perflab_maybe_remove_object_cache_dropin() {
406 global $wp_filesystem;
407
408 // Bail if disabled via constant.
409 if ( defined( 'PERFLAB_DISABLE_OBJECT_CACHE_DROPIN' ) && PERFLAB_DISABLE_OBJECT_CACHE_DROPIN ) {
410 return;
411 }
412
413 // Bail if custom drop-in not present anyway.
414 if ( ! PERFLAB_OBJECT_CACHE_DROPIN_VERSION ) {
415 return;
416 }
417
418 if ( $wp_filesystem || WP_Filesystem() ) {
419 $dropin_path = WP_CONTENT_DIR . '/object-cache.php';
420 $dropin_backup_path = WP_CONTENT_DIR . '/object-cache-plst-orig.php';
421
422 /**
423 * If there is an object-cache-plst-orig.php file, restore it and
424 * override the Performance Lab file. This is only relevant for
425 * backward-compatibility with previous Performance Lab versions
426 * which were backing up the file and then loading both.
427 * Otherwise just delete the Performance Lab file.
428 */
429 if ( $wp_filesystem->exists( $dropin_backup_path ) ) {
430 $wp_filesystem->move( $dropin_backup_path, $dropin_path, true );
431 } else {
432 $wp_filesystem->delete( $dropin_path );
433 }
434 }
435
436 // Delete transient for drop-in check in case the plugin is reactivated shortly after.
437 delete_transient( 'perflab_set_object_cache_dropin' );
438 }
439 register_deactivation_hook( __FILE__, 'perflab_maybe_remove_object_cache_dropin' );
440
441 // Only load admin integration when in admin.
442 if ( is_admin() ) {
443 require_once PERFLAB_PLUGIN_DIR_PATH . 'admin/load.php';
444 require_once PERFLAB_PLUGIN_DIR_PATH . 'admin/server-timing.php';
445 }
446
447 /**
448 * Trigger actions when a module gets activated or deactivated.
449 *
450 * @since 1.8.0
451 *
452 * @param mixed $old_value Old value of the option.
453 * @param mixed $value New value of the option.
454 */
455 function perflab_run_module_activation_deactivation( $old_value, $value ) {
456 $old_value = (array) $old_value;
457 $value = (array) $value;
458
459 // Get the list of modules that were activated, and load the activate.php files if they exist.
460 if ( ! empty( $value ) ) {
461 foreach ( $value as $module => $module_settings ) {
462 if ( ! empty( $module_settings['enabled'] ) && ( empty( $old_value[ $module ] ) || empty( $old_value[ $module ]['enabled'] ) ) ) {
463 perflab_activate_module( PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module );
464 }
465 }
466 }
467
468 // Get the list of modules that were deactivated, and load the deactivate.php files if they exist.
469 if ( ! empty( $old_value ) ) {
470 foreach ( $old_value as $module => $module_settings ) {
471 if ( ! empty( $module_settings['enabled'] ) && ( empty( $value[ $module ] ) || empty( $value[ $module ]['enabled'] ) ) ) {
472 perflab_deactivate_module( PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module );
473 }
474 }
475 }
476
477 return $value;
478 }
479
480 /**
481 * Activate a module.
482 *
483 * Runs the activate.php file if it exists.
484 *
485 * @since 1.8.0
486 *
487 * @param string $module_dir_path The module's directory path.
488 */
489 function perflab_activate_module( $module_dir_path ) {
490 $module_activation_file = $module_dir_path . '/activate.php';
491 if ( ! file_exists( $module_activation_file ) ) {
492 return;
493 }
494 $module = require $module_activation_file;
495 if ( ! is_callable( $module ) ) {
496 return;
497 }
498 $module();
499 }
500
501 /**
502 * Deactivate a module.
503 *
504 * Runs the deactivate.php file if it exists.
505 *
506 * @since 1.8.0
507 *
508 * @param string $module_dir_path The module's directory path.
509 */
510 function perflab_deactivate_module( $module_dir_path ) {
511 $module_deactivation_file = $module_dir_path . '/deactivate.php';
512 if ( ! file_exists( $module_deactivation_file ) ) {
513 return;
514 }
515 $module = require $module_deactivation_file;
516 if ( ! is_callable( $module ) ) {
517 return;
518 }
519 $module();
520 }
521
522 // Run the module activation & deactivation actions when the option is updated.
523 add_action( 'update_option_' . PERFLAB_MODULES_SETTING, 'perflab_run_module_activation_deactivation', 10, 2 );
524
525 // Run the module activation & deactivation actions when the option is added.
526 add_action(
527 'add_option_' . PERFLAB_MODULES_SETTING,
528 /**
529 * Fires after the option has been added.
530 *
531 * @param string $option Name of the option to add.
532 * @param mixed $value Value of the option.
533 */
534 static function ( $option, $value ) {
535 perflab_run_module_activation_deactivation( perflab_get_modules_setting_default(), $value );
536 },
537 10,
538 2
539 );
540