PluginProbe
Performance Lab / 2.1.0
Performance Lab v2.1.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.1.0, at load.php

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