[PoC] Introduce a `ContentTypeTemplate` config entity

Created on 6 March 2025, 3 months ago

Overview

This is in support of ๐ŸŒฑ [META] 7. Content type templates โ€” aka "default layouts" โ€” clarify the tree+props data model Active , based on preliminary design discussions that happened 2 days ago, between @lauriii, @jessebaker, @callumharrod and I.

I promised to get an initial outline going of what a new config entity could look like.

There's AT LEAST two major challenges, both design-wise and technically:

  1. View modes: do we allow the Site Builder to craft a different component tree per view mode?

    โš ๏ธ For scope/design/deliverability purposes, @lauriii has decided to NOT tackle this for now, and to limit to the default view mode only. IOW: no "teaser" support.

    But the config entity design should anticipate this evolving beyond supporting only the default view mode.

  2. Internal/exposed or Locked/unlocked: which subtrees of the Site Builder-defined component tree for the content entity type+bundle+view mode can be customized by the Content Creator?

    (For example: "product" content entities may have rigid presentation of key product information, but unlocked/exposed and subtrees.)

    Related: #3498819-5: [Needs design] Proposal: Adjust representation of Regions in the Layers UI โ†’

(A third technical challenge: translatability of this config. Specifically, the exposed/unlocked subtrees' labels should be translatable. This should avoid the mistakes e.g. CKEditor 5 made โ€” see ๐Ÿ› [Style] CKEditor 5 styles config storage is not compatible with config ovverides Needs work .)

Proposed resolution

Details TBD.

P.S.: I think the name ContentTypeTemplate is not great. We might land on a better name later, when development on this truly begins. Until then, we've always referred to it using this term, so might as well use it for now. It's purely internal anyway.

User interface changes

None; this is purely supporting back-end infrastructure.

๐Ÿ“Œ Task
Status

Active

Version

0.0

Component

Config management

Created by

๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @wim leers
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    Updated issue summary with new design/product questions that I identified while building the PoC to predict future technical challenges: now there's not 2 but 9 challenges! ๐Ÿ˜…

    FYI: I landed on the term for what @jessebaker alluded to in #3498819-5: [Needs design] Proposal: Adjust representation of Regions in the Layers UI โ†’ .

    Note that I built this config entity type PoC while taking into account all discussion-surfaced requirements outlined in the meta โ†’ .

    Omitted from the work I did:

    • Per-component input (un)locking: this seems too overwhelming/too granular.
    • Mostly omitted: view mode concerns. The config entity type supports storing it, but none of the semantical or UX consequences are addressed. For example: it the XB content type template for a "teaser" view mode exposes a different Content Type Slot than the one for the "default" view mode, how would the content author ever populate it? It'd always remain empty! An obvious solution seems: the "default" view mode defines the total set of Content Type Slots, and each view mode can choose to contain only a subset of them. But does this meet @lauriii's product vision? Impossible to tell: it's currently neither written down nor expressed in designs. He did express that anything beyond "default" view mode is a concern for later, so I didn't delve deeper.
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    In not-yet-public docs, I encountered a functional requirement I had not read before, but it makes sense (it ties into XB product requirement 14. Configuration management), it reads:

    I can make changes to the content type templates outside of the production site

    โ€ฆ which is the non-UI, but config-management-level-enforced equivalent of point 9 I surfaced in the issue summary above: .

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    Additional notes while digging into this problem space and trying to think through everything:

    1. ๐Ÿช„โšœ๏ธTranslatability. A component tree will typically contain some static values. For example: a button that points to the current content entity's webshop URL, with that URL being mapped into it dynamically (DynamicPropSource), but the button label being defined statically because it makes no sense as structured data (so: StaticPropSource).

      Any component input populated using a DynamicPropSource is automatically translatable, because it fetches the value from the host content entity.

      But any component input populated using a StaticPropSource is NOT translatable. At least not at this time. Because component trees in config are currently enormous JSON blobs. That's not compatible with Drupal's config translation functionality โ†’ .

    2. (More to follow.)

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom catch

    So, rephrasing: assuming that we know which of the structured data are "meta" vs not, must every non-meta field be used somewhere in the component tree?

    It's common to have fields that are only used on specific view modes, including ones that don't show on the default. An example would be a 'short summary' field that only shows on a card view mode and not on the main content.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    Based on discussing ๐ŸŒฑ [META] 7. Content type templates โ€” aka "default layouts" โ€” clarify the tree+props data model Active with @lauriii this morning, a few things surfaced:

    1. Supporting multiple view modes MUST be supported from the start. But, only the default view mode will be customizable per entity. So, a teaser view mode for example would look the same for all entities of that content entity type+bundle: the same exact XB component tree would be used for all (i.e. the one in the "teaser" Content Type Template config entity), while of course resolving the structured data mapped into the component tree (i.e. using DynamicPropSources).

      This avoids the entire "keep Content Type Slots in sync across all Content Type Templates (one per view mode) for this content entity type+bundle" problem. ๐Ÿ‘

    2. XB is used for either all or none of the view modes. IOW: as soon as you chose to use XB, all existing EntityViewDisplays are ignored. Those that don't have an XB Content Type Template defined yet render nothing.

      Note: this will change in the far future per @lauriii: he intends to allow specifying an XB element (see ๐Ÿ“Œ Clarify "components" vs "elements" vs "patterns" Active ) to be associated with each field type, which essentially becomes the XB equivalent of "the default formatter".

    3. Last but not least: per @lauriii, there won't be a "search" or "search index" view mode for XB โ€” search must be configured to use the "default" view mode's representation of content entities both for 1) crafting a search index to power the search, 2) presenting search results. Related: ๐ŸŒฑ [META] Support alternative renderings of prop data added for the 'full' view mode such as for search indexing or newsletters Active and ๐Ÿ“Œ Create a configurable search api processor for XB data Active .

      It's not clear to me yet how that avoids the

      but without elements that would 'pollute' the search results like field labels, related content blocks, CTAs, social widgets etc. so that if I search for "newsletter" or "Facebook" I don't get every article on the site back in the results, but only the ones with content actually mentioning newsletters or Facebook.

      problem described in ๐ŸŒฑ [META] Support alternative renderings of prop data added for the 'full' view mode such as for search indexing or newsletters Active , though.

  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland lauriii Finland
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
  • Responses

    Hey @wim-leers - the answers below is just my take on the problems listed ๐Ÿ˜„

    1. View modes - Not for me to answer
    2. Internal/exposed or Locked/unlocked aka Exposed Content Type Slots aka unlocked subtrees - Any slots that are used within the template should be able to be an exposed slot. They will not be able to be exposed if they currently contain any child items.
    3. What about the existing EntityViewDisplay(s)? - Unsure on this one, would be keen to discuss it further.
    4. Must every field for the content entity type+bundle be used somewhere in the component tree, because otherwise some data is invisible? - No, it would be up to whoever is creating their content template to decide what fields are mapped to their template. For example: If a product content type has a required field of โ€˜Priceโ€™ it is up the person creating the template to ensure that it is tied to their template.
      I think a good way to think of the creation of templates is similar to how it would be done with a headless CMS, in that the content model and content creation are separate from the templating layer.
    5. Are we okay with either ignoring or breaking existing hook_entity_display_build_alter() implementations? - Not for me to answer
    6. Gotcha for Exposed Content Type Slots aka unlocked subtrees. - Correct, we should allow having no exposed slots for the content type.

      If a user wanted to they could make the entire page a single slot, but they would still need to add a component and expose the slot in the exact same way as exposing any other slot.

    7. Gotcha for Exposed Content Type Slots aka unlocked subtrees. - I donโ€™t believe we should be allowing exposed slots to include anything. By including items in a slot to also be exposed to a content editor, we open lots of ways to break templates that aren't necessary. By going this route I don't think we impede the template builder in any way. In the user flows this should become clearer.
    8. Gotcha for Exposed Content Type Slots aka unlocked subtrees. - Good point, as part of exposing a slot, we can ensure that thereโ€™s a name and machine name here. Will need some designs and work on the front-end to cater for this.
    9. Gotcha for Exposed Content Type Slots aka unlocked subtrees. - Are you saying that when a component is added to a slot when editing content, it cannot be deleted? Or is it just that the data cannot be deleted?

    Questions from me:

    1. Once you have made a slot exposed, are we able to revert this change? Can we turn off an exposed slot?
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    I see that I failed to update the issue summary with @lauriii's input from #7. Now updated. Some questions are fully answered, some are merged.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    #10:
    RE: your question: per discussion this morning with @lauriii: as the Site Builder modifying/creating an XB Content Type Template, you have complete freedom to completely change your mind about adding/removing exposed Content Type Slots. So the answer is: "yes, you can revert".

    1. โœ… Sorry ๐Ÿ™ˆ This has changed โ€” see #7.2. Issue summary updated in #11 ๐Ÿ‘
    2. I suspect we are on the same page, but โ€ฆ I disagree with your specific wording ๐Ÿ˜‡ I know I'm gonna sound super nitpicky, but all of this is going to have enormous consequences for UX and data integrity, so I went to be painfully precise ๐Ÿค“ ๐Ÿ˜œ
      • It should not be "any slot", because slots can live within other slots.
      • Furthermore, I'm not convinced yet that only slots must be exposable as a Content Type Slot, but any component instance. That way:
        • if it's a component instance without slots, it means you can modify this component instance's inputs โ€” for example: XB's my-section SDC would then be able to have inputs (image, text next to the image) that are defined in the Content Type Template, but if the Content Creator chooses, they could modify the inputs without the ability to add more component instances
        • if it's a component instance with >=1 slot(s), it means the Content Creator can modify as much as they like: remove the entire component tree in one of those slots, keep it empty, replace it with other component instances, or keep it all the same as in the Content Type Template
    3. โœ… This has been answered by @lauriii. Issue summary updated in #11 ๐Ÿ‘
    4. ๐Ÿ‘ WFM! But would there then be affordances to ensure the Site Builder is explicitly aware of which fields (whose values) are not (yet) being presented?
    5. โœ… This has been answered by @lauriii. Issue summary updated in #11 ๐Ÿ‘
    6. ๐Ÿ‘ This ties well into what @lauriii has confirmed Product-wise โ€” see the updated information for Question 2 in the issue summary.
    7. ๐Ÿค” I'm not sure how to interpret this. Are you saying that a Site Builder should or should not be able to expose a Content Type Slot that contains some component instances populated with structured data?
    8. ๐Ÿ‘
    9. โœ… Sorry ๐Ÿ™ˆ This has changed โ€” see #7.1. Issue summary updated in #11 ๐Ÿ‘
      (And no, that's not what I meant: I was referring to disallowing deleting Content Type Slots, but @lauriii has since said this is fine, and it's fine to lose Content Creator-crafted data.)
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom catch

    Last but not least: per @lauriii, there won't be a "search" or "search index" view mode for XB โ€” search must be configured to use the "default" view mode's representation of content entities both for 1) crafting a search index to power the search,

    afaict this is incompatible with ๐Ÿ“Œ Create a configurable search api processor for XB data Active - which is suggesting not rendering XB at all when configuring search indexing, except via the special search API processor. I'm not convinced by that issue yet (and left a question on there which hasn't been answered yet) but has that been abandoned or is this a mistake? Using ๐Ÿ“Œ Create a configurable search api processor for XB data Active would mean either not using a view mode at all in search indexing, or a view mode minus XB data that only shows entity fields, with the XB data then provided by the separate processor.

    If you had to use the default view mode and the processor it would mean double-rendering when search indexing.

    2) presenting search results.

    This seems unnecessarily restrictive and also unenforceable. e.g. you can configure search API views to return results from a search index, then use any view mode on the entity that you like right now - like displaying search results as a grid of cards or whatever.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium borisson_ Mechelen, ๐Ÿ‡ง๐Ÿ‡ช

    Last but not least: per @lauriii, there won't be a "search" or "search index" view mode for XB โ€” search must be configured to use the "default" view mode's representation of content entities both for 1) crafting a search index to power the search, 2) presenting search results. Related: ๐ŸŒฑ [META] Support alternative renderings of prop data added for the 'full' view mode such as for search indexing or newsletters Active and ๐Ÿ“Œ Create a configurable search api processor for XB data Active

    It's not clear to me yet how that avoids the

    but without elements that would 'pollute' the search results like field labels, related content blocks, CTAs, social widgets etc. so that if I search for "newsletter" or "Facebook" I don't get every article on the site back in the results, but only the ones with content actually mentioning newsletters or Facebook.

    problem described in ๐ŸŒฑ [META] Support alternative renderings of prop data added for the 'full' view mode such as for search indexing or newsletters Active though.

    Rendering Search results in the same way as the content's detail page doe not seem like the most commonly chosen way of configuring it. I did a quick poll at the contribution room at Drupal Mountain Camp, and everyone who answered me always configures some kind of teaser, card or search-result view mode when rendering a search result page.

    For the indexation part, I also don't see a way that would remove those pollutions without having a seperate view mode, but I personally think that's not as bad. When needing complete control over what all is indexed, it should be indexed using fields, because then it's possible to boost per-field. It gives a lot more control.

    This however would mean something like https://www.drupal.org/project/layoutbuilder_search_api โ†’ for all components/props, which is another approach that could be taken. This removes the double rendering that catch talked about in #13.

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom catch

    When needing complete control over what all is indexed, it should be indexed using fields, because then it's possible to boost per-field. It gives a lot more control.

    This however would mean something like https://www.drupal.org/project/layoutbuilder_search_api โ†’ for all components/props

    I think that ๐Ÿ“Œ Refactor the XB field type to be multi-valued, to de-jsonify the tree, and to reference the field_union type of the prop values Active would also handle this - because the props would be available as field data to search API then without an additional translation layer.

  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland lauriii Finland

    Rendering Search results in the same way as the content's detail page doe not seem like the most commonly chosen way of configuring it. I did a quick poll at the contribution room at Drupal Mountain Camp, and everyone who answered me always configures some kind of teaser, card or search-result view mode when rendering a search result page.

    We should definitely support configuring customizing how content is displayed in the search results page. I'm not sure we need to do that in this issue though because it might make sense to design and implement solution specifically for that, because it's such a common use case.

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom catch

    @lauriii that's the opposite of what this says in #7:

    Last but not least: per @lauriii, there won't be a "search" or "search index" view mode for XB โ€” search must be configured to use the "default" view mode's representation of content entities both for 1) crafting a search index to power the search, 2) presenting search results.

    is there a miscommunication somewhere?

    If search results use a view mode for rendering (which a lot of sites do), then it shouldn't require any special handling in XB, it just needs to not break using view modes for rendering.

    The place where it might get tricky is 'results snippet' type situations where the search result is trying to show the searched keywords in the context of the results. I'm not sure how that's generally implemented in search API or not or whether it would need special handling. For me that's the least important aspect to worry about - it's the initial indexing that feels unresolved still.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    #17: that's not matching what you said earlier โ†’ .

    Unless you meant that that would be the initial state, and you intend to only use the default content type template for search indexing and a different content type template for presenting search results?

    But if we do that, then it follows that the information that was matched is absent from the search result's presentation, meaning highlighting is impossible.

  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland lauriii Finland

    I feel like we are talking past each other with different use cases and scenarios and concerns that are not being impacted by Experience Builder. My understanding is that there are two primary ways of configuring Search API: text based search and faceted search (as well as combination of the two).

    When using text based search and the intent is to index the whole page, the "Rendered HTML output" with the default content type template (same as what user would see when navigating to the page) should be used. Search API would allow configuring other view modes to be used for indexing but those wouldn't include the content added to the slots, but only content that is being rendered through those view modes. So long as we keep view modes working, this should all work without specifically having to accommodate them. This is the same experience that you would get when using Layout Builder today.

    When using the text based search, the results would often display an excerpt which is generated based on what is in the index. This allows highlighting the text that is being matched. This shouldn't require any special accommodations from XB so long as what is stored in the index is sensible.

    When implementing a faceted search, it's common to configure the results to display to using a view mode like cards or search result. In this scenario, text is not being highlighted. Even in this scenario, the index may include the full rendered page, highlighting that the index is a separate concern from the presentation of the results.

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia larowlan ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ.au GMT+10

    Layout builder uses third party settings on the entity view display for this rather than a separate config entity.
    I think that is a valid approach worth considering.

    I also think ๐Ÿ“Œ Decouple tree storage, introduce tree storage plugins Active is important here because our present code-path \Drupal\experience_builder\InternalXbFieldNameResolver::getXbFieldName falls over here

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    Layout builder uses third party settings on the entity view display for this rather than a separate config entity.

    I considered that, but I think there are strong reasons against it:

    1. The consequence of that will be though that this new config entity type is not validatable, because EntityViewDisplay config entities are not yet fully validatable, with an unclear ETA for that in core. This would significantly weaken XB's 14. Configuration management product requirement.
    2. LB predominantly uses field formatters to present structured content: it uses FieldBlock, which contains field formatter settings (which IIRC are treated as the default formatter settings when placing a field block). So, most of the information in the EntityViewDisplay is still somewhat relevant when using LB.
    3. @lauriii has indicated that it should be possible to try XB and be able to abort and go back to what you had before: plain core entity view displays, or Layout Builder entity view displays. Not touching them at all makes that an easy promise to keep.
    4. Finally, and probably the strongest argument: LB does a quite heavy-handed override at \Drupal\layout_builder\Hook\LayoutBuilderHooks::entityTypeAlter() that causes all EntityViewDisplay config entities to use its own LayoutBuilderEntityViewDisplay class instead! XB cannot do the same, or it'd either break LB (race: who wins?) or require LB (definitely not the intent either). That's in the MR:
       * This MUST be a new config entity type because doing something like Layout
       * Builder's `LayoutBuilderEntityViewDisplay` is impossible if XB wants to
       * provide a smooth upgrade path from Layout Builder, due to
       * \Drupal\layout_builder\Hook\LayoutBuilderHooks::entityTypeAlter() โ€” only one
       * module can do that!
      

    I don't think ๐Ÿ“Œ Decouple tree storage, introduce tree storage plugins Active is a hard blocker for this issue, but I definitely agree it'd be nice to solve, especially in light of providing a smooth transition from Layout Builder into Experience Builder! (Note this will require either duplicating LB's FieldBlock in XB, or moving it to another module โ€” otherwise Layout Builder will be required forever even on sites that have all their data moved from LB to XB!)

  • First commit to issue fork.
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States mglaman WI, USA

    +1 to this approach! I had forgotten this issue and proof of concept existed when I had a chat with @phenaproxima where we chatted over this idea. The outcome happened to be nearly the same as this issue, except I didn't consider the possibility of having the config entity implement EntityViewDisplayInterface so we could swap it for the view display object.

    I pushed a test and some wonky code to further explore. I like that it mimics how page regions work. If something exists we execute a new code path versus embedding into the existing code path.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States mglaman WI, USA

    ๐Ÿ“Œ move static collect*() methods from display entity classes to EntityDisplayRepository Active would make this much easier. Then we could swap the display objects not and need hook_entity_prepare_view and hook_entity_view_alter

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    @callumharrod walked us (@lauriii, myself and David Bee) through the designs he crafted. All of us asked various questions. The PoC here is still aligned with the designs, with one exception: we're not going to be exposing a component instance as an exposed slot, but a slot in a component instance.

    Walked @phenaproxima through that change, and captured this change with him together, as a way to hand this off to him: https://git.drupalcode.org/project/experience_builder/-/merge_requests/7... :)

    (I'm still around, obviously!)

  • First commit to issue fork.
  • Pipeline finished with Failed
    about 2 months ago
    Total: 1046s
    #465645
  • Pipeline finished with Failed
    about 2 months ago
    Total: 2393s
    #465667
  • Pipeline finished with Failed
    about 2 months ago
    Total: 1874s
    #465729
  • Pipeline finished with Failed
    about 2 months ago
    Total: 914s
    #465751
  • Pipeline finished with Canceled
    about 2 months ago
    Total: 569s
    #465761
  • Pipeline finished with Failed
    about 2 months ago
    Total: 1021s
    #465768
  • Pipeline finished with Failed
    about 2 months ago
    Total: 1619s
    #465787
  • Pipeline finished with Failed
    about 2 months ago
    Total: 1898s
    #465799
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    @phenaproxima has split this into multiple child issues ๐Ÿ‘

  • Assigned to phenaproxima
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
Production build 0.71.5 2024