Repository navigation
Script Loader: Add an API for filtering inline style attributes - #13250
Sukhendu2002 wants to merge 32 commits into
Conversation
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Replace substring and exact-string assertions with assertEqualHTML() for fully deterministic output, so attribute order, quoting style and self-closing syntax no longer cause spurious failures. Use WP_HTML_Tag_Processor where full-markup comparison is a poor fit: the core concatenation test (whose load-styles.php URL is noisy) and the closing-tag escaping test, which now checks that the CSS cannot break out of the STYLE element rather than pinning the exact escape sequence. Also verify the attributes passed to the wp_inline_style_attributes filter during normal style output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Widen the documented attribute value type from string|true to string|bool for wp_get_inline_style_tag(), wp_print_inline_style_tag() and the wp_inline_style_attributes filter. This matches wp_get_script_tag() and wp_get_inline_script_tag(), and reflects that a false value omits the attribute, as the filter docblock already describes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When wp_hoist_late_printed_styles() splits CSS added via wp_add_inline_style( 'wp-block-library', ... ) into a separate wp-block-library-inline-css-extra STYLE tag, build that tag with wp_get_inline_style_tag() so it receives the attributes from the wp_inline_style_attributes filter. Previously the original tag had a filtered nonce but the split-off tag did not, so a nonce-based Content Security Policy would block the CSS after hoisting. Add a hoisting test data set which filters in a nonce, and loosen the global styles placeholder pattern so that it still matches the placeholder STYLE tag when it has additional attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In WP_Styles::do_item(), the inline style for a handle is already obtained up front via print_inline_style( $handle, false ). When not concatenating, calling print_inline_style( $handle ) again re-read the after data and rebuilt the sourceURL comment. Instead, append the inline style tag to the LINK tag once, and then print or buffer the result, which also removes the duplicated wp_get_inline_style_tag() call between the concat and non-concat branches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the remaining hand-built front-end STYLE tags via wp_print_inline_style_tag() so that they also receive attributes from the wp_inline_style_attributes filter, such as a nonce for a Content Security Policy: * Custom background (including the empty Customizer preview tag). * Additional CSS from the Customizer. * Custom logo header text hiding. * Block support styles. * Font faces. * Recent Comments widget. Add a data-provider test covering each STYLE tag printed outside of WP_Styles, and extend the hoisting test data set with a filtered nonce to assert that every STYLE tag in the page has it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The core inline style data sets add and remove theme support, which is not restored automatically between tests. The leaked custom-background support caused WP_Test_REST_Themes_Controller to fail with an undefined $custom_background global when run after these tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the error page styles with wp_print_inline_style_tag() so that they receive attributes from the wp_inline_style_attributes filter. Since wp_die() may be called before script-loader.php and the HTML API are loaded, fall back to a literal STYLE tag in that case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the transparent background style for the interim login modal with wp_print_inline_style_tag() so that it receives filtered attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the styles for wp-signup.php and wp-activate.php with wp_print_inline_style_tag() so that they receive filtered attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the banner background styles in the plugin information modal with wp_print_inline_style_tag() so that they receive filtered attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the site icon URL custom property with wp_print_inline_style_tag() so that it receives filtered attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the Customizer preview loading styles, the highlighted widget styles and the site icon control template styles with wp_print_inline_style_tag() so that they receive filtered attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the site icon URL custom property in the tmpl-site-icon-preview-crop template with wp_print_inline_style_tag() so that it receives filtered attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Build the gallery shortcode's default STYLE tag with wp_get_inline_style_tag() so that it receives filtered attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the reset styles in the Legacy Widget block preview and the REST API widget preview iframe with wp_print_inline_style_tag() so that they receive filtered attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the STYLE tags in print_embed_styles(), print_emoji_styles(), wp_admin_bar_header(), _admin_bar_bump_cb(), the_block_template_skip_link(), wp_print_auto_sizes_contain_css_fix() and graceful_fail() with the inline style tag API so that they receive filtered attributes when still called by plugins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Print the Kubrick background style in the theme compatibility header template with wp_print_inline_style_tag() so that it receives filtered attributes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pass the CSS for wp_admin_bar_header() and wp_print_auto_sizes_contain_css_fix() as a CSS nowdoc, like the other inline styles, so that IDEs apply CSS syntax highlighting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pass the CSS as a CSS nowdoc, like the other inline styles, so that IDEs apply CSS syntax highlighting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HTML character references are not decoded in STYLE elements, so the &WordPress#38; produced by esc_url() for a URL with multiple query parameters would end up in the CSS literally. Escape with esc_url_raw() instead, and wrap the URLs in double quotes: esc_url_raw() strips double quotes but not single quotes or parentheses, so an unquoted url() token could otherwise be terminated by the URL. Name the variables to make clear they are already escaped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HTML character references are not decoded in STYLE elements, so escape the URL with esc_url_raw() instead of esc_url(). Wrap it in double quotes, since esc_url_raw() strips double quotes but not single quotes, which could otherwise terminate the CSS string. Name the variable to make clear it is already escaped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HTML character references are not decoded in STYLE elements, so obtain the raw stylesheet directory URL and text direction rather than their display-filtered values, and escape the resulting URL with esc_url_raw(). Pass the CSS as a heredoc for syntax highlighting, and name the variable to make clear it is already escaped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Match the quoting used for url() values in the other inline styles, including the site icon crop preview template. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Call esc_url_raw() as a variable function inside the heredoc interpolation, so that the URLs are escaped at the point of output rather than in separate variables beforehand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Getting the raw stylesheet directory URL skipped the bloginfo_url filter, which plugins use to rewrite asset URLs, for example to a CDN. The display context applies no escaping to URLs, so esc_url_raw() remains correct. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The template is a sprintf() format, so a '%' in an attribute value added via the wp_inline_style_attributes filter would be treated as a conversion specification. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What this PR does
Adds a structured API for generating and filtering inline
<style>tags, mirroring the existing inline script tag API:wp_get_inline_style_tag( string $data, array $attributes = array() ).wp_print_inline_style_tag().wp_inline_style_attributesfilter, which receives the attributes and the CSS.WP_HTML_Tag_Processorfor safe attribute and CSS handling, including escaping of a closing</style>in the CSS.$attributesasarray<string, string|bool>, matchingwp_get_inline_script_tag().This allows plugins to add attributes such as CSP nonces without modifying complete HTML strings. The script portion of the original ticket is already covered by
wp_inline_script_attributes, so this PR focuses on the remaining inline style functionality.Core STYLE tags routed through the API
All
<style>tags constructed by core now go through the new API, so that they all receive the filtered attributes. This is especially important in the admin, where a CSP is most valuable.WP_Stylesoutput for normal, no-source, and concatenated inline styles, plus the hoisted extra block library styles and block support styles inscript-loader.php.WP_Font_Face.wp_die()handler, with a fallback to a literal<style>when it is called beforescript-loader.phpand the HTML API are loaded.contain-intrinsic-sizefix, andgraceful_fail().Literal CSS is passed as a
<<<'CSS'nowdoc (or a<<<CSSheredoc when interpolating), as is already done for<<<'JS'with inline scripts, so IDEs apply CSS syntax highlighting.URLs in
url()are escaped late withesc_url_raw()rather thanesc_url(), since HTML character references are not decoded inSTYLEelements, and are wrapped in double quotes, sinceesc_url_raw()strips double quotes but not single quotes or parentheses.Intentionally not changed
src/wp-includes/build/pages/*, which is generated from Gutenberg.privacy-tools.php, since it is a static HTML file where a per-request nonce does not belong.Testing
New tests in
tests/phpunit/tests/dependencies/wpInlineStyleTag.php,tests/phpunit/tests/dependencies/styles.php, andtests/phpunit/tests/template.phpuseassertEqualHTML()andWP_HTML_Tag_Processorto verify the output, including that the core inline styles have the filtered attributes.Trac ticket: https://core.trac.wordpress.org/ticket/51325
Use of AI Tools
AI assistance: Yes
Tool(s): OpenAI Codex
Model(s): GPT-5.6
Used for: Initial code skeleton, test suggestions and code review; final implementation and tests were reviewed and edited by me.
Additional commits were made with Claude Code (Claude Opus 5.5) at the direction of @westonruter, to make the tests more robust with
assertEqualHTML()andWP_HTML_Tag_Processor, to route the remaining core<style>tags through the new API, and to address code review findings. The changes were reviewed by @westonruter.This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.
🤖 Generated with Claude Code