Skip to content

Commit 48eb4f6

Browse files
committed
Preserve CSS cascade so wp-block-library inline styles appear after inlined core block styles
1 parent ff8cbc1 commit 48eb4f6

2 files changed

Lines changed: 137 additions & 54 deletions

File tree

src/wp-includes/script-loader.php

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3742,16 +3742,21 @@ static function () use ( &$style_handles_at_enqueue_block_assets ) {
37423742
/*
37433743
* Add a placeholder comment into the inline styles for wp-block-library, after which the late block styles
37443744
* can be hoisted from the footer to be printed in the header by means of a filter below on the template enhancement
3745-
* output buffer. The `wp_print_styles` action is used to ensure that if the inline style gets replaced at
3746-
* `enqueue_block_assets` or `wp_enqueue_scripts` that the placeholder will be sure to be present.
3745+
* output buffer.
3746+
*
3747+
* Note that wp_maybe_inline_styles() prepends the inlined style to the extra 'after' array, which happens after
3748+
* this code runs. This ensures that the placeholder appears right after any inlined wp-block-library styles,
3749+
* which would be common.css.
37473750
*/
37483751
$placeholder = sprintf( '/*%s*/', uniqid( 'wp_block_styles_on_demand_placeholder:' ) );
3749-
add_action(
3750-
'wp_print_styles',
3751-
static function () use ( $placeholder ) {
3752+
$dependency = wp_styles()->query( 'wp-block-library', 'registered' );
3753+
if ( $dependency ) {
3754+
if ( ! isset( $dependency->extra['after'] ) ) {
37523755
wp_add_inline_style( 'wp-block-library', $placeholder );
3756+
} else {
3757+
array_unshift( $dependency->extra['after'], $placeholder );
37533758
}
3754-
);
3759+
}
37553760

37563761
/*
37573762
* Create a substitute for `print_late_styles()` which is aware of block styles. This substitute does not print
@@ -3963,13 +3968,34 @@ public function replace( string $text ) {
39633968
$css_text = $processor->get_modifiable_text();
39643969

39653970
/*
3966-
* A placeholder CSS comment is added to the inline style in order to force an inline STYLE tag to
3967-
* be printed. Now that we've located the inline style, the placeholder comment can be removed. If
3968-
* there is no CSS left in the STYLE tag after removing the placeholder (aside from the sourceURL
3969-
* comment), then remove the STYLE entirely.
3971+
* Split the block library inline style by the placeholder to identify the original inlined CSS, which
3972+
* is likely would be common.css, followed by any inline styles which had been added by the theme or
3973+
* plugins via `wp_add_inline_style( 'wp-block-library', '...' )`. The separate block styles loaded on
3974+
* demand will get inserted after the inlined common.css and before the extra inline styles added by the
3975+
* user.
39703976
*/
3971-
$css_text = str_replace( $placeholder, '', $css_text );
3972-
if ( preg_match( ':^/\*# sourceURL=\S+? \*/$:', trim( $css_text ) ) ) {
3977+
$css_text_around_placeholder = explode( $placeholder, $css_text, 2 );
3978+
$extra_inline_styles = '';
3979+
if ( count( $css_text_around_placeholder ) === 2 ) {
3980+
$css_text = $css_text_around_placeholder[0];
3981+
if ( '' !== trim( $css_text ) ) {
3982+
$inlined_src = wp_styles()->get_data( 'wp-block-library', 'inlined_src' );
3983+
if ( $inlined_src ) {
3984+
$css_text .= sprintf(
3985+
"\n/*# sourceURL=%s */\n",
3986+
esc_url_raw( $inlined_src )
3987+
);
3988+
}
3989+
}
3990+
$extra_inline_styles = $css_text_around_placeholder[1];
3991+
}
3992+
3993+
/*
3994+
* The placeholder CSS comment was added to the inline style in order to force an inline STYLE tag to
3995+
* be printed. Now that the inline style has been located and the placeholder comment was be removed, if
3996+
* there is no CSS left in the STYLE tag after removal, then remove the STYLE entirely.
3997+
*/
3998+
if ( '' === trim( $css_text ) ) {
39733999
$processor->remove();
39744000
} else {
39754001
$processor->set_modifiable_text( $css_text );
@@ -3978,6 +4004,15 @@ public function replace( string $text ) {
39784004
$inserted_after = $printed_core_block_styles;
39794005
$printed_core_block_styles = '';
39804006

4007+
/*
4008+
* Add a new inline style for any user styles added wp_add_inline_style( 'wp-block-library', '...' ).
4009+
* This must be added here after $printed_core_block_styles to preserve the original CSS cascade when
4010+
* the combined block library stylesheet was used.
4011+
*/
4012+
if ( ! preg_match( ':^\s*/\*# sourceURL=\S+? \*/\s*$:s', $extra_inline_styles ) ) {
4013+
$inserted_after .= "<style id='wp-block-library-inline-css-extra'>$extra_inline_styles</style>\n";
4014+
}
4015+
39814016
// If the classic-theme-styles is absent, then the third-party block styles cannot be inserted after it, so they get inserted here.
39824017
if ( ! $processor->has_bookmark( 'classic_theme_styles' ) ) {
39834018
if ( '' !== $printed_other_block_styles ) {

tests/phpunit/tests/template.php

Lines changed: 90 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,7 +1478,13 @@ public function test_wp_load_classic_theme_block_styles_on_demand( string $theme
14781478
/**
14791479
* Data provider.
14801480
*
1481-
* @return array<string, array{set_up: Closure|null, content: string, inline_size_limit: int, expected_styles: array{ HEAD: string[], BODY: string[] }}>
1481+
* @return array<string, array{
1482+
* set_up: Closure|null,
1483+
* content: string,
1484+
* inline_size_limit: int,
1485+
* expected_styles: array{ HEAD: string[], BODY: string[] },
1486+
* assert?: Closure( string, string, array{ HEAD: string[], BODY: string[] } ): void,
1487+
* }>
14821488
*/
14831489
public function data_wp_hoist_late_printed_styles(): array {
14841490
$blocks_content = '<!-- wp:separator --><hr class="wp-block-separator has-alpha-channel-opacity"/><!-- /wp:separator --><!-- wp:third-party/test --><div>This is only a test!</div><!-- /wp:third-party/test -->';
@@ -1541,6 +1547,7 @@ public function data_wp_hoist_late_printed_styles(): array {
15411547
'BODY' => array(),
15421548
),
15431549
),
1550+
15441551
'standard_classic_theme_config_with_max_styles_inlined' => array(
15451552
'set_up' => null,
15461553
'content' => $blocks_content,
@@ -1563,6 +1570,7 @@ public function data_wp_hoist_late_printed_styles(): array {
15631570
'BODY' => array(),
15641571
),
15651572
),
1573+
15661574
'classic_theme_styles_omitted' => array(
15671575
'set_up' => static function () {
15681576
// Note that wp_enqueue_scripts is used instead of enqueue_block_assets because it runs again at the former action.
@@ -1593,6 +1601,7 @@ static function () {
15931601
'BODY' => array(),
15941602
),
15951603
),
1604+
15961605
'no_styles_at_enqueued_block_assets' => array(
15971606
'set_up' => static function () {
15981607
add_action(
@@ -1622,6 +1631,7 @@ static function () {
16221631
'BODY' => array(),
16231632
),
16241633
),
1634+
16251635
'no_global_styles' => array(
16261636
'set_up' => static function () {
16271637
$dequeue = static function () {
@@ -1649,28 +1659,89 @@ static function () {
16491659
'BODY' => array(),
16501660
),
16511661
),
1652-
'standard_classic_theme_config_extra_block_library_inline_style' => array(
1662+
1663+
'standard_classic_theme_config_extra_block_library_inline_style_none_inlined' => array(
16531664
'set_up' => static function () {
16541665
add_action(
16551666
'enqueue_block_assets',
16561667
static function () {
1657-
wp_add_inline_style( 'wp-block-library', '/* Extra CSS which prevents empty inline style containing placeholder from being removed. */' );
1668+
// Extra CSS which prevents empty inline style containing placeholder from being removed.
1669+
wp_add_inline_style( 'wp-block-library', '.wp-block-separator{ outline:solid 1px lime; }' );
16581670
}
16591671
);
16601672
},
16611673
'content' => $blocks_content,
16621674
'inline_size_limit' => 0,
16631675
'expected_styles' => array(
1664-
'HEAD' => ( function ( $expected_styles ) {
1665-
// Insert 'wp-block-library-inline-css' right after 'wp-block-library-css'.
1666-
$i = array_search( 'wp-block-library-css', $expected_styles, true );
1667-
$this->assertIsInt( $i, 'Expected wp-block-library-css to be among the styles.' );
1668-
array_splice( $expected_styles, $i + 1, 0, 'wp-block-library-inline-css' );
1669-
return $expected_styles;
1670-
} )( $common_expected_head_styles ),
1676+
'HEAD' => array_merge(
1677+
$early_common_styles,
1678+
array(
1679+
'wp-block-library-css',
1680+
'wp-block-separator-css',
1681+
'wp-block-library-inline-css-extra',
1682+
'classic-theme-styles-css',
1683+
'third-party-test-block-css',
1684+
'custom-block-styles-css',
1685+
'global-styles-inline-css',
1686+
),
1687+
$common_at_wp_enqueue_scripts,
1688+
$common_late_in_head,
1689+
$common_late_in_body
1690+
),
1691+
'BODY' => array(),
1692+
),
1693+
'assert' => function ( string $buffer, string $filtered_buffer ) {
1694+
$block_separator_inline_style_start_tag = "<link rel='stylesheet' id='wp-block-separator-css'";
1695+
$block_separator_custom_style = '.wp-block-separator{ outline:solid 1px lime; }';
1696+
$this->assertStringContainsString( $block_separator_inline_style_start_tag, $filtered_buffer );
1697+
$this->assertStringContainsString( $block_separator_custom_style, $filtered_buffer );
1698+
$block_separator_inline_style_position = strpos( $filtered_buffer, $block_separator_inline_style_start_tag );
1699+
$block_separator_custom_style_position = strpos( $filtered_buffer, $block_separator_custom_style );
1700+
$this->assertTrue( $block_separator_custom_style_position > $block_separator_inline_style_position, 'Expected the block separator custom style to appear after the block separator stylesheet.' );
1701+
},
1702+
),
1703+
1704+
'standard_classic_theme_config_extra_block_library_inline_style_all_inlined' => array(
1705+
'set_up' => static function () {
1706+
add_action(
1707+
'enqueue_block_assets',
1708+
static function () {
1709+
// Extra CSS which prevents empty inline style containing placeholder from being removed.
1710+
wp_add_inline_style( 'wp-block-library', '.wp-block-separator{ outline:solid 1px lime; }' );
1711+
}
1712+
);
1713+
},
1714+
'content' => $blocks_content,
1715+
'inline_size_limit' => PHP_INT_MAX,
1716+
'expected_styles' => array(
1717+
'HEAD' => array_merge(
1718+
$early_common_styles,
1719+
array(
1720+
'wp-block-library-inline-css',
1721+
'wp-block-separator-inline-css',
1722+
'wp-block-library-inline-css-extra',
1723+
'classic-theme-styles-inline-css',
1724+
'third-party-test-block-css',
1725+
'custom-block-styles-css',
1726+
'global-styles-inline-css',
1727+
),
1728+
$common_at_wp_enqueue_scripts,
1729+
$common_late_in_head,
1730+
$common_late_in_body
1731+
),
16711732
'BODY' => array(),
16721733
),
1734+
'assert' => function ( string $buffer, string $filtered_buffer ) {
1735+
$block_separator_inline_style_start_tag = '<style id="wp-block-separator-inline-css">';
1736+
$block_separator_custom_style = '.wp-block-separator{ outline:solid 1px lime; }';
1737+
$this->assertStringContainsString( $block_separator_inline_style_start_tag, $filtered_buffer );
1738+
$this->assertStringContainsString( $block_separator_custom_style, $filtered_buffer );
1739+
$block_separator_inline_style_position = strpos( $filtered_buffer, $block_separator_inline_style_start_tag );
1740+
$block_separator_custom_style_position = strpos( $filtered_buffer, $block_separator_custom_style );
1741+
$this->assertTrue( $block_separator_custom_style_position > $block_separator_inline_style_position, 'Expected the block separator custom style to appear after the block separator stylesheet.' );
1742+
},
16731743
),
1744+
16741745
'classic_theme_opt_out_separate_block_styles' => array(
16751746
'set_up' => static function () {
16761747
add_filter( 'should_load_separate_core_block_assets', '__return_false' );
@@ -1693,6 +1764,7 @@ static function () {
16931764
'BODY' => $common_late_in_body,
16941765
),
16951766
),
1767+
16961768
'_wp_footer_scripts_removed' => array(
16971769
'set_up' => static function () {
16981770
remove_action( 'wp_print_footer_scripts', '_wp_footer_scripts' );
@@ -1704,6 +1776,7 @@ static function () {
17041776
'BODY' => array(),
17051777
),
17061778
),
1779+
17071780
'wp_print_footer_scripts_removed' => array(
17081781
'set_up' => static function () {
17091782
remove_action( 'wp_footer', 'wp_print_footer_scripts', 20 );
@@ -1715,6 +1788,7 @@ static function () {
17151788
'BODY' => array(),
17161789
),
17171790
),
1791+
17181792
'both_actions_removed' => array(
17191793
'set_up' => static function () {
17201794
remove_action( 'wp_print_footer_scripts', '_wp_footer_scripts' );
@@ -1727,6 +1801,7 @@ static function () {
17271801
'BODY' => array(),
17281802
),
17291803
),
1804+
17301805
'disable_block_library_and_load_combined' => array(
17311806
'set_up' => static function () {
17321807
add_action(
@@ -1755,37 +1830,6 @@ function (): void {
17551830
'BODY' => $common_late_in_body,
17561831
),
17571832
),
1758-
'override_block_library_inline_style_late' => array(
1759-
'set_up' => static function () {
1760-
add_action(
1761-
'enqueue_block_assets',
1762-
function (): void {
1763-
// This tests what happens when the placeholder comment gets replaced unexpectedly.
1764-
wp_styles()->registered['wp-block-library']->extra['after'] = array( '/* OVERRIDDEN! */' );
1765-
}
1766-
);
1767-
},
1768-
'content' => $blocks_content,
1769-
'inline_size_limit' => 0,
1770-
'expected_styles' => array(
1771-
'HEAD' => array_merge(
1772-
$early_common_styles,
1773-
array(
1774-
'wp-block-library-css',
1775-
'wp-block-library-inline-css', // This contains the "OVERRIDDEN" text.
1776-
'wp-block-separator-css',
1777-
'classic-theme-styles-css',
1778-
'third-party-test-block-css',
1779-
'custom-block-styles-css',
1780-
'global-styles-inline-css',
1781-
),
1782-
$common_at_wp_enqueue_scripts,
1783-
$common_late_in_head,
1784-
$common_late_in_body
1785-
),
1786-
'BODY' => array(),
1787-
),
1788-
),
17891833

17901834
// This tests the Elementor scenario (e.g. Hello Elementor).
17911835
'dequeue_block_library_but_with_theme_json_and_no_block_content' => array(
@@ -1893,7 +1937,7 @@ static function ( $path, $file ) {
18931937
*
18941938
* @dataProvider data_wp_hoist_late_printed_styles
18951939
*/
1896-
public function test_wp_hoist_late_printed_styles( ?Closure $set_up, string $content, int $inline_size_limit, array $expected_styles ): void {
1940+
public function test_wp_hoist_late_printed_styles( ?Closure $set_up, string $content, int $inline_size_limit, array $expected_styles, ?Closure $assert = null ): void {
18971941
// `_print_emoji_detection_script()` assumes `wp-includes/js/wp-emoji-loader.js` is present:
18981942
self::touch( ABSPATH . WPINC . '/js/wp-emoji-loader.js' );
18991943

@@ -2051,6 +2095,10 @@ static function () {
20512095
$found_subset_styles,
20522096
'Expected the same styles. Snapshot: ' . self::get_array_snapshot_export( $found_subset_styles )
20532097
);
2098+
2099+
if ( $assert ) {
2100+
$assert( $buffer, $filtered_buffer, $found_subset_styles );
2101+
}
20542102
}
20552103

20562104
/**

0 commit comments

Comments
 (0)