Skip to content

Instantly share code, notes, and snippets.

@felixarntz
Last active August 9, 2023 05:23
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save felixarntz/63c05392dbf7d51cc7f8f4a424b1ff39 to your computer and use it in GitHub Desktop.
Save felixarntz/63c05392dbf7d51cc7f8f4a424b1ff39 to your computer and use it in GitHub Desktop.
Mini WordPress plugin that uses the Server Timing API of the Performance Lab plugin (also see https://github.com/WordPress/performance/pull/553) to capture additional metrics
<?php
/**
* Plugin Name: Server Timing Extra
* Plugin URI: https://gist.github.com/felixarntz/63c05392dbf7d51cc7f8f4a424b1ff39
* Description: Exposes additional Server-Timing metrics using the Performance Lab plugin's Server Timing API.
* Requires at least: 6.1
* Requires PHP: 5.6
* Version: 0.1.0
* Author: Felix Arntz
* Author URI: https://felix-arntz.me
* License: GPLv2 or later
* License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* Text Domain: server-timing-extra
*
* @package server-timing-extra
*/
/**
* Measures the total time for a given action hook.
*
* @param string $hookname The action hook name.
*/
function stx_measure_action( $hookname ) {
$metric_slug = stx_hookname_to_metric_slug( $hookname );
$measure_callback = function( $metric ) use ( $hookname ) {
$metric->measure_before();
add_action( $hookname, array( $metric, 'measure_after' ), PHP_INT_MAX, 0 );
};
// If action is already running, at least measure the remainder.
if ( doing_action( $hookname ) ) {
perflab_server_timing_register_metric(
$metric_slug,
array(
'measure_callback' => $measure_callback,
'access_cap' => 'exist',
)
);
} else {
add_action(
$hookname,
function() use ( $metric_slug, $measure_callback ) {
perflab_server_timing_register_metric(
$metric_slug,
array(
'measure_callback' => $measure_callback,
'access_cap' => 'exist',
)
);
},
defined( 'PHP_INT_MIN' ) ? PHP_INT_MIN : -9999
);
}
}
/**
* Measures the total time for a given filter hook.
*
* @param string $hookname The filter hook name.
*/
function stx_measure_filter( $hookname ) {
$metric_slug = stx_hookname_to_metric_slug( $hookname );
$measure_callback = function( $metric ) use ( $hookname ) {
$metric->measure_before();
add_filter(
$hookname,
function( $passthrough ) use ( $metric ) {
$metric->measure_after();
return $passthrough;
},
PHP_INT_MAX
);
};
add_filter(
$hookname,
function( $passthrough ) use ( $metric_slug, $measure_callback ) {
perflab_server_timing_register_metric(
$metric_slug,
array(
'measure_callback' => $measure_callback,
'access_cap' => 'exist',
)
);
return $passthrough;
},
defined( 'PHP_INT_MIN' ) ? PHP_INT_MIN : -9999
);
}
/**
* Measures the times for every callback of a given action or filter hook.
*
* @param string $hookname The action or filter hook name.
*/
function stx_profile_hook_callbacks( $hookname ) {
global $wp_filter;
if ( ! isset( $wp_filter[ $hookname ] ) ) {
return;
}
foreach ( $wp_filter[ $hookname ]->callbacks as $priority => $callbacks ) {
foreach ( $callbacks as $idx => $callback ) {
$metric_slug = stx_hookname_to_metric_slug( $hookname ) . '--' . stx_hookname_to_metric_slug( $idx );
$wp_filter[ $hookname ]->callbacks[ $priority ][ $idx ]['function'] = perflab_wrap_server_timing(
$wp_filter[ $hookname ]->callbacks[ $priority ][ $idx ]['function'],
$metric_slug,
'exist'
);
}
}
}
/**
* Gets a Server-Timing metric slug name based on the given hook name.
*
* @param string $hookname The action or filter hook name.
* @return string Corresponding metric slug.
*/
function stx_hookname_to_metric_slug( $hookname ) {
return str_replace( '_', '-', str_replace( 'wp_', '', $hookname ) );
}
/**
* Defines and configures extra metrics to capture.
*/
function stx_capture_extra_metrics() {
if ( ! function_exists( 'perflab_server_timing_register_metric' ) ) {
return;
}
/* More actions can be added here. */
$action_hooks = array(
'plugins_loaded',
'after_setup_theme',
'init',
'widgets_init',
'wp_loaded',
'template_redirect',
);
if ( perflab_server_timing_use_output_buffer() ) {
$action_hooks[] = 'wp_head';
$action_hooks[] = 'wp_enqueue_scripts';
$action_hooks[] = 'wp_footer';
}
array_walk( $action_hooks, 'stx_measure_action' );
/* More filters can be added here. */
$filter_hooks = array();
array_walk( $filter_hooks, 'stx_measure_filter' );
// Measure all callbacks of the 'wp_enqueue_scripts' action individually.
add_action(
'template_redirect',
function() {
if ( perflab_server_timing_use_output_buffer() ) {
stx_profile_hook_callbacks( 'wp_enqueue_scripts' );
}
}
);
// Time it takes to parse the request (including, but not exclusively, the 'parse_request' action).
add_filter(
'do_parse_request',
function( $passthrough ) {
perflab_server_timing_register_metric(
'parse-request',
array(
'measure_callback' => function( $metric ) {
$metric->measure_before();
add_action( 'parse_request', array( $metric, 'measure_after' ), PHP_INT_MAX );
},
'access_cap' => 'exist',
)
);
return $passthrough;
},
PHP_INT_MAX
);
// Time it takes to locate the template.
add_action(
'template_redirect',
function() {
perflab_server_timing_register_metric(
'locate-template',
array(
'measure_callback' => function( $metric ) {
$metric->measure_before();
add_filter(
'template_include',
function( $passthrough ) use ( $metric ) {
$metric->measure_after();
return $passthrough;
},
defined( 'PHP_INT_MIN' ) ? PHP_INT_MIN : -9999
);
},
'access_cap' => 'exist',
)
);
},
PHP_INT_MAX
);
}
add_action( 'plugins_loaded', 'stx_capture_extra_metrics', 0 );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment