All on-demand block styles missing on front end for users with Site Kit access (WP 6.9 classic themes, template enhancement output buffer)
- Dominant language
- JavaScript
- Stars
- 1.4k
- Forks
- 383
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 80
Description
## Bug Description
On WordPress 6.9+ with a classic theme, when Site Kit's authenticated front-end payload loads (admin bar stats enabled, user has Site Kit dashboard access), **all block styles that go through core's new capture-and-hoist pipeline are silently missing from the rendered page** — no ``/`` tag anywhere in the HTML, no network request, no console or PHP error visible to the user.
Affected on every page view by such users:
- all per-block core styles (`wp-block-paragraph-inline-css`, `wp-block-heading-inline-css`, `wp-block-image-inline-css`, …)
- `core-block-supports-inline-css`
- `global-styles-inline-css`
- third-party block styles registered via `register_block_type( $dir, [ 'style' => $handle ] )`
The same URL rendered for an anonymous visitor or a logged-in user **without** Site Kit access is correct. We A/B confirmed causation: granting Site Kit access to a previously unaffected account makes that account reproduce immediately; revoking it resolves it. (This made the bug look like a "random / per-machine" issue for weeks — it tracks Site Kit data access, not user/browser/OS.)
## Background (core mechanism)
Since WP 6.9, classic themes load block styles on demand: styles enqueued during block render are captured into PHP variables at `wp_print_footer_scripts` (`wp_hoist_late_printed_styles()`) and spliced into `<head>` by a filter on the template enhancement output buffer. Once captured, the styles exist only in memory and are marked `done` — if the insertion step delivers nothing, they are lost without any error. Related core tickets: https://core.trac.wordpress.org/ticket/64592 and https://core.trac.wordpress.org/ticket/64389 (cross-referenced there as well: https://core.trac.wordpress.org/ticket/64592#comment:7).
## Evidence
We diffed full HTML captures of the same post (broken = user with Site Kit access, good = user without; both logged in, uncached origin renders):
- Broken page: block markup present, **zero** hoisted styles, Site Kit assets present (`googlesitekit-adminbar-css`, fonts, ~24 footer scripts).
- Both pages: hoist anchors present (`wp-block-library-inline-css`, `classic-theme-styles-inline-css`), **and the
`wp_block_styles_on_demand_placeholder` comment is removed in both** — i.e. the output buffer filter ran and found its anchor, but the captured style variables were empty at insertion time.
- Script order, admin bar, and the rest of the document are otherwise identical.
Note core's capture closure is not idempotent: if `wp_print_footer_scripts` effectively fires twice (or the capture runs again), the handles are already in `done`, `do_items()` outputs nothing, and the captured variables are overwritten with empty strings — which produces exactly this fingerprint.
We have not isolated the exact call in Site Kit that disturbs the sequence. A suspicious area: for authorized users, `Core\Assets\Assets` registers "before print" callbacks on `wp_print_scripts` / `wp_print_styles`, and the `googlesitekit-apifetch-data` script-data callback executes ~15 inline REST requests via `rest_preload_api_request()` during printing. Happy to debug further with guidance, and we can share the (sanitized) HTML captures.
## Steps to reproduce
1. WordPress 6.9.1, any classic theme (on-demand block styles + hoisting active by default).
2. Install + set up Site Kit, enable "Display relevant page stats in the Admin bar".
3. As a user with Site Kit access, view a published post containing core blocks and/or a custom block with a registered style. View source.
4. Compare with the same URL as anonymous / as a user without Site Kit access.
**Expected:** block styles hoisted into `<head>` (as for other users).
**Actual:** all hoisted styles absent from the document; blocks render unstyled.
## Workaround
```php
add_filter( 'should_load_separate_core_block_assets', '__return_false', 100 );
```
## Additional Context
- Plugin Version: 1.173.0 (tested with the latest, 1.180.0, as well)
- WordPress: 6.9.1 (classic theme: JNews + child theme)
- PHP: 8.2 (tested with 8.3 and 8.4 as well)
- Modules connected: Search Console, Analytics, Tag Manager, AdSense, Ads, PageSpeed Insights, Sign in with Google, Reader Revenue Manager
- Reproduced on uncached origin renders (logged-in requests bypass all cache layers in our setup); browser/OS irrelevant
---------------
_Do not alter or remove anything below. The following sections will be managed by moderators only._
## Acceptance criteria
* <!-- One or more bullet points for acceptance criteria. -->
## Implementation Brief
* [ ] <!-- One or more bullet points for how to technically resolve the issue. Make sure to include changes to Storybook and visual regression tests where relevant. -->
### Test Coverage
* <!-- One or more bullet points for how to implement automated tests to verify the issue is resolved. -->
## QA Brief
* <!-- One or more bullet points for how to test that the issue has been resolved. -->
## Changelog entry
* <!-- One sentence summarizing the PR, to be used in the changelog. -->
Contributor guide
Assessment
This issue has not been assessed yet.