Overview
In #3500390: The pending changes API endpoint should list individual regions for global template changes we want content editors seeing each changed region as its own item in the Review N changes panel.
I opened #3501542: Allow a wse_config entity to represent a config partial rather than a complete config entity because when we integrate Workspaces, I think we'll want content editors being able to work on one region in one workspace and a different region in a different workspace.
Should we therefore split page_template into per-region config entities?
Proposed resolution
Decide whether per-region config entities makes sense or if leaving it as a single page_template makes more sense.
Pros of splitting
- #3500390: The pending changes API endpoint should list individual regions for global template changes becomes easier.
- We avoid having to do #3501542: Allow a wse_config entity to represent a config partial rather than a complete config entity.
Possible cons of splitting
- Does it worsen DX of config deployments (e.g., doing a manual code review across per-region YAML files vs within a single YAML file)?
- After XB 1.0, we'll want to add the concept of page template variants. E.g., for nodes of a given type (or any other condition, such as for certain Views, etc.), use a different page layout (similar to the concept of theme hook suggestions for the
pagetemplate). Would this be more cumbersome to manage if the page layout is split across per-region entities? Or on the other hand, would it add useful capabilities like creating variants for some regions while leaving other regions shared across page variants?
User interface changes

| Comment | File | Size | Author |
|---|---|---|---|
| #23 | Screenshot 2025-02-18 at 12.52.05 PM.png | 220.01 KB | wim leers |
Issue fork experience_builder-3501600
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
effulgentsia commentedI think the initial idea for a single
page_templatewas when we envisioned it as replacingpage.html.twigentirely. Meaning, you wouldn't have the concept of theme-determined regions within XB, just a single canvas that you can lay out however you want. But since the UX evolved into being based around theme-determined regions, I think that's a fairly strong argument in favor of refactoring the config entity to match.Comment #3
lauriiiMy gut feeling is that this isn't significantly worsened at least in the case of a single page template. The impact would be more in the case of multiple page templates. It seems like a trade-off that could be accepted.
This could actually be a benefit because for example the header and footer might remain the same on every page template but the content top might need to change for some pages.
I'm wondering if based on this there should be a page template config which can specify a parent page template and is allowed to depend on specific region configurations that would override the parent?
Comment #4
wim leers🤯 I didn't see this coming for sure. #2 is accurate — that's how @lauriii always described it.
I definitely agree with the cons, especially the variants one. Although @lauriii makes a strong observation in #3.
I'll think about this some more. I urgently need to review some things, leaving not enough time to think through all consequences.
AFAICT this would make #3495598: [PP-1] Don't store page template model data in auto-save for an entity obsolete too, and hence we could add it to the "avoid" list?
Comment #5
longwaveI don't think this makes #3495598: [PP-1] Don't store page template model data in auto-save for an entity irrelevant, we still store the entire model against all autosaved entities - the aim of that issue is only store the parts of the model that are relevant to each entity.
Comment #6
wim leersYou're right, I misread & misunderstood!
Comment #7
wim leersRemember: the future
GlobalPageTemplateconfig entity 👻#3478537: Introduce an XB `PageTemplate` config entity introduced the
PageTemplateconfig entity (config schema type:type: experience_builder.page_template.*:). It comes with this comment:That "otherwise" refers to the preceding config schema type: a placeholder for a future piece of functionality that is very closely related: the global page template config entity.
That looks like so:
How would you imagine that to work in the new world proposed by this issue? 🤔 AFAICT, that'd remain unchanged, because it completely ignores the "default/active theme"'s regions.
(Sadly, I can't find any "global page template" details: it's based on discussing this with @laurii IIRC, and is about the "global template" vs the "page template" as captured by https://docs.google.com/spreadsheets/d/1OpETAzprh6DWjpTsZG55LWgldWV_D8jNe9AM73jNaZo/edit?gid=1721130122#gid=1721130122&range=I29">requirements 18 vs 19.)
+1 if we're on the same page
If y'all agree that splitting
PageTemplateinto NPageRegionconfig entities does still leave theGlobalPageTemplateconfig entity unchanged … then I'm +1 to this proposal, and I do think that it'll make things simpler 😊Bonus! 🚀
In fact, a nice consequence will be that if you try to uninstall a module that provides some SDC or Block, you'd get a more precise overview in the "oops, can't do that, because these config entities depend on it" UI: it'd tell you exactly which regions it's being used in, and in the future even which variants! 🥳
Comment #8
wim leersTo add to #7: that'd also mean that the
contentregion would either:PageRegioncontent entity, because that region is hardcoded (in code) to contain the "main content" blockRelated: #3502372: Hide main page content block from XB
Comment #9
wim leersGiven @lauriii specifically opened #3502372, requesting him to approve #7 + #8.
Comment #10
effulgentsia commented+1 to doing what the issue title says: changing 1
PageTemplateconfig entity per theme into NPageRegionconfig entities per theme.I'm confused about what concept
GlobalPageTemplaterepresents. If it's meant to be an override ofpage.html.twig, I think it should be renamed toPageTemplate(which can be a followup once this issue makes that name available). We'd need to come up with a UI (possibly after 1.0) for how to create/edit this entity. But within this UI, we could make aRegioncomponent available. Then this would be an exact replacement for page.html.twig (as well as theregionssection of THEME.info.yml). I.e., someone could use this to build a new theme from scratch, including using only the XB UI to create, name, and place regions. But then what's inside each region is controlled by thePageRegionentities.Comment #11
effulgentsia commentedComment #12
effulgentsia commentedComment #13
wim leersI think that entire comment captures much more clearly than ever before what @lauriii intended all along! 😄
But it's thanks to the
PageTemplateconfig entity per theme containing data for every region → NPageRegionconfig entities per theme, each containing data for 1 regionGlobalPageTemplate→ 1PageTemplaterename that you were able to describe it so clearly! 🤩 👏👏
I'd like @lauriii to explicitly confirm to make sure this matches what he envisioned 😊
P.S.: happy to do this one, I think I'm well-positioned to do this system-wide refactor. 🤓
Comment #14
lauriii#10 and #13 seems like a really solid plan for this. Thank you @effulgentsia and @wim leers 👏
My original thinking last spring was that we would have a single config entity which would store the "page template" meaning the regions available and "block placement" meaning what's inside those regions. We could implement this in phases so that defining the regions is optional and would rely on the theme (to allow integration with existing themes). We've learned since then that this didn't consider all of the factors yet and therefore it was insufficient. I'm +1 to splitting the individual component trees for regions to separate config entities
In my head, global page template is the idea that there would be one template which is the default template (page.html.twig). You could then specify overrides of that for specific parts of the site, e.g. specific content type (page--node--article.html.twig). The latter would be just a regular page template because it's only applied to a specific section of the site. Once we allow multiple page template, it might be clearer to call the global page template the default template at least in code.
Comment #15
wim leersI find the last paragraph of #14 quite confusing, but all of that is out of scope here anyway, so let's save that discussion for later, when we actually work on it.
It doesn't need to be me who implements this, so unassigning.
Comment #16
f.mazeikis commentedComment #17
wim leersAdding to #8: #3505872: Page title block should not be required landed too, so the "validation across the component trees for all regions in a given theme" just became simpler.
To recap, there are 3 special kinds of blocks: "main content", "page title" and "messages".
contentregion.(This also came up at #3502371-5: Make "Page title block" work A) also outside regions, B) on the only routes XB currently supports: content entity routes and #3502371-6: Make "Page title block" work A) also outside regions, B) on the only routes XB currently supports: content entity routes.)
\Drupal\experience_builder\Plugin\DisplayVariant\PageTemplateDisplayVariantdidn't encounter >=1 such block during rendering, then XB's page variant should just place it at the top of thecontentregion automatically, which is exactly whatBlockPageVariantdoes:If @lauriii agrees with that, then we'll have eliminated all of the validation challenges in this MR! It'll allow this MR to delete
\Drupal\experience_builder\Plugin\Validation\Constraint\ComponentTreeMeetsRequirementsConstraint::$nestedand related code.Comment #18
lauriiiAgreed that it would be great to place take care of placing the message. I like the proposal to place the message as a fallback on top of the content region. 👍
Comment #20
wim leersFYI: this blocks #3502769, see #3502769-4: Auto-saved PageRegions may be invalid, but MUST NOT cause XB's previews to fail..
Comment #21
longwaveMoved this along a bit further, fixed all phpcs/phpstan issues and fixed some of the tests. More tests to fix and Wim's review points to address still.
Comment #22
wim leersBoth @longwave and @f.mazeikis are out today, I'll finish this.
Comment #23
wim leersThis is now down to a single last failure that's tricky to debug.
Critical bugs found:
Interesting non-critical bugs found:
Now the word "template" in the XB codebase never refers to
PageTemplateanymore.Out-of-scope
Comment #24
wim leersglobal-regions.cy.jsis green locally.Comment #25
wim leersI've got it! 🥳 First green
block-form.cy.jsCI run.Wow, what a nightmare this was to debug — treating client-side data as unvalidated blobs that must be respected sure results in mind-bending debugging, because the bug/mistake can happen much earlier than the failing test! 😳🧟♀️
Comment #27
wim leersWhew, it's finally in!
Didn't want to drag this >1000 LoC heisenbug-esque monster forward any longer. And didn't want to subject anybody to the painful review, although both @longwave and @larowlan already did. And, of course, I reviewed @f.mazeikis' original MR.
99% of the pain was in the auto-saving parts (see #25 for why — and OpenAPI doesn't help here at all because the client is supposed to be able to send arbitrary blobs!). The test failures when I started working on this were misleading/largely irrelevant, because the foundations were not yet working (see #23, "critical bugs").
The goal is always to first make the config entity iron-clad and thoroughly validated. Then build upon it. (And in this particular case, debugging was surprisingly painful.)
As the screenshot in #23 shows, this just made #3502902: Only auto-save content entities/PageRegion config entities when there are actual changes: simply previewing incorrectly causes them to appear in "Review x changes" more important.
Quoting from #17:
Extracted that into a simple follow-up: #3507549: Remove unused ComponentTreeMeetsRequirementsConstraint::$nested.
More follow-ups tomorrow.
Comment #28
wim leersComment #29
larowlanAfter updating to 0.x and reinstalling seeing #3507631: Page mangled and warning from block components when enabling for global template
Comment #30
wim leersAll out-of-scope follow-ups, as promised in #27, for things I ran into while working on this MR:
Comment #31
nagwani commented