Problem/Motivation
Drupal core's three menu-related plugin managers (Drupal\Core\Menu\LocalTaskManager, Drupal\Core\Menu\LocalActionManager, Drupal\Core\Menu\ContextualLinkManager) key their plugin definition cache on the current language only:
$this->setCacheBackend($cache, 'local_task_plugins:' . $language_manager->getCurrentLanguage()->getId(), ['local_task']);Derivers running through these managers can read overridable configuration (e.g. Drupal\block\Plugin\Derivative\ThemeLocalTask reads system.theme.default), so their output varies per active domain — but the cached result does not, and the first domain to populate the cache freezes the answer for everyone else. Symptom proven on the block administration page (/admin/structure/block): the "default theme" tab title is identical across domains even when each domain has a different default theme override registered through domain_config_ui.
The parent issue #3588057 (in the domain project) currently lands the fix as a class swap in DomainServiceProvider::alter() on the always-loaded base module. This issue is the alternative location: a dedicated experimental submodule in domain_extras so the fix is opt-in by module install.
Why an extras submodule
- Cache fragmentation is opt-in. Every site running
domainbinds an active domain on every request. With the swap always on, the local task plugin definition cache fragments per domain regardless of whether anyone registered an overridable config — small footprint, but a cost imposed on users who get nothing for it. - Container rebuild semantics. Service-provider
alter()runs at container compile time. Toggling the fix would mean invalidating the cached container, which is heavier than the entity-type-definition clear we used indomain_config_ui_extras. Module install/uninstall does container rebuilds automatically and idiomatically — no additional subscriber needed. - Discoverability. "Domain Menu Extras (experimental)" on the modules list is more visible than a buried boolean flag.
- Consistency with the precedent set by #3588091 (
domain_config_ui_extras): layered, opt-in fixes for issues that go beyond the base module's contract live in their own_extrassubmodule. - Group related fixes. The same fix shape applies to all three Menu/* managers (LocalTask, LocalAction, ContextualLink). One submodule colocates them.
Proposed resolution
New submodule domain_menu_extras:
DomainAwareLocalTaskManager extends LocalTaskManager— re-binds the cache backend in its constructor with keylocal_task_plugins:LANGCODE:DOMAIN_ID(falling back toundbefore negotiation). This is the same code already proposed on #3588057, just relocated.- Same shape for
LocalActionManagerandContextualLinkManager:DomainAwareLocalActionManagerandDomainAwareContextualLinkManager. - A small
DomainMenuExtrasServiceProviderthat, inalter(), callssetClass()+addArgument('@domain.negotiation_context')for the three core service definitions. - Module info:
lifecycle: experimental,core_version_requirement: ^10.2 || ^11, depends ondomain:domain.
Per-request overhead is one extra string concatenation per manager instantiation; cache fragmentation is bounded by the number of domains actually visited.
Steps to reproduce
- Multi-domain site with
system.themeregistered as overridable throughdomain_config_uifor at least two domains, with different default themes per domain. - Visit
/admin/structure/blockon each domain — the "default theme" tab title is the same on both. - Enable this submodule,
drush cr. - The tab title reflects each domain's default theme.
Module info
- name: Domain Menu Extras
- package: Domain
- lifecycle: experimental
- core_version_requirement: ^10.2 || ^11
- dependencies: domain:domain
Related
Issue fork domain_extras-3588108
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 #3
mably commentedComment #4
mably commentedComment #6
mably commented