Problem/Motivation
Today, themers don't know what to do with menus and breadcrumb structures.
Obviously, it is not a slot, because it is not possible to put any renderable in it : are too much processes in the templates which expect a strict data structure.
But there is no settings type able to host this data, so themers are using fields anyway, and that's bad because the display can break if we put a renderable (scalar, markup, renderable object, render array, or list of renderable) into this field.
Example: Bootstrap 5
https://git.drupalcode.org/project/ui_suite_bootstrap/-/blob/5.0.x/templ...
fields:
items:
type: "render"
label: "Menu items"
description: "Full-height and lightweight navigation (including support for dropdowns)."
preview:
- title: "Home"
url: "https://example.com"
- title: "Library"
url: "https://example.com"
below:
- title: "Sub 1"
url: "https://example.com"
- title: "Sub 2"
url: "https://example.com"
- title: "Data"
url: "route:<nolink>"
https://git.drupalcode.org/project/ui_suite_bootstrap/-/tree/5.0.x/templ...
fields:
items:
type: "render"
label: "Items"
preview:
- text: "Home"
url: "#"
- text: "Library"
url: "#"
- text: "Data"
Example: Material 2
https://git.drupalcode.org/project/ui_suite_material/-/tree/2.0.x/templa...
fields:
items:
type: render
label: Menu items
description: A renderable list component.
preview:
- type: pattern
id: list
fields:
items:
- title: Home
url: "#"
attributes: {}
- title: Library
url: "#"
below:
- title: Sub 1
url: "#"
- title: Sub 2
url: "#"
- title: Data
url: "#"
https://git.drupalcode.org/project/ui_suite_material/-/tree/2.0.x/templa...
fields:
items:
type: render
label: Items
preview:
- text: Home
url: "#"
- text: Library
url: "#"
- text: Data
Proposed resolution
Create a new plugin: Drupal\ui_patterns_settings\Plugin\UIPatterns\SettingType\MenuSettingType which can host a menu-like structure common between menu.
Configuration form:
- menu (select), pick one menu or the breadcrumb
- level (quantity), Initial visibility level
- depth (quantity): Number of levels to display. This maximum number includes the initial level and the final display is dependant of the pattern template.
The plugin is taking the menu tree, do some parameters processes with the level & the depth, and send the data structure to the pattern.
No more menu--main.html.twig, menu--footer.html.twig... presenter templates!!! :)
So, we are here considering the breadcrumb as a flat menu, because the dat structure are very similar, in order to allow using a menu pattern as breadcrumb and the other way around.
It will be also the opportunity of preprocessing the URL objects from the plugin, so the themer will be able to avoid doing it in preprocess hooks. Example: https://git.drupalcode.org/project/ui_suite_bootstrap/-/blob/5.0.x/src/H...
This feature may replace the planned ui_patterns_menu module.
Remaining tasks
Propose a MR.
Do we implement the "The menu is only visible if the menu link for the current page is at this level or below it. " rule from SystemMenuBlock ?
User interface changes
On Layout Builder:

With ui_patterns_pattern_block:

API changes
Using this new plugin is optional, so it will have no impact on themes and site building not using it.
If a theme want to adopt it, they will need to:
- replace menu items and breadcrumb fields to settings, which will have no impact on the template structure, so it will not break anything
- update the structure of the breadcrumb pattern, to make it similar to the menu structure, so do the data conversion from the breadcrumb.html.twig presenter template
| Comment | File | Size | Author |
|---|
Issue fork ui_patterns_settings-3345071
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
pdureau commentedComment #3
pdureau commentedFirst commit: https://git.drupalcode.org/issue/ui_patterns_settings-3345071/-/commit/3...
Already working well. Tested with:
Next steps:
$this->handleInput([$form_id], $def, $form_type);Comment #5
grimreaperThanks a lot @pdureau for your work!
Either do the structure change in the breadcrumb.html.twig or a preprocess_hook if some variables or objects are not accessible or handleable in the Twig template.
Nice found, I was not aware of ui_patterns_pattern_block (I hope a release will come soon :)), but I think we will still require those presenter templates to have something working out-of-the-box for core menu blocks.
PS:
Please ensure that menu link attributes still works (#3338283-14: Bootstrap 5: dropdown is too complicated (outdated)), for active trail and or support of modules adding attributes/classes on ul / li / a.
Comment #6
pdureau commentedIs it possible to also manage pager (pagination) components with this plugin?
Like menu and breadcrumb, pagers have a strict structure of links and labels, so they belongs to props but are still managed as slots.
Source: https://api.drupal.org/api/drupal/core!modules!system!templates!pager.ht...
Other: https://api.drupal.org/api/drupal/core!modules!views!templates!views-min...
Example: https://git.drupalcode.org/project/ui_suite_bootstrap/-/blob/5.0.x/templ...
Only one field with a 2 level structure:
Example: https://git.drupalcode.org/project/ui_suite_material/-/blob/2.0.x/templa...
One field for each first level, a flat structure inside each:
Example: https://git.drupalcode.org/project/ui_suite_dsfr/-/blob/1.0.x/templates/...
Same as Bootstrap
This will also be the opportunity to remove this preprocess hook:
https://git.drupalcode.org/project/ui_suite_bootstrap/-/blob/5.0.x/src/H...
More complicated example: https://git.drupalcode.org/project/ui_suite_dsfr/-/blob/1.0.x/ui_suite_d...
Comment #7
grimreaperHi,
About pager, if the structure is ok, why not. But I am surprised of that.
Also will the plugin will not be too complicated and would it not be better to split into 3 plugins (also to have different settings options)?
- menus
-- depth of items shown
-- starting level
- breadcrumb
-- add home link?
-- display current page as title?
- pager
-- number of items displayed?
Because also technically when loading the links it is 3 different services:
- menu
- breadcrumb builder
- pager manager
Comment #8
pdureau commentedI would prefer to try without splitting the plugin first. I know it will be complicated, but it seems better to keep complexity here, in a stable generic codebase, and offer to the templates builder a single data structure.
This data structure will be a list of link items, optionally multi-levels. In a perfect world, they make their templates with this single structure, without overthinking, and the site builder decide which components they use for menus, breadcrumbs and pagers.
Comment #9
pdureau commentedComment #10
grimreaperHi,
Thanks both for the work done here, code and review.
I have added my comments.
pager part not implemented yet or did I miss something?
I hope to be able to help @pdureau with the implementation if needed (not only for pager, I mean).
Comment #11
pdureau commented@christian
Comment #12
pdureau commented"menu" setting type is renamed "links" because it targets also breadcrumbs and pagers
Comment #13
pdureau commentedSome news about the current work
Pierre's proposal
MR: https://git.drupalcode.org/project/ui_patterns_settings/-/merge_requests...
Naming
The setting type is called "menu" but we want "links"
Data structure
We followed the Drupal menu structure https://api.drupal.org/api/drupal/core!modules!system!templates!menu.htm...
With addition of link_attributes property (extracted from Url::getOptions()):
Same data structure for menus, links (for example language switcher), breadcrumb & pagers (system and views)
The plugin is doing the conversion. We took menu as base because it is the more capable.
Challenge
Cache management was tricky but we did it successfully with: PatternSettingBase::alterElement()
Twig filter
The controversial part. We introduced |convertToMenu() (TODO: rename to |normalizeLinks()) filter to do the conversion from presenter templates.
IMHO, it is OK to have such a filter because never used in components templates
Christian's rewrite
Branch: https://git.drupalcode.org/project/ui_patterns_settings/-/tree/ISSUE-334...
Naming
The setting type is called "link_lists", it is better than "menu" but IMHO "links" is even better.
New plugin type: SettingDataProvider
https://git.drupalcode.org/project/ui_patterns_settings/-/tree/ISSUE-334...
breadcrumb and menu are implemented with this plugin type, so the SettingType plugin is lighter
That's great because it is kind of similar to the target architecture of Ui Patterns 2 (source plugins more powerful and compatible with props) .
Issues
The Twig filter is missing. I know it is not nice but we need to find a way to accomodate presenter template. Maybe we can introduce a public static method in the setting type plugin, which will be easy to use in preprocess hooks inside each theme.
Where is the code related to pagers and links ?
The component cache is no longer invalidated when a menu change.
Comment #14
pdureau commentedComment #16
pdureau commentedA new MR based on Christian's rewrite: https://git.drupalcode.org/project/ui_patterns_settings/-/merge_requests/16
The Twig filter is not here anymore, so front developers will need to do preprocess in order to convert the links structure.
Examples:
I think it is OK to have such preprocess because they are:
Comment #17
pdureau commentedBefore we merge, I would like to discuss a bit about the links data structure.
We decided, and implemented, that:
link_attributes, because it is the more capableHowever, #3227824: Move the linkset functionality from the decoupled menus contributed module to core's system module tell us about an IETF's proposed linkset format already used by JSON API to avoid creating too many drupalism.
Example:
However, expected properties are not easily mappable:
hierarchystructure insteadtitlehrefAnd additional properties, sometimes used by components authors, are not mappable at all:
Comment #20
christian.wiedemann commentedThanks!
Comment #21
pdureau commentedhi,
We have a little issue with previews, so i am reopening the ticket.
In this setting type, the data we are storing in the config is not the same as the data we are sending to the component.
For example:
We have a the PatternSettingTypeInterface::settingsPreprocess() method which is doing this job of converting.
However, sometimes, we don't want this conversion. We want the raw data. For example, when we take it from the preview in the definition YML file.
Today, there is no data returned, empty array, so I am proposing this fix:
Is it too naive?
Comment #22
pdureau commentedOther issue.
Those 2 imports are missing from LinksSettingType :
And we need to use
toUriString()instead oftoString()So, this hook is not working properly:
Also, now we have used this setting type in Bootstrap 4, Bootstrap 5, Material Design, Mozilla Protocol, DSFR... it appears we may not need
convertPagerToMenu()&convertMiniPagerToMenu()Comment #23
pdureau commentedOther feedback.
While working on #3369769: Bootstrap 5: Convert menu, breadcrumb and pagers to the links prop type, we found some changes to do related to the menu API:
Source: /admin/structure/menu/manage/{menu_id}/add
Let's also check what is provided by https://www.drupal.org/project/menu_link_attributes integration
I will propose a MR
Comment #24
pdureau commented(removed)
Comment #26
pdureau commentedHello @christian, let's talk about this MR: https://git.drupalcode.org/project/ui_patterns_settings/-/merge_requests/18
Comment #27
pdureau commentedTested with:
Comment #29
pdureau commentedShipped in 2.2-alpha1
Comment #31
christian.wiedemann commented