You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Feature request, filed to anchor the idea rather than to specify it — the design needs working through from several angles before anyone builds it.
The need
Sections that appear on every post of a type but are not part of any post's content: related articles, a CTA under an article, a newsletter box above the footer. Today these live in the Twig template, which means changing one is a code change and a deploy. Editors cannot touch them.
The concrete case that prompted this: three fixed patterns at the end of every article, editable in one place.
Why not just FSE
WordPress solves this natively with block templates — templates/single-post.html wrapping <!-- wp:post-content /--> with whatever surrounds it. That is the right idea and the wrong implementation for this stack.
A full block theme discards the Twig layer, the component system, and everything this package is.
A hybrid (add_theme_support( 'block-template-parts' ) + theme.json + parts/) is technically supported and is the dangerous option: it gives the site a template-part editor that competes with Twig for ownership of the layout. Two competing sources of truth about what a page looks like is worse than one imperfect source. It fails late — the editor UI works, someone edits a part, and the front end does not change because Twig owns that region.
What is worth taking from FSE is the principle, not the machinery: regions outside the post content are editable content, not code. That principle can be adopted with the tools this stack already has.
Sketch
A named slot registered alongside the other theme config, resolved to a pattern and rendered by the theme:
Slots declared by the consuming theme, in the manner of StarterBase::$options_pages — a name, the post types it applies to, and where it renders.
The value is an ACF post_object field restricted to post type wp_block, on an options page for the global default, optionally overridden per post.
core/block's own render callback handles a missing target, nested patterns, and recursion protection. Loading the wp_block post and calling do_blocks( $post->post_content ) directly bypasses all of that.
Exposed to Twig through the existing context so a template can place it: {{ slot('after_article') }} or similar.
Design questions to settle first
These are the reason this is a feature request and not a plan.
The three-state cascade. An empty per-post field is ambiguous: "inherit the global" or "show nothing here"? Two states cannot express three intents, and without an explicit answer there is no way to give one article no slot at all. Probably an explicit override toggle beside the picker, but it is a UX decision as much as a data one.
Cache invalidation. A pattern's content is not in any rendering post, so editing it changes no post's post_modified. Every page rendering that pattern must be purged when it is saved, and nothing does that by default — the symptom is an edit that appears not to have saved. portadesign-mcp exposes portadesign_mcp_cache_clearers for registering a clearer, so there is a place to hook; the harder part is knowing which pages render a given pattern, which argues for storing the reference somewhere queryable rather than only in an options row.
Scope of a slot. Per post type is the obvious granularity. Per taxonomy term, per language, or per template are all plausible extensions and each one multiplies the resolution logic. Worth deciding how far the first version goes and saying so.
Translation. The pattern is a post, so it translates as a post; a post_object reference remaps through wpml_object_id. Whether the slot assignment is per language or shared is a separate decision — an options field under ACFML can be either, and the two give quite different editorial workflows. This package already carries Acfml/ and Wpml/, so the machinery is at hand, but the intent needs choosing.
How much can editors break? The point of moving a region out of code is that editors can change it. The point of it being a fixed layout is that they cannot change it wrongly. Where that line sits — which patterns are selectable, whether arbitrary ones are — decides whether this is safer or less safe than the status quo.
Why post_object specifically
Worth recording because it is the one decision that is cheap now and expensive later. If the reference is a post_object field rather than a text or number field holding a raw id, it is a first-class reference to every tool that already understands ACF references — the portadesign-mcp connector remaps it for translations, finds it when it dangles, and can read and write it as an ordinary field. A raw id in a text field is an opaque number that none of that machinery can see.
Related
portadesign/portadesign-mcp#182 — exposing synced patterns through the MCP connector (promote a block to a pattern, insert one). Complementary: that issue is about the agent noticing repetition and proposing a pattern; this one is about placing a chosen pattern in a fixed region.
portadesign/portadesign-mcp#183 — template_lock being unenforced on the write path. Same underlying theme: page regions governed by a rule stored outside the content they affect.
Feature request, filed to anchor the idea rather than to specify it — the design needs working through from several angles before anyone builds it.
The need
Sections that appear on every post of a type but are not part of any post's content: related articles, a CTA under an article, a newsletter box above the footer. Today these live in the Twig template, which means changing one is a code change and a deploy. Editors cannot touch them.
The concrete case that prompted this: three fixed patterns at the end of every article, editable in one place.
Why not just FSE
WordPress solves this natively with block templates —
templates/single-post.htmlwrapping<!-- wp:post-content /-->with whatever surrounds it. That is the right idea and the wrong implementation for this stack.add_theme_support( 'block-template-parts' )+theme.json+parts/) is technically supported and is the dangerous option: it gives the site a template-part editor that competes with Twig for ownership of the layout. Two competing sources of truth about what a page looks like is worse than one imperfect source. It fails late — the editor UI works, someone edits a part, and the front end does not change because Twig owns that region.What is worth taking from FSE is the principle, not the machinery: regions outside the post content are editable content, not code. That principle can be adopted with the tools this stack already has.
Sketch
A named slot registered alongside the other theme config, resolved to a pattern and rendered by the theme:
StarterBase::$options_pages— a name, the post types it applies to, and where it renders.post_objectfield restricted to post typewp_block, on an options page for the global default, optionally overridden per post.core/block's own render callback handles a missing target, nested patterns, and recursion protection. Loading thewp_blockpost and callingdo_blocks( $post->post_content )directly bypasses all of that.{{ slot('after_article') }}or similar.Design questions to settle first
These are the reason this is a feature request and not a plan.
The three-state cascade. An empty per-post field is ambiguous: "inherit the global" or "show nothing here"? Two states cannot express three intents, and without an explicit answer there is no way to give one article no slot at all. Probably an explicit override toggle beside the picker, but it is a UX decision as much as a data one.
Cache invalidation. A pattern's content is not in any rendering post, so editing it changes no post's
post_modified. Every page rendering that pattern must be purged when it is saved, and nothing does that by default — the symptom is an edit that appears not to have saved.portadesign-mcpexposesportadesign_mcp_cache_clearersfor registering a clearer, so there is a place to hook; the harder part is knowing which pages render a given pattern, which argues for storing the reference somewhere queryable rather than only in an options row.Scope of a slot. Per post type is the obvious granularity. Per taxonomy term, per language, or per template are all plausible extensions and each one multiplies the resolution logic. Worth deciding how far the first version goes and saying so.
Translation. The pattern is a post, so it translates as a post; a
post_objectreference remaps throughwpml_object_id. Whether the slot assignment is per language or shared is a separate decision — an options field under ACFML can be either, and the two give quite different editorial workflows. This package already carriesAcfml/andWpml/, so the machinery is at hand, but the intent needs choosing.How much can editors break? The point of moving a region out of code is that editors can change it. The point of it being a fixed layout is that they cannot change it wrongly. Where that line sits — which patterns are selectable, whether arbitrary ones are — decides whether this is safer or less safe than the status quo.
Why
post_objectspecificallyWorth recording because it is the one decision that is cheap now and expensive later. If the reference is a
post_objectfield rather than a text or number field holding a raw id, it is a first-class reference to every tool that already understands ACF references — theportadesign-mcpconnector remaps it for translations, finds it when it dangles, and can read and write it as an ordinary field. A raw id in a text field is an opaque number that none of that machinery can see.Related
portadesign/portadesign-mcp#182— exposing synced patterns through the MCP connector (promote a block to a pattern, insert one). Complementary: that issue is about the agent noticing repetition and proposing a pattern; this one is about placing a chosen pattern in a fixed region.portadesign/portadesign-mcp#183—template_lockbeing unenforced on the write path. Same underlying theme: page regions governed by a rule stored outside the content they affect.