Codeinwp / Codeinwp/otter-blocks
Block assets are never enqueued when a block sits inside a nested synced pattern
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 198
- Forks
- 36
- Avg merge
- 3d 4h
- Merged PRs (30d)
- 30
Description
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-styleandbuild/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.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 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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at Registration::enqueue_dependencies() in inc/class-registration.php:531 and inspect how parse_blocks() collects core/block entries, then compare the nested-pattern traversal in inc/css/class-block-frontend.php. Reproduce the top-level and Group-nested cases, and verify that otter-form-style and build/blocks/form.js are loaded for the nested pattern, including in the widgets path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, php, wordpress
- Domain
- backend, frontend, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100