Problem/Motivation

One of the product requirements is 7. Content type templates:

As a builder, I want to create and modify content type templates for how content of a specific content type will be displayed. I want to be able to create multiple templates for a given content type (view mode). Within the template, I want to add components that may or may not map to fields in the content type.

This is too high-level to implement.

Additional context exists in @lauriii's write-up at #3452440: Page Builder Research 2024, specifically:

Layout Builder

  • Users are often using Layout Builder either for defining the display template for structured content, or for page building. It doesn't work as well for hybrid content because a) overrides apply to the whole display template b) there is no way to centrally update pages. Therefore, some users resort to using Layout Builder for managing the display template and Paragraphs for page building.

(Emphasis mine.)

In other words: Experience Builder (XB) must be more flexible/granular than Layout Builder (LB).

We've gone ahead in the 0.x branch with @effulgentsia's #3440578: [PP-2] JSON-based data storage proposal for component-based page building "JSON storage with tree and props stored separately" approach, which definitely allows for the above, but there's many aspects undefined.

Let's define them.

Critical context: @lauriii's video on this subject: https://www.youtube.com/watch?v=l0LWqoqFmBY — see #19.

Steps to reproduce

N/A

Proposed resolution

Clarify the precise interpretation of this requirement and capture it as a architecture decision record (#3454669: Record Architecture Decisions — to scale to many people + many timezones), because it deeply impacts both technical architecture and UX.

In the discussions we had about that requirement, plus subsequent discussions, this is what I understand to be the more precise interpretation of that user story:

  1. the first content type template ("default layout") for a bundle MUST be for the default view mode
  2. there MAY be one content type template per view mode (default/full/teaser/search/…)
  3. any change to a content type template MUST propagate to all entities of that content type (entity bundle)
  4. the UX for defining a content type template MUST have affordances to indicate to the Site Builder persona: A) which parts will be editable by the Content Creator persona (i.e. "unlocked"), B) that this is a template, not a concrete entity, C) which fields in the content type (i.e. FieldConfigs) do not yet have a representation in the content type template
    • 👆 For A): in a content type template, it's possible to mark slots as "unlocked", meaning the Content Creator can add additional components to it (later also with restrictions, see 17. Restrict nested components)
    • 👆 For A): in a content type template, it's possible to mark component subtrees as "unlocked", meaning the Content Creator can change that component subtree (later also with restrictions, see 17. Restrict nested components)
  5. when creating content entities of that content type (entity bundle), the Content Creator sees:
    • the element/component library appears in the left sidebar — if there's >=1 unlocked slot/component subtree
    • the static prop values in the right sidebar, to edit them — if a placed component is selected on the canvas with >=1 unlocked static prop
    • the dynamic prop values in the right sidebar (aka the content type's FieldConfig fields)

Data model diagram in HEAD 🆚 the above
(The exact UX is out of scope here — this is only capturing what must be possible to do/not do, restrict/not restrict, inherit/override, etc.)

Creative freedom 🆚 design consistency

Consequence/purpose: the ability to lock/unlock slots and component subtrees allows the Site Builder to define the creative freedom of the Content Creator on a per-content type basis, which is another way of saying: controlling how rigid/consistent/enforced the layouts are.

Remaining tasks

Discuss the above, and answer the open questions below:

Open questions

  1. @lauriii indicated in that discussion that creating a content type template should not be a required step. How is that possible? Does that mean starting out with an full-creative-freedom canvas?
  2. When there's multiple entity view displays (i.e. for multiple view modes) that use XB (so not just XB for default and no XB for teaser), how do per-entity overrides or additions work? Because an unlocked slot may not exist in all entity view displays, nor may an unlocked component subtree.

Related: @catch in #3440578-57: [PP-2] JSON-based data storage proposal for component-based page building and other comments in that issue.

Issues

🚧Work in progress. 🚧 This is following the example set in #3499919: [Meta] Plan for in-browser code components.

Each lane can happen in parallel, within a lane, much work is sequential. Details TBD.

Lane 1: ContentTypeTemplate config entity infrastructure
🚧 List very incomplete; work in progress!
  1. #3511366: [META] Introduce a `ContentTypeTemplate` config entity + related infrastructure
  2. Make ComponentTreeItem respect the relevant ContentTypeTemplate during saving
  3. Make ComponentTreeItem respect the relevant ContentTypeTemplate during rendering
  4. #3452848: [PP-1] Test coverage to prove configurable fields cannot be deleted from content entity types if they are used in XB Content Type Template
  5. Internal HTTP API support: implement XbHttpApiEligibleConfigEntityInterface, add XbConfigEntityHttpApiTest::testContentTypeTemplate()
  6. Auto-save support
Lane 2: SDC/code component shape matching for all core field types
⚠️ This is actually an assumption for this epic/meta/plan/capability, but the XB codebase has not yet reached this point. So this being listed here is for pragmatism/realism reasons.
🚧 List very incomplete; work in progress!
  1. #3512433: Provide visibility into which (core) field types (74%), field type props (63%) can be mapped into Content Type Templates vs not, and which field widgets (36%) are supported
  2. #3467870: Support `{type: array, …}` prop shapes
  3. #3456008: [later phase] Support matching enum SDC prop shapes against DynamicPropSources, not only generating StaticPropSources
Lane 3: Redux integration for all core field widgets
⚠️ This is actually an assumption for this epic/meta/plan/capability, but the XB codebase has not yet reached this point. So this being listed here is for pragmatism/realism reasons.
🚧 List very incomplete; work in progress!
  1. #3463842: [META] Redux sync on ALL prop types, not just ones with a single [value] property
Lane 4: UI for creating/editing the ContentTypeTemplate config entity
🛑 blocked on design
🛑 blocked on ContentTypeTemplate HTTP API support
Lane 5: UI for creating/editing a content entity that uses a ContentTypeTemplate config entity
🛑 blocked on design
🛑 blocked on Make ComponentTreeItem respect the relevant ContentTypeTemplate during saving
🛑 blocked on Make ComponentTreeItem respect the relevant ContentTypeTemplate during rendering
Command icon 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

Wim Leers created an issue. See original summary.

wim leers’s picture

Title: [META] 7. Content type templates — aka "default layouts" — clarify the tree+props data model » [META] 7. Content type templates — aka "default layouts" — affects the tree+props data model

One possible implementation

Here's a possible implementation:

enum CreativeFreedom {
  case Locked; // SB allows CC to change nothing.
  case LockedTreeUnlockedStaticProps; // SB allows CC to change nothing about layout, nor prop sources, but does allow changing the StaticPropSources' values.
  case LockedTreeUnlockedProps; // SB allows CC to change nothing about layout, but does allow changing prop sources, but does allow changing the StaticPropSources' values.
  case Unlocked; // SB allows CC to change anything.
}

👆 I'm not saying I think this is a good idea. This is more on the extreme end of granularity of control.

The freedom available to the Content Creator (CC) persona when creating an article node will then depend on the freedom configured by the Site Builder (SB) persona:

  1. Least CC freedom: SB defines the component tree for all article nodes, with all component props being sourced from "dynamic" prop sources (i.e. fields on the host entity type). Zero overrides allowed for individual article nodes: not for component tree nor for props values.

    Result: all articles look exactly the same but with different values; CCs can only specify values for fields on article nodes (title/body field/image field/tags field), they are not even allowed to override component props values statically assigned at the article node type level.

    (IOW: the tree XB field property is empty for all article nodes, as is the props XB field property, because literally everything is defined at the article content type level — similar to Drupal core's existing EntityViewDisplay functionality.)

    XB field configuration for article nodes using CreativeFreedom::Locked:

    tree: [{"uuid":"something7d","type":"provider:sdc-name"}, …]
    props: {"something7d":{"image":{"sourceType":"dynamic","expression":"ℹ︎␜entity:node:article␝field_image␞0␟value"},"text":{"sourceType":"static:field_item:string","value":"Hello, world!","expression":"ℹ︎string␟value"}}, …}
    creative_freedom:
      tree: NONE
      props: NONE
    

    XB field values for article 42:

    tree: null
    props: null
    
  2. Little CC freedom: SB defines the component tree for all article nodes, no overrides allowed for individual article nodes. Result: all articles look exactly the same but with different values; CCs can only specify static props values, with even restrictions on those. (IOW: tree XB field property is empty for all article nodes, props XB field property is maybe non-empty.)

    XB field configuration for article nodes using CreativeFreedom::LockedTreeUnlockedStaticProps:

    tree: [{"uuid":"something7d","type":"provider:sdc-name"}, …]
    props: {"something7d":{"image":{"sourceType":"dynamic","expression":"ℹ︎␜entity:node:article␝field_image␞0␟value"},"text":{"sourceType":"static:field_item:string","value":"Hello, world!","expression":"ℹ︎string␟value"}}, …}
    creative_freedom:
      tree: NONE
      props: STATIC-ONLY
    

    XB field values for article 42:

    tree: null
    props: {"something7d":{"text":{"sourceType":"static:field_item:string","value":"Hello, world!","expression":"ℹ︎string␟value"}}, …}
    
  3. Zero layout freedom, full content freedomStaticPropSources — they can even change the default prop source from StaticPropSource to DynamicPropSource.

    XB field configuration for article nodes using CreativeFreedom::LockedTreeUnlockedProps:

    tree: [{"uuid":"something7d","type":"provider:sdc-name"}, …]
    props: {"something7d":{"image":{"sourceType":"dynamic","expression":"ℹ︎␜entity:node:article␝field_image␞0␟value"},"text":{"sourceType":"static:field_item:string","value":"Hello, world!","expression":"ℹ︎string␟value"}}, …}
    creative_freedom:
      tree: NONE
      props: FULL
    

    XB field values for article 42:

    tree: null
    props: {"something7d":{"text":{"sourceType":"dynamic""expression":"ℹ︎␜entity:node:article␝title␞␟value}}, …}
    
  4. Some CC freedom: SB defines the component tree for all article nodes, and designates which subtrees can be modified by CCs (this could be only slots). Result: all articles look largely the same; CCs have some layout choices.

    XB field configuration for article nodes using CreativeFreedom::LockedTreeUnlockedStaticProps:

    tree: [{"uuid":"something7d","type":"provider:sdc-name"}, …]
    props: {"something7d":{"image":{"sourceType":"dynamic","expression":"ℹ︎␜entity:node:article␝field_image␞0␟value"},"text":{"sourceType":"static:field_item:string","value":"Hello, world!","expression":"ℹ︎string␟value"}}, …}
    creative_freedom:
      tree: FULL
      props: FULL # implied
    

    XB field values for article 42:

    tree: [{"uuid":"SOMETHING-ELSE","type":"provider:sdc-name"}, …]
    props: {"SOMETHING-ELSE": …}
    
  5. Most CC freedom: SB defines no component tree for all article nodes, and allows everything to be modified by CCs.

    XB field configuration for article nodes:

    tree: []
    props: {}
    creative_freedom:
      tree: FULL # implied
      props: FULL # implied
    

… and it's possible to think of in-between states too.

Wim Leers credited lauriii.

wim leers’s picture

Issue summary: View changes
Related issues: +#3452440: Page Builder Research 2024

Wim Leers credited bnjmnm.

Wim Leers credited tedbow.

wim leers’s picture

Crediting the people that helped craft the bulleted list above ~2 months ago.

wim leers’s picture

Note: the current implementation reality for "content type templates" is captured in the current "data model" diagram — the DefaultTree in represents how it works in today's PoC in the 0.x branch: https://git.drupalcode.org/project/experience_builder/-/blob/0338812d1d7...

👉 there's zero integration yet with EntityViewDisplay: there's only a default value on the XB field for a bundle, and that just happens to be the sole default layout/content type template: no such thing as a content type template per view mode yet.

IOW: this issue blocks #3444424: [META] Configuration management: define needed config entity types, because we need to get more clarity first on how to support per-view mode content type templates. Until there is clarity here, XB will stick to a single default layout/content type template, rather than one per view mode.

wim leers’s picture

Created MR to provide an updated diagram that matches the current issue summary's interpretation of the product requirements.

The outcomes of this issue must be captured both in the diagram and in an ADR.

wim leers’s picture

Title: [META] 7. Content type templates — aka "default layouts" — affects the tree+props data model » [later phase] [META] 7. Content type templates — aka "default layouts" — affects the tree+props data model

Last but not least: conveying in the issue title that this is NOT something we're IMPLEMENTING during this phase of development, per #3454094: Milestone 0.1.0: Experience Builder Demo.

Not marking Postponed because while we're not implementing it, we should be discussing/refining it to reach a conclusion! 🤓

wim leers’s picture

Issue summary: View changes
acbramley’s picture

This is great, thank you so much Wim. I've read through all notes so far and it's cleared up quite a few questions I had.

On the note of CC freedom, I think one thing that would be ideal (and I'm pretty sure is covered but there is a bit of nuance) is having the ability to be able to configure the amount of freedom per region per layout per bundle. As in at level in bold, as a site builder, I want to be able to configure the "freedom" of the CC.

This is essentially what Layout builder restrictions (and lock I believe) modules allow you to do. I know those layers are named differently I'm XB but I believe there's a similar concept (although XB allows more nesting).

Ideally, also, let's try and make the UI for configuring this good for the site builder 😅

catch’s picture

For A): in a content type template, it's possible to mark slots as "unlocked", meaning the Content Creator can add additional components to it (later also with restrictions, see 17. Restrict nested components)

I think I understand this - say an article with author, submitted, main image, standfirst, at the top, but then arbitrary amounts of text and/or images and/or sidebars underneath, and then maybe with a templated related articles + social sharing block at the bottom too.

👆 For A): in a content type template, it's possible to mark component subtrees as "unlocked", meaning the Content Creator can change that component subtree (later also with restrictions, see 17. Restrict nested components)

But I don't understand what this is at all. Is it possible to add a concrete use case?

C) which fields in the content type (i.e. FieldConfigs) do not yet have a representation in the

Assuming we do #3365551: Add the notion of a 'configured layout builder block' to solve a number of content-editor and performance pain points (and then whatever the SDC version of that might end up being), this could happen when you select which field is used in a field block (or which prop after selecting a component), so we don't have a list of possibly useless fields like revision log messages in the sidebar.

the static prop values in the right sidebar, to edit them — if a placed component is selected on the canvas with >=1 unlocked static prop

Why is this necessary vs. a default value for a field (or a value to use when the field is empty)? I can see a use-case for non-editable arbitrary content in a bundle layout, views blocks for example, but also maybe a heading or something. However that would never, ever make it into entity content - it would appear only in the bundle config. Once something becomes editable, how is it providing anything genuinely different from what you can (or potentially could) do with a field value?

@lauriii indicated in that discussion that creating a content type template should not be a required step. How is that possible? Does that mean starting out with an full-creative-freedom canvas?

If components are defined by bundle, then I could see it being a blank sheet template where everything is done per-entity - i.e. a 100% override all the time. But this would mean that content editing would have to be done in layout builder/XB - if you only filled out field values (UI or API), nothing would show up at all then. I think this is a valid use case for a 'landing page' bundle where the overall structure is completely arbitrary even if common components are used within that.

lauriii’s picture

Assigned: lauriii » Unassigned

I recorded a video with my thinking around this, approaching it from a slightly different angle: https://www.youtube.com/watch?v=l0LWqoqFmBY. I'm walking through two diagrams on that video; one for data sources + design system and one for breaking down a content type.

On the note of CC freedom, I think one thing that would be ideal (and I'm pretty sure is covered but there is a bit of nuance) is having the ability to be able to configure the amount of freedom per region per layout per bundle. As in at level in bold, as a site builder, I want to be able to configure the "freedom" of the CC.

If I understand this correctly, instead of configuring which components are available for a bundle, you'd like to configure slot restrictions for a specific component within a specific bundle. Do you have specific example scenarios where this is needed that you could walk us through?

Edit: I realized I had forgotten the JSON data source from the first diagram. It has been added to the diagram but it's missing from the video.

wim leers’s picture

Issue summary: View changes

#17:

per region per layout per bundle

Interesting!

per bundle
✅ In everything I wrote above, the "content type template" is the default layout for 1 bundle
per region
🤔 AFAICT this maps to the slots I wrote above. See @lauriii's video in #19, that'll probably help you confirm.
per layout
🤔 What does this mean? The per-view mode default layout?

Ideally, also, let's try and make the UI for configuring this good for the site builder 😅

💯 — without that, XB falls apart!


#18:

But I don't understand what this is at all. Is it possible to add a concrete use case?

Essentially this is a more complex variant of unlocked slots (which you mentioned above). I'm not at all certain it is a good idea! It was discussed at some point (maybe even just at DrupalCon — I do not recall). It kind of falls under the I'm not saying I think this is a good idea. This is more on the extreme end of granularity of control. caveat I wrote in #2.

I personally suspect this would make the Content Creator UX too complex.

Concrete use case: take your article with author, submitted, main image, standfirst, at the top, example. Let's assume that they've got this default layout:

{
  "<root>": [
    {uuid: <uuid1>, component: "provider:two-col"},
    {uuid: <uuid3-standfirst>, component: "provider:marquee"},
  ]
  "<uuid1>": {
    firstColumn: [
      {uuid: <uuid4-author>, component: "provider:person-card"},
      {uuid: <uuid2-submitted>, component: "provider:elegant-date"}
    ],
    secondColumn: [
      {uuid: <uuid5-main-image>, component: "provider:image-hero"}
    ],
  }
}

IOW: a two-col at the top, with a marquee containing the standfirst below. The two-col contains author + submitted in the first column, the main image in the second column.

What "unlocked subtrees" is referring to is that you would be able to mark e.g. the subtree below <uuid1> as unlocked, which would allow you to change that component as well as everything inside it.

[…[ so we don't have a list of possibly useless fields like revision log messages in the sidebar.

💯
(Also fixed an incomplete sentence in the issue summary!)

Why is this necessary vs. a default value for a field (or a value to use when the field is empty)? […] However that would never, ever make it into entity content - it would appear only in the bundle config.

Ah, that's where @lauriii's product vision deviates from your assumptions then I think. It's expressly the intent to allow additional unstructured content to be created by the Content Creator per content entity if the creative freedom granted by the Site Builder allows for that. @lauriii's video in #19 should clarify that.

Once something becomes editable, how is it providing anything genuinely different from what you can (or potentially could) do with a field value?

I'm not sure I fully understand this question 🤔 But I think you're asking: "if it is edited like a field and kinda stored like a field … why not make it an actual field?" — is that right?

Assuming that is right: it is an actual field, just one that is not part of the data model, because given 1000 article nodes, in the slot where the Content Creator has the necessary creative freedom, they would be able to place any component, any number of components, and so it would not make sense to pollute the data model with optional fields for all of these.

catch’s picture

I just watched the video in #19 and have two main questions. Most of the locked vs. slots stuff makes loads of sense to me. Not sure I understood the 'default value for a slot' idea before but do now!

I'm not sure I know what the advanced use cases are that this doesn't cover yet, might be good to explicitly list what those are at some point so the constraints are clear.

The two things I didn't get:

1. Maybe it's implicit, but I didn't see a mention of components in templates that are locked but may not have a value. e.g. in the example the image field could be optional, but if it's populated, then the image always gets rendered in the same place. The 'image in slot' concept would allow you to remove the image from there but still add a field value which is either not used, or used in a component added in a slot elsewhere. But this is different from the image always being in the same place, but maybe not having a value. Optional fields are already supported in layout builder and view mode config. Would be good to clarify that's not going away.

2. I'm afraid I still don't see the reasoning for 'static props in entity content' in that video, the various paragraph data, accordion etc. could still be stored as multi-value fields on the entity.

wim leers’s picture

#21.1: +1 — optional fields are not going to go away. But I completely agree that "required vs optional" is something that is absent from the video. IMHO that's tied to 41. Conditional display of components in the requirements — I think that if an optional field (e.g. the image field on article nodes in the Standard install profile) has its value presented by a component, that that component should automatically get a conditional display configured ("only display if this field has a value") and should get a corresponding affordance in the UI.
I think @lauriii didn't touch on that in the video to keep it focused.

#21.2: Hm … I was hoping that the video starting at https://youtu.be/l0LWqoqFmBY?si=6dKplDCnX340mnuK&t=422 would clarify this sufficiently, especially combined with the last paragraph of my comment in #20.
If the combination of the video + that paragraph doesn't connect the dots sufficiently, then maybe it'd make sense for you, @lauriii and maybe @effulgentsia to meet — and maybe an additional video after that meeting, depending on the outcome?

catch’s picture

#21.2: Hm … I was hoping that the video starting at https://youtu.be/l0LWqoqFmBY?si=6dKplDCnX340mnuK&t=422 would clarify this sufficiently, especially combined with the last paragraph of my comment in #20.
If the combination of the video + that paragraph doesn't connect the dots sufficiently

I think I understand why people think it's necessary, but also I think I disagree with it for specific reasons, but I'm not sure I've clarified what those objections are enough (or that it's been lost in the barrage of issues + comments).

so it would not make sense to pollute the data model with optional fields for all of these.

possibly sums up the disagreement.

Let's take an example building on the university degree course content type from the video.

The university site builder adds a 'Testimonial' component, this has:

student image
student name
student testimonial

Something like: "Michelle ~ This course gave me a great foundation in computer science and I found a job a month after I received my degree".

This is not included in the view mode template config at all, it's just one of the options for content editors to use in slots, designed to be interspersed with other elements to break things up.

At first, this is only intended to be used in the optional slots on the default view mode, but later on, they decide that the listings pages (the teaser/card view in the video) should show a testimonial too.

If that testimonial component is backed from field data from the beginning, then the site builder can immediately configure the 'teaser/card' view mode XB template (or just regular manage display) and add the first (or random potentially) delta of testimonials in. It's all ready to go, the site builder never had to make an up front decision based on what may or may not become a requirement later, or learn the difference between field backed and static components before they could start building their site successfully.

If it's using 'static props', then it will only exist in the XB field data for the default view mode, and be inaccessible when configuring other view modes.

They're then left with (at least) three (bad to very bad) options:

1. Add another testimonial component, this time field backed, to the content type, and manually or via an update hook, migrate the content from static props to fields.

2. Some horrible hack where they try to parse out the testimonial from the default view mode xb field content to use on the teaser.

3. Add a slot to the teaser/card view mode, that allows a testimonial to be added, and duplicate the data manually between the two view modes.

catch’s picture

Two more questions based on the video in #19:

In the video, there's a component in a slot which uses an entity reference. Is this:

a. An entity reference + view mode selection - with the specific layout/component coming from the view mode.

b. An entity reference which is then manually mapped to props on a component selected by the content editor?

And regardless of the answer to a. or b., is the intention to support both?

---
With default components in templates (the image in a slot), is the default value always stored with the entity? i.e. if the default was changed from an image to video later, I am assuming that all the existing content that did not customize the slot would still have the image, because it's a default value which then gets saved when the entity is saved. Not sure that's 100% correct interpretation though.

lauriii’s picture

In the video, there's a component in a slot which uses an entity reference. Is this:

1. An entity reference + view mode selection - with the specific layout/component coming from the view mode.

2. An entity reference which is then manually mapped to props on a component selected by the content editor?

And regardless of the answer to #1 or #2, is the intention to support both?

The example of content composition I showed, I'd imagine falling under #1. However, we're aiming XB to support both of these.

With default components in templates (the image in a slot), is the default value always stored with the entity? i.e. if the default was changed from an image to video later, I am assuming that all the existing content that did not customize the slot would still have the image, because it's a default value which then gets saved when the entity is saved. Not sure that's 100% correct interpretation though.

The default value is stored with the entity, so if the default was changed later, it would remain intact on existing content.

acbramley’s picture

What does this mean? The per-view mode default layout?

I mean layout plugins, usually defined in our theme (or modules) foo.layouts.yml

Do you have specific example scenarios where this is needed that you could walk us through?

Definitely, we use Layout Builder Restrictions on basically every project that uses LB - it's essentially a mandatory module IMO if you're allowing layout overrides.

One way we use it is something like this:

Say we have 2 bundles - Basic Page (BP) and Landing Page (LP).

We have 3 Layouts defined in our theme - Sidebar , Cards, and Edge.
Sidebar is an 80/20 split layout with regions "main" and "aside"

Cards is a variable layout that allows some full width content with a variable number of columns of "cards" underneath (see Lee's blog post for more info on this) with regions "intro" and "cards"

Edge is a full bleed layout that expands across the whole page with only 1 region "main"

With LB Restrictions I can setup the following config:

On BP content
Only allow the Sidebar layout, do not allow Cards or Edge.
On the Sidebar layout, only allow certain components in the main region and certain components in the aside. E.g I do not want CCs adding my right hand menu to the main region, and I don't want image cards in the aside.

On LP content
Allow all layouts
Apply the same rules as BP content to Sidebar layouts, and maybe allow an additional component (because it should allow different permutations per bundle)
On Edge layouts only allow a "Hero" component - taking it a step further it could be ideal to restrict this to only a single Hero component and nothing else (this extra bit currently isn't possible with LB restrictions afaik)
On Cards layouts only allow simple Text components in the Intro region, and Card components in the Cards region.

acbramley’s picture

Forgot to reply to this:

Essentially this is a more complex variant of unlocked slots (which you mentioned above). I'm not at all certain it is a good idea! It was discussed at some point (maybe even just at DrupalCon — I do not recall). It kind of falls under the " I'm not saying I think this is a good idea. This is more on the extreme end of granularity of control." caveat I wrote in #2.

Which was a reply to @catch's question about unlocking only certain slots in #18

As per above in #26 I think this kind of flexibility is a good idea and somewhat required. In my example above we could imagine that on the Basic page maybe the Sidebar region (or slot?) of the 2 col 80/20 layout may be locked. E.g I can imagine a use case where I want CC to be able to edit the main region of that 2 col layout, but I want to lock the sidebar to only ever display the right hand tree navigation component, and nothing else.

catch’s picture

Two further questions on this:

1. Right now XB only enables one XB field instance per bundle, but if unlocked slots are ever allowed on the non-default view mode, wouldn't it need to be a field-per-view-mode-with-unlocked-slots? Or all view modes stored in one field value with an additional layer of JSON nesting?

2. Note #3440578-80: [PP-2] JSON-based data storage proposal for component-based page building where I tried to think through 'special' view modes like search (indexing) and newsletter rendering - which usually show nearly the same content as the 'default' view mode but with certain differences like related content blocks or field labels removed. This gets very, very complicated with the current data model and unlocked slots. If we allow unlocked slots in multiple view modes, it could get even more complicated - e.g. say someone makes an unlocked slot in the teaser view mode for an article content type, and you then want that search indexed along with the unblocked 'body' slot on the article view mode.

I was also unable to find internal search indexing and multi-channel re-use such as e-mail in the product requirements.

wim leers’s picture

Assigned: Unassigned » lauriii

@catch in #28:

  1. Quoting the product requirements, emphasis mine:

    As a builder, I want to create and modify content type templates for how content of a specific content type will be displayed. I want to be able to create multiple templates for a given content type (view mode). Within the template, I want to add components that may or may not map to fields in the content type.

    So I think the question is: how do we keep unlocked vs locked slots in sync across the different templates? And if they're not in sync, then the content creator would need to author the same entity's layout/component tree multiple times: once per view mode that uses XB.

  2. Let's first get clarity on the first point, that reduce hypothesizing as we dig into this bit 😅

I was also unable to find internal search indexing and multi-channel re-use such as e-mail in the product requirements.

VERY good point 😳😱

@lauriii: thoughts?

catch’s picture

I unfortunately thought about search indexing/newsletters several hours after talking to @lauriii about XB at devdays, have opened an explicit issue at #3462219: [META] Support alternative renderings of prop data added for the 'full' view mode such as for search indexing or newsletters so it can be tracked in its own right.

However one thing that came up when we talked is that most of the experience builders don't actually have a concept of view modes at all - you create the data, and then it gets put out as JSON, and then the front end templates just consume the bits of the JSON they need (full, card etc.), but the idea of having separate configurations for different view modes is not really in there. (hopefully this is an accurate summary of what was said).

So I think the question is: how do we keep unlocked vs locked slots in sync across the different templates?

I would assume locked is fine, because there is no editing of something that is locked, it's just bundle + view mode level config.

But yeah once you have unlocked slots in more than one view mode there is a lot to deal with. One way to deal with it would just be to prevent it everywhere except full/default.

wim leers’s picture

But yeah once you have unlocked slots in more than one view mode there is a lot to deal with. One way to deal with it would just be to prevent it everywhere except full/default.

Interesting proposal! WDYT, @lauriii?

wim leers’s picture

Component: Data model » Config management
tedbow’s picture

I am working on #3481720: Tighten validation: only allow StaticPropSource in XB fields + PageTemplate, DynamicPropSource in ContentTypeTemplate. Since we are removing dynamic properties we didn't need some of the logic and test coverage we added in #3454257: Allow Experience Builder fields to support Asymmetric and Symmetric translations.

Basically since you can't display a field like the node title in the XB field it you can't get the wrong translation of the title. You can still have different component properties per language, they will just all be static props

But this current issue will need some of the logic and test coverage we removed added back. Particulary this https://git.drupalcode.org/project/experience_builder/-/merge_requests/3.... I assuming the same fix will be needed and work but to be sure we will need to update the test coverage we removed in \Drupal\Tests\experience_builder\Functional\TranslationTest in #3481720

The test/use case won't be exactly the same but basically we will need to test if you use the node title in a component prop in the content type template when view a single node in different languages you see the correct translation of the title

We will also need to determine if we will support config translation of content type templates. If so that will be another area to test

wim leers’s picture

#33++

larowlan’s picture

FWIW @DanielVeza has been working on a LB solution for this at https://www.drupal.org/project/lb_immutable_sections

wim leers’s picture

Title: [later phase] [META] 7. Content type templates — aka "default layouts" — affects the tree+props data model » [Needs design] [META] 7. Content type templates — aka "default layouts" — affects the tree+props data model
Assigned: lauriii » callumharrod
Status: Active » Needs work
Issue tags: +Needs design

Design for this has begun in earnest. @callumharrod is working on that. Initial design review happened <48 hours ago.

To ensure the design is thinking about future needs and not just the subset we'll start with, I promised to create an outline of how the supporting config entity would work and would tie in to other parts.

Did that in #3511366: [META] Introduce a `ContentTypeTemplate` config entity + related infrastructure. Specifically, the context in #3511366-3: [META] Introduce a `ContentTypeTemplate` config entity + related infrastructure, and the issue summary as of that point.

wim leers’s picture

wim leers’s picture

Issue summary: View changes

Start crafting an issue list, inspired by #3499919: [Meta] Plan for in-browser code components's example, but with explicit parallel lanes.

wim leers’s picture

Issue summary: View changes
wim leers’s picture

Issue summary: View changes
wim leers’s picture

Issue summary: View changes
wim leers’s picture

Issue summary: View changes
larowlan’s picture

Tagging this as a stable blocker. In order for XB to be a viable replacement to LB/Paragraphs this is needed.
Otherwise we're in https://xkcd.com/927/ territory.

Also linking pieces that will make this easier. There is a lot we can learn from LB on this front.

wim leers’s picture

#44+++++++++++

@larowlan: please see #3511366: [META] Introduce a `ContentTypeTemplate` config entity + related infrastructure for the concrete proposal I made for a config entity architecture that (attempts to) solidify all past discussions in something tangible.

larowlan’s picture

thanks Wim

kristen pol’s picture

Issue tags: +XB Migration

tagging for findability

danielveza’s picture

This has been partially covered above and may be part of the video from #19, but I just wanted to have my thoughts in written format from pain points experienced with Layout Builder and overrides. As flagged by this being a stable blocker so I'm happy this is on the radar, I think its something that XB needs to get right (to the best of our ability) from the start. I'm going to use Layout Builder terms in this comment but the same logic should apply to their XB equivalent.

Note that this is going to be a braindump and going to be a bit rambly.

Layout Builder is a fantastic tool, and the contrib community around has built tools to further support how it works. Where Layout Builder falls over however, is getting updates from the default template to nodes that have been overridden.

Lets say we have a content type with 5 sections in it's default template, and 10,000 nodes of that content type where most if not all have been overridden to add additional content on a per node basis. Now we need to add a new block to section 3 for legal or compliance reasons.

This new block is not going to appear on any of the overridden nodes, so we need to write a complex update hook to add it everywhere. However there are still problems here. We can't guarantee that section has not been deleted or moved on any of the overridden nodes, so we need to take that into account. Layout Builder sections don't have UUIDs (#3208766: Add UUID to sections, so we can't even look up the section during the update process with confidence. This is very flaky so we tend not to do it.

Because of this on some new projects I've started to create blocks that renders a collection of fields/blocks, so the Layout builder content now looks like this.

-- Top content (Collection of blocks in a single plugin)
-- Layout Builder content
-- Bottom content (Collection of blocks in a single plugin)

This means the editors lose some control over what parts of the page they can edit (Only the middle section), but allows us to add new content to the top or bottom blocks that will automatically apply to all nodes, regardless on if they're overriden or not.

This leads us to the second problem, how do we add new Sections to the default template and have them flow through to the overridden nodes in the correct place. Again this is a problem in Layout Builder and something that should be considered for XB.

TLDR; Updating overriden content in Layout Builder from the default template is painful. We should take the lessons we've learnt from Layout Builder and apply them to XB from the start.

wim leers’s picture

A lot of progress has happened on this front!

I used #3511366: [META] Introduce a `ContentTypeTemplate` config entity + related infrastructure to create a PoC, to align with @lauriii on the product side and @callumharrod on the design side. We now have actual designs!

Then … @phenaproxima stepped in and took the PoC I did in #3511366, and started really building this:

  1. #3517741: Content templates, part 1: introduce the `ContentTemplate` config entity type
  2. #3518013: Content templates, part 2: Using the templates for rendering
  3. #3517845: Content templates, part 3a: allow content templates to define exposed slots
  4. (blocked/long detour via #3468272: Store the ComponentTreeStructure field property one row per component instance, which now landed)
  5. currently being worked on: #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities

#48:

Now we need to add a new block to section 3 for legal or compliance reasons.

This new block is not going to appear on any of the overridden nodes, so we need to write a complex update hook to add it everywhere.

This is exactly the problem we wanted to avoid! 👍 And we did. See #3517741: Content templates, part 1: introduce the `ContentTemplate` config entity type + #3517845: Content templates, part 3a: allow content templates to define exposed slots + #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities.

This means the editors lose some control over what parts of the page they can edit (Only the middle section), but allows us to add new content to the top or bottom blocks that will automatically apply to all nodes, regardless on if they're overriden or not.

Yep, this is exactly what exposed slots are about. See #3517845: Content templates, part 3a: allow content templates to define exposed slots :)

This leads us to the second problem, how do we add new Sections to the default template and have them flow through to the overridden nodes in the correct place.

This, too, is addressed in the above. Because a ContentTemplate for article Nodes literally controls every article node entity, with each individual article node only being able to populate exposed slots.


@callumharrod has designs. I'll ask him to share those here.

callumharrod’s picture

Here's a link to the Figma design for Content Templates: https://www.figma.com/design/am9E9G2MeDOHnkET2uSRc7/-Feature--Content-Te...

More than happy to answer any design-related questions! 👍

wim leers’s picture

Title: [Needs design] [META] 7. Content type templates — aka "default layouts" — affects the tree+props data model » [PP-1] [META] 7. Content Templates — aka "default layouts" — affects the tree+props data model
Version: 0.x-dev » 1.x-dev
Status: Needs work » Postponed
Issue tags: -stable blocker

For 1.0, we're targeting a subset of the entire scope: #3541000: [META] Content templates UI for 1.0: only nodes, no exposed slots, no replacement for the view mode/display UI. At a high level (see #3541000-25: [META] Content templates UI for 1.0: only nodes, no exposed slots, no replacement for the view mode/display UI), we're leaving the following for later:

wim leers’s picture

Marked #3511366 as fixed, because the subset of this meta it aimed to deliver, it did: #3511366-34: [META] Introduce a `ContentTypeTemplate` config entity + related infrastructure.

Project: Experience Builder » Drupal Canvas

Experience Builder has been renamed to Drupal Canvas in preparation for its beta release. You can now track issues on the new project page.

dunx’s picture

I've just found this from Slack. The video at https://www.drupal.org/project/canvas/issues/3455629#comment-15646756 matches exactly how I imagined this working - structured content interspersed with unstructured content, but still providing the ability to update the global template which applies to all nodes even when the template for that node has been overridden, which is very difficult in Layout Builder right now.

I understand why it's not in v1.0, but does represent a common use case, so v1.1 perhaps ;)