[META] Production-ready data storage
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3520449. --> Reported by: [wim leers](https://www.drupal.org/user/99777) Related to !1102 >>> <p><u>Legend<u></u></u></p> <ul> <li>&#9989; Done.</li> <li>&#128994; Confident it will not require backwards compatibility breaks.</li> <li>&#128993; Medium confidence; more work needed to achieve necessary confidence.</li> <li>&#128308; Low confidence; requires a lot more work</li> </ul> <h3 id="overview">Overview</h3> <p>XB's data model (<code>ComponentTreeItem</code>) was originally prototyped with:</p> <ol> <li>only SDCs</li> <li>&#9989; dynamic data fetched from the host entity, the right value(s) extracted using <code>(Reference)Field(Object)PropExpression</code> and assigned to the right component instance into the component tree: <code>DynamicPropSource</code>s</li> <li>&#9989; static data stored in independent field item objects: <code>StaticPropSource</code>s (which also must extract the right value(s), and does so using <code>(Reference)FieldType(Object)PropExpression</code>)</li> <li>&#9989; symmetric + asymmetric translation support (symmetric: <code>tree</code> is locked, <code>inputs</code> are per-translation; assymmetric: both are translatable, meaning different component trees for each translation) </li></ol> <p>Those foundations remained largely the same, but since then we gained:</p> <ol> <li>&#9989; multiple component types, thanks to <code>ComponentSource</code> plugins &rArr; everything must scale to unknown future component types </li><li>&#9989; additional prop sources, such as <code>DefaultRelativeUrlPropSource</code> &rArr; everything must scale to unknown future prop sources </li><li>&#9989; auto-saving of component trees </li></ol> <p>Finally, we <em>know</em> there's both known technical debt, and more features that we'll eventually need to support:</p> <ol> <li>&#9989; debt: full dependency support, throughout all of the above, to allow for reliable updates </li><li>&#128994; debt: the explicit input schema must be able to evolve, and each <code>ComponentSource</code> may have different needs for that. For example: block plugins may change their settings (and their config schema), SDCs may gain new optional inputs, JS components may gain new required inputs &rarr; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3501708" title="Status: Closed (fixed)">#3501708: Prove that it *will* be possible to apply block settings update paths (assuming #3521221 in core) to stored XB component trees in config/content</a></span> + <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3523841" title="Status: Closed (fixed)">#3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions &rArr; less data to store per XB field row</a></span> here &mdash; but <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-4"><a href="https://www.drupal.org/project/canvas/issues/3524751" title="Status: Postponed">#3524751: [later phase] Component Source plugins: generalized support for schema changes of explicit inputs</a></span> later. </li><li>&#9989; debt: we went with a JSON-heavy initial implementation (the <code>inputs</code> and <code>tree</code> props both store a JSON struture), but we may want to reconsider this &rarr; solved in <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3468272" title="Status: Closed (fixed)">#3468272: Store the ComponentTreeStructure field property one row per component instance</a></span>, with <a href="https://www.drupal.org/project/experience_builder/issues/3520449#comment-16123309:~:text=type%3A%20string-,storage%20efficiency,-%E2%80%94%20see%20%2313%20through">additional refinements possible post-release for more field types than just XB</a> </li><li>&#9989; feature: content entities' XB component trees must be able to populate the exposed slots provided by the corresponding <code>ContentTemplate</code> (&rarr; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3519352" title="Status: Closed (fixed)">#3519352: Content templates, part 3b: store exposed slot subtrees on individual entities</a></span>) </li><li>&#128994; feature: asymmetric translation will need some explicit inputs to be locked, because some explicit inputs may be considered to be not translatable &mdash; for example an image input of some component </li><li>&#128994; debt: currently, XB fields can only exist on XB's own <code>Page</code> content entity type (base field definition) and on the <code>article</code> bundle of <code>Node</code> entities (configurable field) &mdash; expanding that is out of scope here and is in scope for <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3498525" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3498525</a></span>. This poses no additional risks for XB's data storage, because this already covers the gamut of possible <em>kinds</em> of XB fields on content entities. </li><li>&#128994; feature: full read/write support of XB trees in JSON:API (<span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-4"><a href="https://www.drupal.org/project/canvas/issues/3521002" title="Status: Postponed">#3521002: [META] Maintainable client-side data model + internal HTTP API</a></span>'s <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3499632" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3499632</a></span>), including the ability to filter (&rarr; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-1"><a href="https://www.drupal.org/project/canvas/issues/3523844" title="Status: Active">#3523844: Spike: Explore adding configuration options to the tree item formatter to support alternate use-cases</a></span>). </li><li>&#128994; feature: ability to store variants of component trees for use cases like personalization (i.e. different component subtree for Belgians &amp; Brits vs everyone else &rarr; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-1"><a href="https://www.drupal.org/project/canvas/issues/3525564" title="Status: Active">#3525564: [META] Experience Builder Personalization</a></span>), responsive design (i.e. breakpoint-specific overrides), and arbitrary future use cases (&rarr; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-4"><a href="https://www.drupal.org/project/canvas/issues/3525746" title="Status: Postponed">#3525746: Update the React client preview view</a></span>) </li></ol> <h3 id="beta">Beta blockers (July 2025)</h3> <p>Beta blockers (tag: <code>beta blocker</code>) MUST happen before <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3515932" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3515932</a></span>.</p> <p><em>&#9888;&#65039; As part of this, we're aiming to ideally close <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-17"><a href="https://www.drupal.org/project/experience_builder/issues/3477428" title="Status: Closed (outdated)">#3477428: [PP-1] Refactor (or decide not to) the XB field type to be multi-valued, to de-jsonify the tree, and to reference the field_union type of the prop values</a></span> and <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-4"><a href="https://www.drupal.org/project/drupal/issues/3440578" title="Status: Postponed">#3440578: [PP-2] JSON-based data storage proposal for component-based page building</a></span>, but both of those cover many aspects. They're being tackled piece-by-piece by the beta-blocking issues below, as originally proposed by @larowlan at <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-17"><a href="https://www.drupal.org/project/experience_builder/issues/3477428" title="Status: Closed (outdated)">#3477428: [PP-1] Refactor (or decide not to) the XB field type to be multi-valued, to de-jsonify the tree, and to reference the field_union type of the prop values</a></span>.</em></p> <p><em>(Numbered lists must happen one after the other, bulleted lists can happen in parallel.)</em></p> <ol> <dl> <dt id="beta-dependencies">&#9989; Dependencies/usage beta blockers</dt> <dd>Precise dependency information for every XB component tree: every config entity with a component tree AND <u>every revision of an XB field instance in content entities</u>, because that allows strong guarantees, and is essential for explicit input schema evolvability</dd> <dd> <ol> <li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3457504" title="Status: Closed (fixed)">#3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3521202" title="Status: Closed (fixed)">#3521202: Store XB field type's "deps_*" columns in separate table to allow efficient querying</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3460230" title="Status: Closed (fixed)">#3460230: Component entity config dependencies are incomplete: missing ComponentSourceInterface::calculateSettingsDependencies() to compute deps for field storage + instance settings + widget</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/canvas/issues/3544604" title="Status: Closed (fixed)">#3544604: Calculating dependencies of `ReferenceField(Type)PropExpression` is missing intermediate dependencies</a></span> </li></ol> </dd> <dt id="beta-field-type-storage">&#9989; Field type storage (content entities) schema beta blockers</dt> <dd> Given lessons in the ecosystem over the past decade, plus what we know about functionality we still intend to add to XB, organize the data storage to avoid future backwards compatibility breaks, and allow data storage for new features to be easily added later.<br> </dd> <dd> <ol> <li>&#9989; Ensuring multi-value (<code>type: array</code>) explicit inputs (e.g. list of integers for sparkline component, list of images for image gallery component, etc.) can be supported later: <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3467870" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3467870</a></span></li> <li>&#9989; 1 row/revision with 2 enormous JSON blobs &rarr; 1 row/component instance/revision with a single tiny JSON blob: <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3468272" title="Status: Closed (fixed)">#3468272: Store the ComponentTreeStructure field property one row per component instance</a></span> </li><li>&#9989; <u>content templates:</u> XB field on content entities should be able to store &gt;1 component tree: one per exposed slot in the governing <code>ContentTemplate</code>, if any <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3519352" title="Status: Closed (fixed)">#3519352: Content templates, part 3b: store exposed slot subtrees on individual entities</a></span> </li><li>&#9989; New <code>name</code> field property for additional functionality: <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3460958" title="Status: Closed (fixed)">#3460958: Data storage support for allowing Content Creator to name component instances for the specific context</a></span> </li><li>&#9989; versioned <code>Component</code>s + associated storable prop shapes (field types + settings) (blocker for <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-4"><a href="https://www.drupal.org/project/canvas/issues/3524751" title="Status: Postponed">#3524751: [later phase] Component Source plugins: generalized support for schema changes of explicit inputs</a></span>): <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3523841" title="Status: Closed (fixed)">#3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions &rArr; less data to store per XB field row</a></span> </li><li>&#9989; <del>bike shed</del> finalize the field type's field property names: <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3528167" title="Status: Closed (fixed)">#3528167: Rename `version` field property to `component_version`</a></span> </li><li>&#9989; ensure this architecture allows for efficient updating of existing component trees when explicit input schemas (block settings, SDC props &hellip;) change: <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3501708" title="Status: Closed (fixed)">#3501708: Prove that it *will* be possible to apply block settings update paths (assuming #3521221 in core) to stored XB component trees in config/content</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3528528" title="Status: Closed (fixed)">#3528528: `ComponentInputs::getPropSources()` needs to take `GeneratedFieldExplicitInputUxComponentSourceBase::rawInputValueToPropSourceArray()` into account</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3528499" title="Status: Closed (fixed)">#3528499: Revisit storage of dependencies in separate table now we have separate deltas per component + remove plugin dependencies + make component version usages auditable</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-3"><a href="https://www.drupal.org/project/experience_builder/issues/3520923" title="Status: Closed (duplicate)">#3520923: [PP-1] Use `json` schema type for SQLite and remove `text` workaround</a></span> </li></ol> </dd> <dt id="beta-config-storage">&#9989; Configuration storage schema beta blockers</dt> <dd> <ul> <li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3502982" title="Status: Closed (fixed)">#3502982: Rename ComponentSource settings' `plugin_id` to `local_source_id` or similar to not bias towards source plugins that don't use plugins under the hood</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3521137" title="Status: Closed (fixed)">#3521137: XB's storing JSON blobs should not be visible in exported config nor to test authors</a></span> </li><li>&#9989; ensure the versions are deterministic hashes: <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3528159" title="Status: Closed (fixed)">#3528159: Ensure deterministic version hashes for ComponentSource-specific settings, thanks to config schema-powered normalization</a></span> </li><li>&#9989; ensure the deterministic hashes capture all crucial aspects: <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3528362" title="Status: Closed (fixed)">#3528362: Deterministic Component version hash should depend not only on source-specific settings, but also slots + explicit input schema</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3526127" title="Status: Closed (fixed)">#3526127: Ensure deterministic config export order of config-defined component trees</a></span> </li></ul> </dd> <dt id="beta-validation">&#9989; Validation beta blockers</dt> <dd> <ul> <li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3473289" title="Status: Closed (fixed)">#3473289: XB Component config entity's `status` may only be `true` if it meets all of XB's requirements</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3526818" title="Status: Closed (fixed)">#3526818: Tighten validation of `parent_uuid` and `slot` on XB fields to match the strictness of config</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3519891" title="Status: Closed (fixed)">#3519891: Constrain slot names allowed by XB in Components (and in its component tree)</a></span> </li></ul> </dd> </dl> <h2 id="stable">Stable blockers (October 2025)</h2> <p>Stable blockers (tag: <code>stable blocker</code>) do not block <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3515932" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3515932</a></span>, but would be <em>nice-to-have</em> at that point in time. They MUST happen before <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3517885" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3517885</a></span>.</p> <dl> <dt id="stable-field-type">Field type storage (content entities) schema stable blockers</dt> <dd> <ul> <li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3528284" title="Status: Closed (fixed)">#3528284: Add e2e tests that prove we can edit an old version of a component</a></span> </li></ul> </dd> <dt id="stable-config-storage">Configuration storage schema stable blockers</dt> <dd> <ul> <li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3533458" title="Status: Closed (fixed)">#3533458: Change CodeComponentDataProvider::getRequiredXbDataLibraries() to base its logic on information provided by the front-end rather than on naive string/regex matching</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3538537" title="Status: Closed (fixed)">#3538537: Update path tests should also run against non-SQLite DBs</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/canvas/issues/3548165" title="Status: Closed (fixed)">#3548165: Components in `ContentTemplate`s and `PageRegion`s are not always rendered in correct order</a></span> </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-1"><a href="https://www.drupal.org/project/canvas/issues/3538273" title="Status: Active">#3538273: Use AST to identify resources fetched by CodeComponents so they can be preloaded/prefetched</a></span> </li><li><span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3460232" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3460232</a></span> </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-1"><a href="https://www.drupal.org/project/canvas/issues/3526706" title="Status: Active">#3526706: Stop assuming default Field Widget settings suffice&nbsp;&mdash;&nbsp;add Field Widget settings support to `experience_builder.generated_field_explicit_input_ux: prop_field_definitions`</a></span> </li><li><span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3503272" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3503272</a></span> </li><li><span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3464042" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3464042</a></span> </li></ul> </dd> <dt id="stable-validation">Validation stable blockers</dt> <dd> <ul> <li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-3"><a href="https://www.drupal.org/project/experience_builder/issues/3471026" title="Status: Closed (duplicate)">#3471026: Harden UUID validation in ComponentTreeStructureConstraintValidator</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3525759" title="Status: Closed (fixed)">#3525759: SdcPropKeysConstraintValidator::validate() should complain about extraneous keys too, not just missing keys</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3526721" title="Status: Closed (fixed)">#3526721: Require Drupal 11.1.8 and remove `type: field.value.language` work-around</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3526707" title="Status: Closed (fixed)">#3526707: Tighten validation of `experience_builder.generated_field_explicit_input_ux: prop_field_definitions.[%key].default_value`</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3538503" title="Status: Closed (fixed)">#3538503: Disallow component trees with `component_version: active`</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3526716" title="Status: Closed (fixed)">#3526716: Tighten validation of `experience_builder.generated_field_explicit_input_ux: prop_field_definitions.[%key].expression`</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3538487" title="Status: Closed (fixed)">#3538487: Don't allow passing uncollapsed inputs if using default expression</a></span> </li></ul> </dd><dt id="stable-security">Security stable blockers</dt> <dd> <ul> <li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/canvas/issues/3546996" title="Status: Closed (fixed)">#3546996: Component instances populated by linked `DynamicPropSource`s, but inaccessible entity/field: fall back to `NULL` for these values, triggering fallback rendering</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/canvas/issues/3554184" title="Status: Closed (fixed)">#3554184: Bubble cacheability of resolved props values and access results + `PropSourceBase::evaluate()` does not return cacheability at all</a></span> </li></ul> </dd> <dt id="stable-other">Other stable blockers</dt> <dd> <ul> <li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3528723" title="Status: Closed (fixed)">#3528723: Component::onDependencyRemoval() should be an uninstall validator if the dependency being removed is a module or theme</a></span> </li><li>&#9989; <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/experience_builder/issues/3537783" title="Status: Closed (fixed)">#3537783: ComponentTreeItem must override `::mainPropertyName()` because it has no `value` field property</a></span> </li></ul> </dd> </dl> <h2 id="post-stable-priorities">Post-stable priorities (<em>after</em> October 2025)</h2> <p>Post-stable priorities (tag: <code>post-stable priority</code>) do not block any release, and are things we'd like to see happen, but are intentionally NOT happening any time soon. We're highly confident that these will be net additions without the need for backwards compatibility breaks.</p> </ol><ul> <li>Field type storage (content entities) schema full feature scope blockers <ul> <li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-4"><a href="https://www.drupal.org/project/canvas/issues/3524406" title="Status: Postponed">#3524406: [later phase] [Needs design] [PP-1] Provide API for finding and UI for surfacing dangling/dead component subtrees &mdash; aka garbage clean-up</a></span> </li><li><span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3498525" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3498525</a></span> </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-1"><a href="https://www.drupal.org/project/canvas/issues/3526189" title="Status: Active">#3526189: Spike: explore merits of one Canvas field per exposed slot in content templates</a></span> </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-1"><a href="https://www.drupal.org/project/canvas/issues/3528458" title="Status: Active">#3528458: Component instances in exposed `ContentTemplate` slots must use the exposed slot's machine name</a></span> </li></ul> </li> <li>To be categorized: <ul> <li>&#128994;<span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3518272" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3518272</a></span> &mdash; note that the stable-blocking subset already landed &mdash; see <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3518272" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3518272</a></span> for details. </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-13"><a href="https://www.drupal.org/project/canvas/issues/3526703" title="Status: Needs work">#3526703: Adopt `AtLeastOneOf` validation constraint for cardinality validation</a></span> </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-1"><a href="https://www.drupal.org/project/canvas/issues/3523844" title="Status: Active">#3523844: Spike: Explore adding configuration options to the tree item formatter to support alternate use-cases</a></span> </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-4"><a href="https://www.drupal.org/project/canvas/issues/3522953" title="Status: Postponed">#3522953: [later phase] Make Component `audit` operation performant/scalable</a></span> </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-13"><a href="https://www.drupal.org/project/canvas/issues/3530051" title="Status: Needs work">#3530051: Update `ComponentAudit::getConfigEntityDependenciesUsingComponent()` to support component versions</a></span> </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-1"><a href="https://www.drupal.org/project/canvas/issues/3532712" title="Status: Active">#3532712: Audit use of ::loadUnchanged and any routes that might need to load the latest revision</a></span> </li></ul> </li> <li><u>clean-up</u>: <ul> <li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-4"><a href="https://www.drupal.org/project/canvas/issues/3530097" title="Status: Postponed">#3530097: [later phase] [PP-1] Prune unused `Component` config entity versions</a></span> </li><li><span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3495625" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3495625</a></span> </li><li><span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3518696" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3518696</a></span> </li><li><span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3481188" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3481188</a></span> </li></ul> </li> <li><u>asymmetric translation explicit input locking: across al component instances and/or per component instance</u> <ul> <li>Add a <code>untranslatable_inputs</code> field property, to allow a <u>content author</u> to <a href="https://www.drupal.org#:~:text=%F0%9F%94%B4-,feature%3A%20asymmetric%20translation%20will%20need%20some%20explicit%20inputs%20to%20be%20locked%2C%20because%20some%20explicit%20inputs%20may%20be%20considered%20to%20be%20not%20translatable%20%E2%80%94%20for%20example%20an%20image%20input%20of%20some%20component,-%F0%9F%9F%A2%20debt%3A%20currently%2C%20XB">lock an explicit input of a <u>single component instance</u></a> &mdash; e.g. a particular image component instance may have contain an image that should be the same across all translations (maybe it is a photo of the CEO), but another image component instance may have an image that should be translatable (e.g. locale-specific names for the same product: "Lotus" speculoos cookies in Belgium, "Biscoff" in the US)<br> <pre>diff --git a/config/schema/experience_builder.schema.yml b/config/schema/experience_builder.schema.yml<br>index 900a0b96e..ea54e8b34 100644<br>--- a/config/schema/experience_builder.schema.yml<br>+++ b/config/schema/experience_builder.schema.yml<br>@@ -264,6 +264,10 @@ experience_builder.component_tree_node:<br>&nbsp;&nbsp;&nbsp;&nbsp; inputs:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type: ignore<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label: 'Input values for each component in the component tree'<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; translatable: true<br>+&nbsp;&nbsp;&nbsp; untranslatable_inputs:<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type: ignore<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label: 'Untranslatable input values for each component in the component tree'<br> <br> # Based on core/assets/schemas/v1/metadata-full.schema.json#$defs.slotDefinition<br> # @todo Tighten &amp; add validation in https://www.drupal.org/project/experience_builder/issues/3519891<br>diff --git a/src/Plugin/Field/FieldType/ComponentTreeItem.php b/src/Plugin/Field/FieldType/ComponentTreeItem.php<br>index 6fc12e593..c9a95873b 100644<br>--- a/src/Plugin/Field/FieldType/ComponentTreeItem.php<br>+++ b/src/Plugin/Field/FieldType/ComponentTreeItem.php<br>@@ -96,6 +96,10 @@ use Symfony\Component\Validator\ConstraintViolationList;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'component_id',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ],<br>&nbsp;&nbsp;&nbsp;&nbsp; ],<br>+&nbsp;&nbsp;&nbsp; 'untranslatable_inputs' =&gt; [<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'label' =&gt; new TranslatableMarkup('Untranslatable component input values'),<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'translatable' =&gt; FALSE,<br>+&nbsp;&nbsp;&nbsp; ],<br>&nbsp;&nbsp; ],<br> )]<br> class ComponentTreeItem extends FieldItemBase {<br>@@ -257,7 +261,16 @@ class ComponentTreeItem extends FieldItemBase {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'not null' =&gt; TRUE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'inputs' =&gt; [<br>-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'description' =&gt; 'The input for this component instance in the component tree.',<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'description' =&gt; 'The inputs for this component instance in the component tree.',<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'type' =&gt; 'json',<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'pgsql_type' =&gt; 'jsonb',<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'mysql_type' =&gt; 'json',<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // @todo Change back to 'json' once https://www.drupal.org/i/3487533 is resolved.<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'sqlite_type' =&gt; 'text',<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'not null' =&gt; FALSE,<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ],<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'untranslatable_inputs' =&gt; [<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'description' =&gt; 'The untranslatable inputs for this component instance in the component tree.',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'type' =&gt; 'json',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'pgsql_type' =&gt; 'jsonb',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'mysql_type' =&gt; 'json',<br>@@ -333,6 +346,10 @@ class ComponentTreeItem extends FieldItemBase {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;setLabel(new TranslatableMarkup('Input values for each component in the component tree'))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;setRequired(TRUE);<br> <br>+&nbsp;&nbsp;&nbsp; $properties['untranslatable_inputs'] = DataDefinition::create('component_inputs')<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;setLabel(new TranslatableMarkup('Input values for each component in the component tree'))<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;setRequired(FALSE);<br>+<br>&nbsp;&nbsp;&nbsp;&nbsp; return $properties;<br>&nbsp;&nbsp; }</pre></li> <li>Related, add a new <code>asymmetrically_translated_explicit_inputs</code> setting to <code>type: experience_builder.component_source_settings.*</code> to allow <u>site builders</u> to <a href="https://www.drupal.org#:~:text=%F0%9F%94%B4-,feature%3A%20asymmetric%20translation%20will%20need%20some%20explicit%20inputs%20to%20be%20locked%2C%20because%20some%20explicit%20inputs%20may%20be%20considered%20to%20be%20not%20translatable%20%E2%80%94%20for%20example%20an%20image%20input%20of%20some%20component,-%F0%9F%9F%A2%20debt%3A%20currently%2C%20XB">lock an explicit input of <u>ALL instances of a component</u></a>:<br> <pre>diff --git a/config/schema/experience_builder.schema.yml b/config/schema/experience_builder.schema.yml<br>index 19722e2bc..bafe44264 100644<br>--- a/config/schema/experience_builder.schema.yml<br>+++ b/config/schema/experience_builder.schema.yml<br>@@ -266,6 +266,12 @@ experience_builder.component_source_settings.*:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type: string<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label: 'The intra-source ID of this component in this source'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; constraints: {}<br>+&nbsp;&nbsp;&nbsp; asymmetrically_translated_explicit_inputs:<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type: sequence<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label: 'The list of explicit inputs of this component that should only be stored in the default translation'<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sequence:<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # @todo Validate: must match a concrete explicit input<br>+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type: string</pre></li> </ul> </li> <li><u>storage efficiency</u> &mdash; see #13 through #15 on #3523842 for the most current overview (mid-May 2025). This is about deduplication of blobs of the per-component instance JSON blobs that contain the explicit inputs for that component instance. Doing both of these is best, but doing either one will diminish the impact of the other. <ul> <li>core: <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-13"><a href="https://www.drupal.org/project/drupal/issues/3469082" title="Status: Needs work">#3469082: Add way to "intern" large field item values to reduce database size by 10x to 100x for sites with many entity revisions and/or languages</a></span> </li><li>core: <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-1"><a href="https://www.drupal.org/project/drupal/issues/2770417" title="Status: Active">#2770417: Revision garbage collection and/or compression</a></span> </li><li>XB &mdash; probably we won't do this after 1 or both of the above land: <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-4"><a href="https://www.drupal.org/project/canvas/issues/3523842" title="Status: Postponed">#3523842: Spike: Explore storing a hash lookup of the ComponentInputs field property: one hash per component instance</a></span> </li></ul> </li> <li><span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3463996" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3463996</a></span> </li><li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-6"><a href="https://www.drupal.org/project/experience_builder/issues/3524345" title="Status: Closed (works as designed)">#3524345: Avoid deleting `PageRegion`s &amp; `Pattern`s when uninstalling field type-providing module: implement `::onDependencyRemoval()` , replace with default StaticPropSource</a></span> </li></ul> > Related issue: [Issue #3521002](https://www.drupal.org/node/3521002) > Related issue: [Issue #3520484](https://www.drupal.org/node/3520484) > Related issue: [Issue #3517941](https://www.drupal.org/node/3517941) > Related issue: [Issue #3523841](https://www.drupal.org/node/3523841)
issue