PluginProbe
Performance Lab / 3.6.1
Performance Lab v3.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 / includes / server-timing / load.php

load.php in Performance Lab 3.6.1, at includes/server-timing/load.php

239 lines 7.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Server-Timing API integration file
4 *
5 * @package performance-lab
6 * @since 1.8.0
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit; // Exit if accessed directly.
11 }
12
13 // Do not add any of the hooks if Server-Timing is disabled.
14 if ( defined( 'PERFLAB_DISABLE_SERVER_TIMING' ) && PERFLAB_DISABLE_SERVER_TIMING ) {
15 return;
16 }
17
18 define( 'PERFLAB_SERVER_TIMING_SETTING', 'perflab_server_timing_settings' );
19 define( 'PERFLAB_SERVER_TIMING_SCREEN', 'perflab-server-timing' );
20
21 require_once __DIR__ . '/hooks.php';
22
23 /**
24 * Provides access the Server-Timing API.
25 *
26 * When called for the first time, this also initializes the API to schedule the header for output.
27 * In case that no metrics are registered, this is still called on {@see 'wp_loaded'}, so that even then it still fires
28 * its action hooks as expected.
29 *
30 * @since 1.8.0
31 */
32 function perflab_server_timing(): Perflab_Server_Timing {
33 static $server_timing;
34
35 if ( null === $server_timing ) {
36 $server_timing = new Perflab_Server_Timing();
37
38 /*
39 * Do not add the hook for Server-Timing header output if it is entirely disabled.
40 * While the constant checks on top of the file prevent this from happening by default, external code could
41 * still call the `perflab_server_timing()` function. It needs to be ensured that such calls do not result in
42 * fatal errors, but they should at least not lead to the header being output.
43 */
44 if ( defined( 'PERFLAB_DISABLE_SERVER_TIMING' ) && PERFLAB_DISABLE_SERVER_TIMING ) {
45 return $server_timing;
46 }
47
48 $server_timing->add_hooks();
49 }
50
51 return $server_timing;
52 }
53
54 /**
55 * Initializes the Server-Timing API.
56 *
57 * @since 3.1.0
58 */
59 function perflab_server_timing_init(): void {
60 perflab_server_timing();
61 }
62
63 add_action( 'wp_loaded', 'perflab_server_timing_init' );
64
65 /**
66 * Registers a metric to calculate for the Server-Timing header.
67 *
68 * This method must be called before the {@see 'perflab_server_timing_send_header'} hook.
69 *
70 * @since 1.8.0
71 *
72 * @param string $metric_slug The metric slug.
73 * @param array{measure_callback: callable, access_cap: string} $args {
74 * Arguments for the metric.
75 *
76 * @type callable $measure_callback The callback that initiates calculating the metric value. It will receive
77 * the Perflab_Server_Timing_Metric instance as a parameter, in order to set
78 * the value when it has been calculated. Metric values must be provided in
79 * milliseconds.
80 * @type string $access_cap Capability required to view the metric. If this is a public metric, this
81 * needs to be set to "exist".
82 * }
83 */
84 function perflab_server_timing_register_metric( string $metric_slug, array $args ): void {
85 perflab_server_timing()->register_metric( $metric_slug, $args );
86 }
87
88 /**
89 * Returns whether an output buffer should be used to gather Server-Timing metrics during template rendering.
90 *
91 * @since 1.8.0
92 *
93 * @return bool True if an output buffer should be used, false otherwise.
94 */
95 function perflab_server_timing_use_output_buffer(): bool {
96 return perflab_server_timing()->use_output_buffer();
97 }
98
99 /**
100 * Wraps a callback (e.g. for an action or filter) to be measured and included in the Server-Timing header.
101 *
102 * @since 1.8.0
103 *
104 * @param callable $callback The callback to wrap.
105 * @param string $metric_slug The metric slug to use within the Server-Timing header.
106 * @param string $access_cap Capability required to view the metric. If this is a public metric, this needs to be
107 * set to "exist".
108 * @return Closure Callback function that will run $callback and measure its execution time once called.
109 */
110 function perflab_wrap_server_timing( callable $callback, string $metric_slug, string $access_cap ): Closure {
111 return static function ( ...$callback_args ) use ( $callback, $metric_slug, $access_cap ) {
112 // Gain access to Perflab_Server_Timing_Metric instance.
113 $server_timing_metric = null;
114
115 // Only register the metric the first time the function is called.
116 // For now, this also means only the first function call is measured.
117 if ( ! perflab_server_timing()->has_registered_metric( $metric_slug ) ) {
118 perflab_server_timing_register_metric(
119 $metric_slug,
120 array(
121 'measure_callback' => static function ( $metric ) use ( &$server_timing_metric ): void {
122 $server_timing_metric = $metric;
123 },
124 'access_cap' => $access_cap,
125 )
126 );
127 }
128
129 // If metric instance was not set, this metric should not be calculated.
130 if ( null === $server_timing_metric ) {
131 return call_user_func_array( $callback, $callback_args );
132 }
133
134 // Measure time before the callback.
135 $server_timing_metric->measure_before();
136
137 // Execute the callback.
138 $result = call_user_func_array( $callback, $callback_args );
139
140 // Measure time after the callback and calculate total.
141 $server_timing_metric->measure_after();
142
143 // Return result (e.g. in case this is a filter callback).
144 return $result;
145 };
146 }
147
148 /**
149 * Gets default value for server timing setting.
150 *
151 * @since 3.1.0
152 *
153 * @return array{benchmarking_actions: string[], benchmarking_filters: string[], output_buffering: bool} Default value.
154 */
155 function perflab_get_server_timing_setting_default_value(): array {
156 return array(
157 'benchmarking_actions' => array(),
158 'benchmarking_filters' => array(),
159 'output_buffering' => false,
160 );
161 }
162
163 /**
164 * Registers the Server-Timing setting.
165 *
166 * @since 2.6.0
167 */
168 function perflab_register_server_timing_setting(): void {
169 register_setting(
170 PERFLAB_SERVER_TIMING_SCREEN,
171 PERFLAB_SERVER_TIMING_SETTING,
172 array(
173 'type' => 'object',
174 'sanitize_callback' => 'perflab_sanitize_server_timing_setting',
175 'default' => perflab_get_server_timing_setting_default_value(),
176 )
177 );
178 }
179 add_action( 'init', 'perflab_register_server_timing_setting' );
180
181 /**
182 * Sanitizes the Server-Timing setting.
183 *
184 * @since 2.6.0
185 *
186 * @param array|mixed $value Server-Timing setting value.
187 * @return array{benchmarking_actions: string[], benchmarking_filters: string[], output_buffering: bool} Sanitized Server-Timing setting value.
188 */
189 function perflab_sanitize_server_timing_setting( $value ): array {
190 if ( ! is_array( $value ) ) {
191 $value = array();
192 }
193 $value = wp_array_slice_assoc(
194 array_merge( perflab_get_server_timing_setting_default_value(), $value ),
195 array_keys( perflab_get_server_timing_setting_default_value() )
196 );
197
198 /*
199 * Ensure that every element is an indexed array of hook names.
200 * Any duplicates across a group of hooks are removed.
201 */
202 foreach ( wp_array_slice_assoc( $value, array( 'benchmarking_actions', 'benchmarking_filters' ) ) as $key => $hooks ) {
203 if ( ! is_array( $hooks ) ) {
204 $hooks = explode( "\n", $hooks );
205 }
206 $value[ $key ] = array_values(
207 array_unique(
208 array_filter(
209 array_map(
210 static function ( string $hook_name ): string {
211 /*
212 * Allow any characters except whitespace.
213 * While most hooks use a limited set of characters, hook names in plugins are not
214 * restricted to them, therefore the sanitization does not limit the characters
215 * used.
216 */
217 return (string) preg_replace(
218 '/\s/',
219 '',
220 sanitize_text_field( $hook_name )
221 );
222 },
223 $hooks
224 )
225 )
226 )
227 );
228 }
229
230 $value['output_buffering'] = (bool) $value['output_buffering'];
231
232 /**
233 * Validated value.
234 *
235 * @var array{benchmarking_actions: string[], benchmarking_filters: string[], output_buffering: bool} $value
236 */
237 return $value;
238 }
239