feat(core): Pattern Overrides support for Webentor blocks (release 0.15.7) - #6
Merged
Conversation
…15.7) WP 7.0 opened Pattern Overrides to custom blocks through a single server-side opt-in: any attribute listed in `block_bindings_supported_attributes` becomes overridable per synced-pattern instance. That one list drives the "Enable overrides" button, the Overrides panel, the editor read/write plumbing, the server-side substitution in WP_Block::render() and the contentOnly/disabled locking of instances -- so no JS was needed, core handles it generically. Opts in the content attributes of e-button (button), e-accordion and e-tab-container (title), e-image (imgId, link), e-svg (imgId), e-icon-picker (icon) and e-gallery (images), behind a new `webentor/block_bindings_supported_attributes` filter so projects can extend the map or opt their own blocks in. Also fixes a latent issue this exposed: the block render_callback discarded its $attributes argument -- the value WP guarantees carries resolved binding values for dynamic blocks -- and re-read $block->attributes instead. It now passes them into render_block_blade(), which takes an optional third argument. Two things explored and deliberately not shipped: - A `pattern/overrides` usesContext filter. Unnecessary: WP_Block::process_block_bindings() injects the source's own uses_context before calling get_value(). - An apply_block_bindings() resolver for the recursive Blade renderer, on the assumption nested blocks would miss bindings. Verified by stubbing it out that nested overrides still render correctly: render() merges bound values into $this->attributes in place and WP_Block_List caches instances, so the merge has already happened by the time our recursion reads them. Verified on test-site (WP 7.0): pattern editor controls, contentOnly/disabled modes, read and write paths (typed in-browser -- overrides land on the instance's content keyed by metadata.name, pattern original untouched), frontend after save including nested l-section > e-button and the tab nav in get_tabs_nav_data(), e-image swapping per instance, and 26/26 blocks valid with no new console errors via scripts/check-blocks-console.mjs. Documented caveat: WP keys bindings by top-level attribute name only, so e-button's single `button` object is overridden as a whole. An overridden instance keeps its own variant/size/icon and stops inheriting later design changes from the pattern -- confirmed empirically. Container blocks are overridden through their inner blocks; per-instance structure is not possible (core/block stores only ref + content, and instances serialize self-closing). Claude-Session: https://claude.ai/code/session_015gnVTZywLgQYkM6Epr2uW2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WordPress 7.0 opened Pattern Overrides to custom blocks. This opts the Webentor core blocks in, so a synced pattern can be reused across pages with per-instance content while the design keeps propagating from the original.
How it works
WP 7.0 collapsed the whole mechanism into one server-side filter,
block_bindings_supported_attributes(wp-includes/block-bindings.php:141). That single list drives:editor.js:49988patterns.js:320block-editor.js:7400— swaps in boundattributes, reroutessetAttributes→source.setValuesWP_Block::render()block-editor.js:9544So no JS changes were needed — core handles read/write generically for any block. And because Webentor blocks are dynamic (
save: () => null+ Blade), bound values simply arrive in$attributes; no HTML API selector work.Blocks opted in
e-buttonbuttone-accordiontitlee-tab-containertitlee-imageimgId,linke-svgimgIde-icon-pickericone-galleryimagesExtensible via the new
webentor/block_bindings_supported_attributesfilter.Also fixed
The block
render_callbackdiscarded its$attributesargument — the value WP guarantees carries resolved Block Bindings values for dynamic blocks — and re-read$block->attributesinstead.render_block_blade()now takes them as an optional third argument. No behavior change for blocks without bindings.Explored and deliberately not shipped
pattern/overridesusesContextfilter. Unnecessary —WP_Block::process_block_bindings()injects the source's ownuses_contextbefore callingget_value().apply_block_bindings()resolver for the recursive Blade renderer, on the assumption nested blocks would miss bindings. Verified by stubbing it out that nested overrides still render correctly:render()merges bound values into$this->attributesin place andWP_Block_Listcaches instances, so the merge has already happened by the time our recursion reads them. Removed ~50 lines duplicating a private core method.Caveats (documented)
button.titlesub-paths. Soe-button's singlebuttonobject is stored wholesale: once an instance overrides a button it keeps its ownvariant/size/iconand stops inheriting later design changes from the pattern. Confirmed empirically. Avoiding this would mean changing the attribute contract every consumer theme's Blade views and filters build on, so it was a deliberate call.e-accordion,e-tabs, …) are overridden through their inner blocks, not the container. Per-instance structure is impossible:core/blockstores onlyref+content, instances serialize self-closing, andReusableBlockEditwires inner blocks withonInput/onChange: NOOP.Verification (test-site, WP 7.0 + PHP 8.4)
contentOnly, everything else →disabled.contentkeyed bymetadata.name; pattern original and sibling instance untouched. Both scalar (e-accordion.title) and object (e-button.button) paths.l-section > e-buttonand the tab nav viaget_tabs_nav_data();e-image.imgIdswaps per instance.scripts/check-blocks-console.mjs: 26 blocks, 0 invalid, frontend 200, no new console errors (only pre-existing__next40pxDefaultSizewarnings, removal target WP 7.1 — separate item).pnpm check:versionsin sync;phpcsclean.Release
core0.15.6→0.15.7. Patch, so.webentor/project.jsoncoreVersionstays^0.15— no consumer constraint or codemod changes. Note this is a feature-level addition that semver would put at0.16.0; shipping as a patch means consumers on^0.15pick it up automatically. Safe, since it is additive and inert until someone enables overrides on a block.New docs page:
docs/src/guides/pattern-overrides.md, plus awebentor/block_bindings_supported_attributesentry in the PHP API reference.https://claude.ai/code/session_015gnVTZywLgQYkM6Epr2uW2