Skip to content

Instantly share code, notes, and snippets.

@westonruter
Last active October 11, 2025 23:42
Show Gist options
  • Save westonruter/99af37489334927aaf04a46eaf2a11eb to your computer and use it in GitHub Desktop.
Save westonruter/99af37489334927aaf04a46eaf2a11eb to your computer and use it in GitHub Desktop.
<?php
/**
* Plugin Name: Always Load Block Styles on Demand
* Plugin URI: https://gist.github.com/westonruter/99af37489334927aaf04a46eaf2a11eb
* Description: In classic themes a lot more CSS is added to a page than is needed because when the HEAD is rendered before the rest of the page, so it is not yet known what blocks will be used. This can be fixed with output buffering. This is a demonstration plugin for Core Trac ticket #43258 which adds output buffering for the rendered template.
* Requires at least: 6.9-alpha1
* Version: 0.2.0
* Author: Weston Ruter
* Author URI: https://weston.ruter.net/
* License: GPLv2 or later
* License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* Update URI: false
* GitHub Plugin URI: https://gist.github.com/westonruter/99af37489334927aaf04a46eaf2a11eb
* Primary Branch: main
*
* @package always-load-block-styles-on-demand
*/
namespace AlwaysLoadBlockStylesOnDemand;
/**
* Initializes hooks.
*/
function init(): void {
if ( wp_is_block_theme() || ! function_exists( 'wp_should_output_buffer_template_for_enhancement' ) ) {
return;
}
/*
* Make sure that wp_should_output_buffer_template_for_enhancement() returns true even if there aren't any
* `wp_template_enhancement_output_buffer` filters added, but do so at priority zero so that applications which
* wish to stream responses can more easily turn this off. This plugin adds the
* `wp_template_enhancement_output_buffer` filter via a closure below.
*/
add_filter( 'wp_should_output_buffer_template_for_enhancement', '__return_true', 0 );
if ( ! wp_should_output_buffer_template_for_enhancement() ) {
return;
}
// Load separate block styles so that the large block-library stylesheet is not enqueued unconditionally,
// and so that block-specific styles will only be enqueued when they are used on the page.
add_filter( 'should_load_separate_core_block_assets', '__return_true' );
// Also ensure that block assets are loaded on demand (although the default value is should_load_separate_core_block_assets).
add_filter( 'should_load_block_assets_on_demand', '__return_true' );
// Add hooks which require the presence of the output buffer. Ideally the above two filters could be added here, but they run too early.
add_action( 'wp_template_enhancement_output_buffer_started', __NAMESPACE__ . '\add_hooks_for_output_buffer' );
}
add_action( 'after_setup_theme', __NAMESPACE__ . '\init' );
/**
* Adds hooks for the output buffer.
*/
function add_hooks_for_output_buffer(): void {
// While normally late styles are printed, there is a filter to disable late styles, so this makes sure they are printed.
add_filter( 'print_late_styles', '__return_true', 100 );
// Print a placeholder comment to inject late styles right after the head styles are printed.
$placeholder = sprintf( '<!--%s:%s-->', 'late_styles', wp_generate_uuid4() );
remove_action( 'wp_head', 'wp_print_styles', 8 );
add_action(
'wp_head',
static function () use ( $placeholder ) {
wp_print_styles();
echo $placeholder;
},
8
);
// Replace logic that prints scripts and styles in the footer,
$late_styles = '';
remove_action( 'wp_print_footer_scripts', '_wp_footer_scripts' );
add_action(
'wp_print_footer_scripts',
static function () use ( &$late_styles ) {
ob_start();
print_late_styles();
$late_styles = ob_get_clean();
print_footer_scripts();
}
);
// Replace placeholder with the captured late styles.
add_filter(
'wp_template_enhancement_output_buffer',
static function ( $buffer ) use ( $placeholder, &$late_styles ) {
return str_replace( $placeholder, $late_styles, $buffer );
}
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment