Problem/Motivation
At the moment every contrib module that needs to add/alter tree manipulators require to override Drupal\system\Plugin\Block\SystemMenuBlock
(or implement their own).
The only possible solution for contrib now is to override block class via hook_block_alter()
but when more then one module installed only last override wins.
This collisions affects following contrib modules:
- https://www.drupal.org/project/superfish
- https://www.drupal.org/project/menu_multilingual
- https://www.drupal.org/project/menu_block
- https://www.drupal.org/project/domain_entity to incorporate https://github.com/skilld-labs/domain_menu_access
- https://www.drupal.org/project/menu_per_role
- https://www.drupal.org/project/menu_item_visibility
- https://www.drupal.org/project/menu_manipulator
Proposed resolution
Implement a new hook that allows menu tree manipulators to be altered.
Remaining tasks
- Decide on hook name - hook_system_menu_tree_manipulators_alter()
- File change record
- Commit
User interface changes
No
API additions
Adds hook_system_menu_tree_manipulators_alter
to alter manipulators used in menu blocks
Data model changes
No
Comment | File | Size | Author |
---|---|---|---|
#47 | 2854013-nr-bot.txt | 144 bytes | needs-review-queue-bot |
#32 | interdiff-31-32.txt | 1.47 KB | flocondetoile |
#32 | 2854013-32.patch | 8.51 KB | flocondetoile |
#31 | 2854013-31.patch | 8.28 KB | flocondetoile |
#13 | 2854013-13.patch | 7.51 KB | jofitz |
Comments
Comment #2
tuutti CreditAttribution: tuutti as a volunteer commentedHere's an initial patch for this.
Comment #3
andypostQuickly skimmed patch and it looks awesome!!!
Comment #4
andypostThat works and covered with tests
Comment #5
tuutti CreditAttribution: tuutti as a volunteer commentedNot sure if it would be better to do this somewhere else as other parts of the core uses the same manipulators as well (like
\Drupal\Menu_ui\MenuForm::buildOverviewForm()
).Any thoughts?
Comment #6
andypostI think menu UI should be continue to display all items
Comment #7
alexpottThe issue summary is full of TBD and there is no change record.
Comment #9
andypostUpdated IS with current state
Looks better name could be more block-centric
hook_system_menu_block_manipulators_alter
instead ofhook_system_menu_tree_manipulators_alter
because we alter manipulators for block onlyComment #10
hitfactory CreditAttribution: hitfactory commented@andypost, thanks for the heads up about this issue.
This approach would solve my problem raised in #2466553-43: Untranslated menu items are displayed in menus as contrib modules such as Superfish and Menu Block that extend SystemMenuBlock and override the build() method could also call this alter hook.
Here are some other related contrib issues raised by @id.tarzanych that would benefit from this hook.
#2834616: Make menu tree manipulators alterable
#2834619: Integrate with Superfish module
But I also feel something like a generateMenuTree method that did just the following and included the alter hook would mean that contrib and custom modules would not need to call the alter hook separately as well as avoid having to duplicate the other lines of code to generate the tree.
The build method would then call this method.
@andypost, @tuutti, what do you think?
Comment #12
anavarreNo longer applies.
Comment #13
jofitz CreditAttribution: jofitz at ComputerMinds commentedRe-rolled.
Comment #14
dawehnerI'm wondering whether the better approach would be to actually make it easier to extend the specific block class, and well, add a method which returns the manipulators, that should be used.
Comment #15
tstoeckler#14 certainly makes sense, IMO. To go even further, IMO we could make the list of manipulators part of the configuration, but not expose it in the UI. Instead we could make it a
'#type' => 'value'
element, and then people could either use a form-alter if they want to give site builders any options to change something, or people can just edit the configuration directly if that's sufficient for them.Comment #16
andypost#14 & #15 both does not solve contrib issue when multiple modules needs to alter one block
Basic example is domain + superfish
Comment #17
andypostCR filed https://www.drupal.org/node/2940082
Comment #19
tstoecklerComment #20
tstoecklerNot endorsing the patch but #18 was just a random fail ;-)
Comment #21
dawehnerI'm curious, why is it not enough to change the templates etc. to get superfish working? I think documenting something like this in the issue summary would be a great step forward.
Comment #22
larowlanThere was no answer to the questions in #14 and #21
Comment #23
andypostExtending block lass is no go cos when you wanna enable domain module & allow it to be disablable you will need to update/remove all block configs to change plugin id
I thing duplicating blocks to provide a set of manipulators that should be site wide is bad idea
Comment #24
andypostUpdated summary with explanation and a list of contrib which affected
#14 is that if you have more then one module which overrides block class like https://github.com/skilld-labs/domain_menu_access/blob/8.x/domain_menu_a... then only last wins - no way to apply more then one override this way
As example #2847313: Discussion about merging the module with Menu block current language - menu_block & menu_multilingual both require to inject own manipulators ...and fail
#21 superfish - at the template level there's not enough information and it anyway will have collision if any other contrib will alter block, basically module require to manipulate menu structure instead of templates. Also it will have a huge performance impact when whole menu will be passed to template which supposed to have different structure.
Comment #25
Wim LeersHooks don't prevent collisions.
Why can't all those modules provide alternative menu blocks? For example, "Superfish menu block". If they want to, they can subclass the existing logic. We could refactor
\Drupal\system\Plugin\Block\SystemMenuBlock::build()
to not hardcode a list of manipulators, but instead have a method return those. Then they'd only need to subclass this method.So, concerns:
Comment #26
andypost@Wim Leers I mean "collisions" in block classes - each module replace
SystemMenuBlock
with own class implementation but requirement is to provide more then one manipulatorFor example I need to apply "domain manipulator" & "superfish" same time to the main menu & domain + menu_per_role to sidebar block https://cgit.drupalcode.org/menu_per_role/tree/src/MenuPerRoleLinkTreeMa...
Again they will replace block without ability to extend list of manipulators, also you can not override block depending on its plugin ID (which is extra feature to have)
hook will allow to have more then one manipulator to be added to extend core "hardcoded" list
Instead of hook maybe better to implement event?
would be great to add the block instance here as well to allow alter manipulators per block
Comment #27
dawehnerHere is an alternative suggestion. Let's move this list into something which is statically configureable, let's say a container parameter. Modules then can add new ones to all menu queries, without having a runtime dependency.
Comment #28
andypost@dawehner why you wanna make the list static? container param is good choice btw ...but still no ability to apply different set of modifiers per block instance. Event looks good compromise for speed instead of hook and static set
Comment #30
joelpittetNeeds a re-roll due to #2594425: Add the option in system menu block to "Expand all items in this tree" and I hope keeps this in mind #3018863: Make SystemMenuBlock's new constructor argument dependency optional
Comment #31
flocondetoileRe-rolled on latest dev. Always using an alter hook to modify the menu tree manipulators.
Comment #32
flocondetoileAdded a context in the alter hook as suggested in #28
Comment #35
malcolm_p CreditAttribution: malcolm_p commentedI believe this is a much needed feature, however it seems to me that altering of manipulators should be done more centrally within
\Drupal\Core\Menu\MenuLinkTree::transform()
otherwise this only works for menus rendered via SystemMenuBlock or extending blocks. This will fail to cover use cases such as rendering a menu directly within a theme / preprocess function. I've created #3091246 for this approachI would also be in favor of an event for this instead of an alter hook.
Comment #36
franzComment #37
gonssalI just needed to implement this and I was honestly surprised it wasn't possible. Looks like a must-have feature to me. Seeing this has been in the works for 3 years already, I thought I'd share what I found.
After reviewing both issues, I went with the event-based solution from @malcolm_p in #3091246. Events are the way forward, not adding new hooks. In my case I didn't even need to add a new manipulator, but just modify the $tree in my event subscriber. Very useful.
Not having this issue resolved is not only badly affecting multiple contrib projects, like the ones already mentioned, but it's making people find ways to do it however they can. Take this for example: #2535162, where the proposed solution is to override the
menu.link_tree service
. What happens if all the contrib projects do this?Comment #38
johnwebdev CreditAttribution: johnwebdev commentedThe problem here is inheritance. Wondering if we allowed block classes to be decorated this problem would be solved. Along with separating the manipulators to its separate method.
Comment #39
joachim CreditAttribution: joachim commentedHmm yes we need maintainer input on whether to go whether the alter hook solution here, or event solution at #2854013: Allow SystemMenuBlock tree manipulators to be altered.
Comment #40
orlando.thoenyJust a thought of mine 🤔Maybe it's a bad idea ;)
Couldn't this also be realized with a Plugin or tagged Service based approach?
Having a new plugin type, with a service that loads them. Which then can be used inside the
SystemMenuBlock
. And also for custom developments. Possibly also add a propertytypes
or however you may call it, in case a module needs it's own manipulators, that should not be used elsewhere. Would probably also need a weight/priority to know in which order to execute them.Something like this:
However this is probably not really good regarding BC?
Comment #47
needs-review-queue-bot CreditAttribution: needs-review-queue-bot as a volunteer commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #49
lauriiiComment #50
matthieuscarset CreditAttribution: matthieuscarset commentedThank you @lauriii for the link to the other issue in #49.
I think the solution proposed there is better than what we've done here.
I suggest we can close this current issue and continue work on the other.
What do you think?