Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add output buffering checkbox to Server-Timing screen #801

Merged
merged 18 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
101 changes: 93 additions & 8 deletions admin/server-timing.php
Expand Up @@ -43,6 +43,13 @@ function perflab_add_server_timing_page() {
* @since n.e.x.t
*/
function perflab_load_server_timing_page() {
add_settings_section(
'output-buffering',
__( 'Output Buffering', 'performance-lab' ),
'perflab_render_server_timing_page_output_buffer_checkbox',
PERFLAB_SERVER_TIMING_SCREEN
);

add_settings_section(
'benchmarking',
__( 'Benchmarking', 'performance-lab' ),
Expand Down Expand Up @@ -71,12 +78,16 @@ static function() {
<?php
echo wp_kses(
sprintf(
/* translators: 1: Server-Timing, 2: template_include */
__( 'Since the %1$s header is sent before the template is loaded, only hooks before the %2$s filter can be measured.', 'performance-lab' ),
/* translators: 1: Server-Timing, 2: template_include, 3: anchor link */
__( 'Since the %1$s header is sent before the template is loaded, only hooks before the %2$s filter can be measured. Enable <a href="%3$s">Output Buffering</a> to measure hooks during template rendering.', 'performance-lab' ),
felixarntz marked this conversation as resolved.
Show resolved Hide resolved
'<code>Server-Timing</code>',
'<code>template_include</code>'
'<code>template_include</code>',
esc_url( '#server_timing_output_buffering' )
),
array( 'code' => array() )
array(
'code' => array(),
'a' => array( 'href' => true ),
)
);
}
?>
Expand All @@ -95,7 +106,7 @@ static function() {
'benchmarking_actions',
__( 'Actions', 'performance-lab' ),
static function() {
perflab_render_server_timing_page_field( 'benchmarking_actions' );
perflab_render_server_timing_page_hooks_field( 'benchmarking_actions' );
},
PERFLAB_SERVER_TIMING_SCREEN,
'benchmarking',
Expand All @@ -105,7 +116,7 @@ static function() {
'benchmarking_filters',
__( 'Filters', 'performance-lab' ),
static function() {
perflab_render_server_timing_page_field( 'benchmarking_filters' );
perflab_render_server_timing_page_hooks_field( 'benchmarking_filters' );
},
PERFLAB_SERVER_TIMING_SCREEN,
'benchmarking',
Expand Down Expand Up @@ -136,13 +147,13 @@ function perflab_render_server_timing_page() {
}

/**
* Renders a field for the given Server-Timing option.
* Renders a hooks field for the given Server-Timing option.
*
* @since n.e.x.t
*
* @param string $slug Slug of the field and sub-key in the Server-Timing option.
*/
function perflab_render_server_timing_page_field( $slug ) {
function perflab_render_server_timing_page_hooks_field( $slug ) {
$options = (array) get_option( PERFLAB_SERVER_TIMING_SETTING, array() );

// Value for the sub-key is an array of hook names.
Expand All @@ -168,3 +179,77 @@ class="large-text code"
</p>
<?php
}

/**
* Renders a checkbox for enabling output buffering for Server-Timing.
*
* @since n.e.x.t
*/
function perflab_render_server_timing_page_output_buffer_checkbox() {
$slug = 'output_buffering';
$field_id = "server_timing_{$slug}";
$field_name = PERFLAB_SERVER_TIMING_SETTING . '[' . $slug . ']';
$description_id = "{$field_id}_description";
$has_filter = has_filter( 'perflab_server_timing_use_output_buffer' );
$is_enabled = perflab_server_timing_use_output_buffer();

?>
<style>
/* The following styles are copied from core where they normally include `.form-table td` in the selectors. */
fieldset.output-buffering {
margin-bottom: 9px;
padding: 15px 10px 15px 0;
felixarntz marked this conversation as resolved.
Show resolved Hide resolved
line-height: 1.3;
vertical-align: middle;
font-size: 14px;
}
fieldset.output-buffering label,
fieldset.output-buffering p {
line-height: 1.4;
}
fieldset.output-buffering label {
margin: 0.35em 0 0.5em !important;
display: inline-block;
}
fieldset.output-buffering p {
font-size: 14px;
}
</style>
<fieldset class="output-buffering">
<legend class="screen-reader-text">
<?php esc_html_e( 'Output Buffering', 'performance-lab' ); ?>
</legend>
<input
type="checkbox"
id="<?php echo esc_attr( $field_id ); ?>"
name="<?php echo esc_attr( $field_name ); ?>"
aria-describedby="<?php echo esc_attr( $description_id ); ?>"
<?php disabled( $has_filter ); ?>
<?php checked( $is_enabled ); ?>
>
<label for="<?php echo esc_attr( $field_id ); ?>">
<?php esc_html_e( 'Enable output buffering of template rendering.', 'performance-lab' ); ?>
</label>
<p id="<?php echo esc_attr( $description_id ); ?>" class="description">
<?php if ( $has_filter ) : ?>
<?php if ( $is_enabled ) : ?>
<?php
echo wp_kses(
__( 'Output buffering has been forcibly enabled via the <code>perflab_server_timing_use_output_buffer</code> filter.', 'performance-lab' ),
felixarntz marked this conversation as resolved.
Show resolved Hide resolved
array( 'code' => array() )
);
?>
<?php else : ?>
<?php
echo wp_kses(
__( 'Output buffering has been forcibly disabled via the <code>perflab_server_timing_use_output_buffer</code> filter.', 'performance-lab' ),
felixarntz marked this conversation as resolved.
Show resolved Hide resolved
array( 'code' => array() )
);
?>
felixarntz marked this conversation as resolved.
Show resolved Hide resolved
<?php endif; ?>
<?php endif; ?>
<?php esc_html_e( 'This is needed to capture metrics after headers have been sent and while the template is being rendered. Note that output buffering may possibly cause an increase in TTFB if the response would be flushed multiple times.', 'performance-lab' ); ?>
felixarntz marked this conversation as resolved.
Show resolved Hide resolved
westonruter marked this conversation as resolved.
Show resolved Hide resolved
</p>
</fieldset>
<?php
}
6 changes: 5 additions & 1 deletion server-timing/class-perflab-server-timing.php
Expand Up @@ -195,6 +195,10 @@ static function( $value ) {
* @return bool True if an output buffer should be used, false otherwise.
*/
public function use_output_buffer() {
$slug = 'output_buffering';
$options = (array) get_option( PERFLAB_SERVER_TIMING_SETTING, array() );
$enabled = ! empty( $options[ $slug ] );
westonruter marked this conversation as resolved.
Show resolved Hide resolved

/**
* Filters whether an output buffer should be used to be able to gather additional Server-Timing metrics.
*
Expand All @@ -206,7 +210,7 @@ public function use_output_buffer() {
*
* @param bool $use_output_buffer Whether to use an output buffer.
*/
return apply_filters( 'perflab_server_timing_use_output_buffer', false );
return (bool) apply_filters( 'perflab_server_timing_use_output_buffer', $enabled );
}

/**
Expand Down
5 changes: 4 additions & 1 deletion server-timing/load.php
Expand Up @@ -163,6 +163,7 @@ function perflab_sanitize_server_timing_setting( $value ) {
static $allowed_keys = array(
'benchmarking_actions' => true,
'benchmarking_filters' => true,
'output_buffering' => true,
);

if ( ! is_array( $value ) ) {
Expand All @@ -175,7 +176,7 @@ function perflab_sanitize_server_timing_setting( $value ) {
* Ensure that every element is an indexed array of hook names.
* Any duplicates across a group of hooks are removed.
*/
foreach ( $value as $key => $hooks ) {
foreach ( wp_array_slice_assoc( $value, array( 'benchmarking_actions', 'benchmarking_filters' ) ) as $key => $hooks ) {
if ( ! is_array( $hooks ) ) {
$hooks = explode( "\n", $hooks );
}
Expand Down Expand Up @@ -203,5 +204,7 @@ static function( $hookname ) {
);
}

$value['output_buffering'] = ! empty( $value['output_buffering'] );

return $value;
}
8 changes: 4 additions & 4 deletions tests/admin/server-timing-tests.php
Expand Up @@ -57,7 +57,7 @@ public function test_perflab_load_server_timing_page() {
array_keys( $wp_settings_fields[ PERFLAB_SERVER_TIMING_SCREEN ] )
);
$this->assertEqualSets(
array( 'benchmarking_actions', 'benchmarking_filters' ),
array( 'benchmarking_actions', 'benchmarking_filters', 'output_buffering' ),
array_keys( $wp_settings_fields[ PERFLAB_SERVER_TIMING_SCREEN ]['benchmarking'] )
);
}
Expand All @@ -75,7 +75,7 @@ public function test_perflab_render_server_timing_page_field() {
$slug = 'benchmarking_actions';

ob_start();
perflab_render_server_timing_page_field( $slug );
perflab_render_server_timing_page_hooks_field( $slug );
$output = ob_get_clean();

$this->assertStringContainsString( '<textarea', $output );
Expand All @@ -87,7 +87,7 @@ public function test_perflab_render_server_timing_page_field_empty_option() {
delete_option( PERFLAB_SERVER_TIMING_SETTING );

ob_start();
perflab_render_server_timing_page_field( 'benchmarking_actions' );
perflab_render_server_timing_page_hooks_field( 'benchmarking_actions' );
$output = ob_get_clean();

$this->assertStringContainsString( '></textarea>', $output );
Expand All @@ -100,7 +100,7 @@ public function test_perflab_render_server_timing_page_field_populated_option()
);

ob_start();
perflab_render_server_timing_page_field( 'benchmarking_actions' );
perflab_render_server_timing_page_hooks_field( 'benchmarking_actions' );
$output = ob_get_clean();

// Array is formatted/imploded as strings, one per line.
Expand Down
22 changes: 13 additions & 9 deletions tests/server-timing/load-tests.php
Expand Up @@ -103,39 +103,43 @@ public function data_perflab_sanitize_server_timing_setting() {
),
'empty list, array' => array(
array( 'benchmarking_actions' => array() ),
array( 'benchmarking_actions' => array() ),
array( 'benchmarking_actions' => array(), 'output_buffering' => false ),
),
'empty list, string' => array(
array( 'benchmarking_actions' => '' ),
array( 'benchmarking_actions' => array() ),
array( 'benchmarking_actions' => array(), 'output_buffering' => false ),
),
'empty list, string with whitespace' => array(
array( 'benchmarking_actions' => ' ' ),
array( 'benchmarking_actions' => array() ),
array( 'benchmarking_actions' => array(), 'output_buffering' => false ),
),
'regular list, array' => array(
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded' ) ),
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded' ) ),
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded' ), 'output_buffering' => false ),
),
'regular list, string' => array(
array( 'benchmarking_actions' => "after_setup_theme\ninit\nwp_loaded" ),
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded' ) ),
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded' ), 'output_buffering' => false ),
),
'regular list, string with whitespace' => array(
array( 'benchmarking_actions' => "after_setup_ theme \ninit \n\nwp_loaded\n" ),
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded' ) ),
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded' ), 'output_buffering' => false ),
),
'regular list, array with duplicates' => array(
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded', 'init' ) ),
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded' ) ),
array( 'benchmarking_actions' => array( 'after_setup_theme', 'init', 'wp_loaded' ), 'output_buffering' => false ),
),
'regular list, array with special hook chars' => array(
array( 'benchmarking_actions' => array( 'namespace/hookname', 'namespace.hookname' ) ),
array( 'benchmarking_actions' => array( 'namespace/hookname', 'namespace.hookname' ) ),
array( 'benchmarking_actions' => array( 'namespace/hookname', 'namespace.hookname' ), 'output_buffering' => false ),
),
'output buffering enabled' => array(
array( 'output_buffering' => 'on' ),
array( 'output_buffering' => true ),
),
'regular list, disallowed key' => array(
array( 'not_allowed' => array( 'after_setup_theme', 'init', 'wp_loaded' ) ),
array(),
array( 'output_buffering' => false ),
),
);
}
Expand Down