Description
When a block sits inside a synced pattern (core/block) that is itself nested inside another block, none of that block's assets are enqueued on the frontend — neither its stylesheet nor its script. The block renders as bare markup.
I expect the pattern's blocks to get their assets registered regardless of how deeply the pattern is nested, the same way they do when the pattern sits at the top level of the page. Instead nothing is registered.
For the Form block the consequence is not only cosmetic: submission happens in JS, so the form cannot be submitted at all. .otter-form__container also loses display: flex, so field widths stop working and inputs fall back to the theme's default styling.
Step-by-step reproduction instructions
- Add a Form block to a page.
- Select it and create a synced pattern from it.
- On a page, place that pattern inside a Group block.
- View the page on the frontend and look for
otter-form-style and build/blocks/form.js.
Two otherwise identical pages against the same pattern:
| Page content |
otter-form-style |
form.js |
core/block at top level |
loaded |
loaded |
core/group > core/block |
missing |
missing |
Screenshots, screen recording, code snippet or Help Scout ticket
Registration::enqueue_dependencies() — inc/class-registration.php:531:
if ( has_block( 'core/block', $post ) ) {
$blocks = parse_blocks( $content );
$blocks = array_filter(
$blocks,
function ( $block ) {
return 'core/block' === $block['blockName'] && isset( $block['attrs']['ref'] );
}
);
foreach ( $blocks as $block ) {
$this->enqueue_dependencies( $block['attrs']['ref'] );
}
}
parse_blocks() returns a flat list of top-level blocks and innerBlocks is never walked, so a nested pattern is invisible. The has_block() guard above does match, since it searches the raw content string — only the collection step misses it.
Two things that may be worth more than adding recursion:
-
The plugin already gets this right elsewhere. The dynamic CSS path in inc/css/class-block-frontend.php traverses nested patterns correctly. That asymmetry is what made this look like an oversight rather than a deliberate trade-off.
-
The conditional registration is what defeats WordPress's own mechanism. The Form block declares "style": "otter-form-style" and "script": "otter-form" in its block.json, and core enqueues those handles when the block actually renders — at any depth, from a pattern or not. But the handles are only registered if this scan found the block first, so core's enqueue silently no-ops on an unregistered handle. Registration is cheap; enqueueing is what costs. Registering unconditionally and letting core enqueue at render time would make the scan, and this bug, unnecessary.
The same flat filter serves the widgets path (enqueue_dependencies( 'widgets' )), so a nested pattern in a widget area is affected too.
Environment info
Otter Blocks 3.2.2, WordPress 7.0.4, PHP 8.4, classic (non-FSE) theme — a Neve child theme. The code is unchanged on master as of this writing. No pastebin; happy to provide Site Health info if useful.
Is the issue you are reporting a regression
No. The pattern handling was added in 2.0.1 ("Fix styles not loaded for Reusable Blocks") and has only ever covered the top level. Since WP 6.3 made synced patterns the standard way to reuse content — typically nested inside a section or group — the case has become common.
Created with help of Claude Code.
Description
When a block sits inside a synced pattern (
core/block) that is itself nested inside another block, none of that block's assets are enqueued on the frontend — neither its stylesheet nor its script. The block renders as bare markup.I expect the pattern's blocks to get their assets registered regardless of how deeply the pattern is nested, the same way they do when the pattern sits at the top level of the page. Instead nothing is registered.
For the Form block the consequence is not only cosmetic: submission happens in JS, so the form cannot be submitted at all.
.otter-form__containeralso losesdisplay: flex, so field widths stop working and inputs fall back to the theme's default styling.Step-by-step reproduction instructions
otter-form-styleandbuild/blocks/form.js.Two otherwise identical pages against the same pattern:
otter-form-styleform.jscore/blockat top levelcore/group > core/blockScreenshots, screen recording, code snippet or Help Scout ticket
Registration::enqueue_dependencies()—inc/class-registration.php:531:parse_blocks()returns a flat list of top-level blocks andinnerBlocksis never walked, so a nested pattern is invisible. Thehas_block()guard above does match, since it searches the raw content string — only the collection step misses it.Two things that may be worth more than adding recursion:
The plugin already gets this right elsewhere. The dynamic CSS path in
inc/css/class-block-frontend.phptraverses nested patterns correctly. That asymmetry is what made this look like an oversight rather than a deliberate trade-off.The conditional registration is what defeats WordPress's own mechanism. The Form block declares
"style": "otter-form-style"and"script": "otter-form"in itsblock.json, and core enqueues those handles when the block actually renders — at any depth, from a pattern or not. But the handles are only registered if this scan found the block first, so core's enqueue silently no-ops on an unregistered handle. Registration is cheap; enqueueing is what costs. Registering unconditionally and letting core enqueue at render time would make the scan, and this bug, unnecessary.The same flat filter serves the widgets path (
enqueue_dependencies( 'widgets' )), so a nested pattern in a widget area is affected too.Environment info
Otter Blocks 3.2.2, WordPress 7.0.4, PHP 8.4, classic (non-FSE) theme — a Neve child theme. The code is unchanged on
masteras of this writing. No pastebin; happy to provide Site Health info if useful.Is the issue you are reporting a regression
No. The pattern handling was added in 2.0.1 ("Fix styles not loaded for Reusable Blocks") and has only ever covered the top level. Since WP 6.3 made synced patterns the standard way to reuse content — typically nested inside a section or group — the case has become common.
Created with help of Claude Code.