Problem/Motivation

We are not supporting Layout plugins and dealing directly with SDC. This is compliant with the goal of Display Builder to be "design system" native.

However:

Proposed resolution

If possible:

  • Derive each layout plugins as SDC plugins. Each region become a slot. Each setting becomes a prop
  • Filter available layout plugins by removing the ones provided by ui_patterns, to avoid duplicates

If the first proposal is not possible:

  1. Add a LayoutSource plugin for slots, implementing the SourceWithChoicesInterface.
  2. Filter available layout plugins by removing the ones provided by ui_patterns, to avoid duplicates
  3. Manage the layouts as components in the UI
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

pdureau created an issue. See original summary.

pdureau’s picture

Issue summary: View changes
pdureau’s picture

Issue tags: +BarCampPerpignan2025
mogtofu33’s picture

Title: [1.0.0-beta2] Layout plugins support » Layout plugins support
Issue tags: +display_builder-1.0.0-beta
pdureau’s picture

During the work on #3531523: Migration from Layout Builder (config only) we tried to import Layout plugins as SDC:

  • using hook_component_info_alter (forbidden by SDC but restored by UI Patterns) but any try to call an other plugin manager from this hook caused a PHP memory lilmit
  • adding a second discovery mechanism

Core's ComponentPluginManager::getDiscovery(): DirectoryWithMetadataPluginDiscovery is making the direct override of the method difficult, but we can override ComponentPluginManager::findDefinitions() and add the discovery here:

   protected function findDefinitions() {
-    $definitions = parent::findDefinitions();
+    $discovery = new DerivativeDiscoveryDecorator($this->getDiscovery());
+    $definitions = $discovery->getDefinitions();
      .... the rest of the content of parent::findDefinitions()

Then we can add a SDC component to deriver:

name: Layout
noUi: true
deriver: '\Drupal\display_builder_entity_view\Plugin\Derivative\LayoutComponent'
props:
  type: object
  properties: {}

Unfortunately, we have:

  • the usual difficulties with Twig template path with is calculated by and can't be manually set. We believe this can be solved.
  • The memory limit again when calling any other plugin manager!
pdureau’s picture

Issue summary: View changes
pdureau’s picture

pdureau’s picture

Assigned: Unassigned » pdureau

We may need a ComponentSource plugin type, like Canvas does, with 3 plugins:

pdureau’s picture

Status: Active » Needs work

Work has started. It is going well.

We may need a ComponentSource plugin type, like Canvas does.

It was not necessary, there is a more elegant way: a small SourceWithSlotInterface for source plugins.

pdureau’s picture

Work in progress.

The main job is to move SDC related logic from BuilderPanel::buildSingleComponent() and LayersPanel::buildSingleComponent() to the implementation of the new SourceWithSlotInterface in ComponentSource and LayoutSource.

Not much is left to do. Main tasks:

  • Layout forms are not saved properly yet.
  • TreePanel mus also be adapted
  • Playwright fails

To discuss:

  • We don't support layout regions in the source's ::settingsForm() method because Dispaly Builder doesn't need them there (they are managed by BuilderPanel LayersPanel and TreePanel). It may be confusing when the source is using in UI Patterns
  • Is it better to do #3568329: Leverage PluginSettingsInterface::settingsSummary() in LayersPanel before merging this one? The current state of the MR is totally removing LayersPanel::buildComponentSettingItem() and its is not clear what are we losing here (apart the component variant in the component label, which can be easily moved to ::settingsSummary())
pdureau’s picture

Issue summary: View changes
pdureau’s picture

Assigned: pdureau » mogtofu33
Status: Needs work » Needs review

Hi Jean,

Pipeline is green (I guess, still running) and work is nearly completed (a few things to check, TreePanel, some optional TODOs...) so it would be a good moment to discuss together about what has be done here.

It is an important work because it moves most of SDC specific logic from ApiController, Instance entity, LayersPanel, BuilderPanel and ContextualPanel to ComponentSource implementing SourceWithSlotInterface.

By that, we are allowing the introduction of other slot source plugins with slot support (like LayoutSource). Also, we are future proofing our usage of ComponentSource because we are not playing with the internal of its data structure (which is sometime weird) anymore.

pdureau’s picture

Assigned: mogtofu33 » pdureau
Status: Needs review » Needs work

ooops... a playwright fail. i will have a look.

mogtofu33’s picture

I added a link on a failing Playwright job on the right panel : External links > Playwright test report.
So you can see the problem, it's a service, seems you assume layout_discovery is enabled.

pdureau’s picture

Thanks a lot for the hint, Jean, those playwright test results are so useful.

I got the same error if I remove in my local dev environment:

$ ddev drush pmu layout_discovery
 [success] Successfully uninstalled: layout_discovery, layout_builder, navigation, layout_options, ui_patterns_layouts, ui_styles_layout_builder

Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "plugin.manager.core.layout". Did you mean one of these: "plugin.manager.condition", "plugin.manager.views.sort"? in Drupal\Component\DependencyInjection\Container->get() (line 157 of core/lib/Drupal/Component/DependencyInjection/Container.php).

It seems they are 2 different issues here:

  • If my display using a LayoutSource plugin (for example, entity view display after import from Layout builder), we need to implement DependentPluginInterface::calculateDependencies() to also avoid
    PluginNotFoundException once ServiceNotFoundException is fixed. This may trigger the removal of the display instead of block the uninstall of the module, but this issue is already covered by #3562750: Field, Theme or module uninstalled.
  • if my display is not using LayoutSource, this error is showing another issue, something missing in the logic of BlockLibraryPanel::getSources()

I will try to fix both in a single commit.

pdureau’s picture

Once the pipeline is green and the review is positive, let's not merge the work directly.

I will create an issue on UI Patterns project to move those files there:

  • src/SourceWithSlotsInterface.php
  • src/Plugin/UiPatterns/Source/ComponentSource.php
  • src/Plugin/UiPatterns/Source/LayoutSource.php

This will allow:

  • avoiding the ugly addition to src/Hook/UiPatternsHooks.php
  • enjoying the benefits of SourceWithSlotsInterface directly in UI Patterns, for example to simplify ComponentElementBuilder (we can add soemthing like SourceTreeRendererInterface::renderSources() which will be usable in Display Builder)
  • keeping all source plugins logic in a single codebase, which is strategic because we have big plans to reorganize and simplify the source system in UI Patterns in S2 2026 (without breaking much I hope)

Then, we can resume the work here, with a cleaner MR.

pdureau’s picture

Assigned: pdureau » mogtofu33
Status: Needs work » Needs review

Hi Jean,

I am not reproducing locally the playwright fails from pipeline:

    Error: expect(locator).toBeVisible() failed
    Locator: locator('.db-island-builder [data-slot-id="slot_1"]').first()
    Expected: visible

Locally, everything is OK expect a little KO ("Create override— Tests/entity_view.spec.ts:187") not related to the current work.

So I guess it is time for review :)

By the way:

  • We don't support layout regions in the source's ::settingsForm() method because Dispaly Builder doesn't need them there (they are managed by BuilderPanel LayersPanel and TreePanel). It may be confusing when the source is using in UI Patterns. Something will be done in a UI Patterns MR to mitigate that.
  • Is it better to do #3568329: Leverage PluginSettingsInterface::settingsSummary() in LayersPanel before merging this one? The current state of the MR is totally removing LayersPanel::buildComponentSettingItem() and its is not clear what are we losing here (apart the component variant in the component label, which can be easily moved to ::settingsSummary())

If you are OK, put the issue in "RTBC" without merging, I will switch to UI Patterns for the next step.

pdureau’s picture

By the way, to test this feature, you need to build a entity view display with Layout Builder using non SDC layouts first, and then switch to Display Builder. The layout sources will be imported.

mogtofu33’s picture

Assigned: mogtofu33 » pdureau
Status: Needs review » Needs work

You cannot reproduce locally because you have layout_builder enabled.
I still have the issue:

Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "plugin.manager.core.layout". Did you mean one of these: "plugin.manager.condition", "plugin.manager.views.sort"? in Drupal\Component\DependencyInjection\Container->get() (line 157 of core/lib/Drupal/Component/DependencyInjection/Container.php).
Drupal\display_builder\Plugin\UiPatterns\Source\LayoutSource::create() (Line: 21)
Drupal\Core\Plugin\Factory\ContainerFactory->createInstance() (Line: 85)
Drupal\Component\Plugin\PluginManagerBase->createInstance() (Line: 318)
Drupal\ui_patterns\SourcePluginManager->{closure:Drupal\ui_patterns\SourcePluginManager::createInstances():317}()
array_map() (Line: 316)
Drupal\ui_patterns\SourcePluginManager->createInstances() (Line: 187)
Drupal\ui_patterns\Element\ComponentFormBase::getSources() (Line: 368)
Drupal\ui_patterns\Element\ComponentSlotForm::buildAddSourceButton() (Line: 190)
Drupal\ui_patterns\Element\ComponentSlotForm::buildForm() (Line: 1065)
Drupal\Core\Form\FormBuilder->doBuildForm() (Line: 1128)
Drupal\Core\Form\FormBuilder->doBuildForm() (Line: 1128)
Drupal\Core\Form\FormBuilder->doBuildForm() (Line: 1128)
Drupal\Core\Form\FormBuilder->doBuildForm() (Line: 597)
Drupal\Core\Form\FormBuilder->processForm() (Line: 347)
Drupal\Core\Form\FormBuilder->buildForm() (Line: 130)
Drupal\display_builder\IslandPluginBase->build() (Line: 86)

Seems we call LayoutSource when out of layout context.

To reproduce:

  • Disable layout_builder, layout_discovery (and possibly layout_options)
  • Create a page layout
  • Drag a component
  • Check xhr request error
mogtofu33’s picture

Assigned: pdureau » mogtofu33
Status: Needs work » Needs review

Added a requirement on layout_discovery module in the LayoutSource, seems good, keep going on review.

pdureau’s picture

Assigned: mogtofu33 » pdureau
Status: Needs review » Needs work

Thanks a lot

pdureau’s picture

Assigned: pdureau » mogtofu33
Status: Needs work » Needs review

I don't know why I reassigned the issue to me when i wrote the "Thanks a lot" comment 🤔

Giving back to you

  • mogtofu33 committed 543d9f52 on 1.0.x authored by pdureau
    feat: #3531521 Layout plugins support
    
    By: pdureau
    By: mogtofu33
    
mogtofu33’s picture

Assigned: mogtofu33 » Unassigned
Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.