Repository navigation
v3.3.0
What's Changed
Added
-
Menu locations —
drupal_kit.menu_locationsservice, config object and admin form (Drupal\drupal_kit\Services\MenuLocations,Drupal\drupal_kit\Form\MenuLocationsForm, routedrupal_kit.menu_locationsat/admin/structure/menu/locations). A theme declares named menu "slots" undermenu_locations:in its<theme>.info.yml— the same shape asregions:— a site builder assigns one menu to each slot on the new form (config shapelocations: { <theme>: { <slot>: <menu machine name> } }), and the theme reads the slot's items as data throughMenuLocations::items(), inEntityHelper::getMenu()'s own shape.One menu per slot in the default language, not one menu per slot per language.
menu_link_contentis itself content-translatable andEntityHelper::getMenu()already returns the current content language's translation — a second, config-level menu-per-language assignment on top of that is a second translation mechanism for the same fact, and the two drift (a real downstream example carried two independently-translated copies of the same footer address, disagreeing).menuName(string $slot, ?string $theme = NULL, ?CacheableMetadata $collected = NULL): ?stringhas no langcode parameter and no per-language fallback logic as a result.items()render-caches its build in therenderbin, keyed by theme, slot AND the resolved menu name (so reassigning a slot to a different menu is reflected immediately rather than serving the old menu from a stale entry), and bubbles the full cache metadata — the assignment config's OWN cacheable metadata (CacheableMetadata::createFromObject($config), not hand-built — see below) plus the resolved menu's own tags/contexts, includinglanguages:language_contentandroute.menu_active_trails:<menu>— into an optional accumulator; the stored cache entry itself carriesconfig:drupal_kit.menu_locationstoo, so saving the assignment form invalidates an already-cached entry.A genuinely different menu per language is still possible, through Drupal's own native
config_translationmodule — optional, never a hard dependency. The slot's config leaf type (drupal_kit.menu_locations.menu_nameinconfig/schema/drupal_kit.schema.yml) is markedtranslatable: truewith aform_element_classof the newDrupal\drupal_kit\FormElement\MenuSelect, which renders as a<select>of every menu on the "Translate" tabconfig_translationadds to the menu locations form (registered via the newdrupal_kit.config_translation.ymlmapper) — the same kind of widget the default-language form itself uses, notconfig_translation's own default (a plain textfield). Saved as a genuine language config override, resolved byConfigFactory::get()transparently, with no special-casing inMenuLocationsat all:menuName()/items()read the config through the injected factory exactly like any other value, so a site withoutconfig_translation(orlanguage) installed simply never sees an override applied. That override follows the interface language (languages:language_interface, via core'sLanguageConfigFactoryOverride), not the content language menu items vary by — on a site like arkero, where both are negotiated from the same URL prefix, the distinction is invisible; documented inMenuLocations' own class docblock and the README for a site where it would not be.slots()andmenuName()default to the currently active theme (theme.manager), not the site's default theme, so a negotiated frontend theme reads its own slots; the admin form is the deliberate exception and always edits the site's default (frontend) theme.drupal_kit_post_update_menu_locations()installsdrupal_kit.menu_locations(create-only, idempotent) for a site that already had the module enabled before this feature shipped, sinceconfig/installonly runs on a fresh module install — it only ever installs the empty default, so the per-language-to-per-slot config shape change needed no migration on this (unreleased) branch. Replaces the "menu_block placed in a region only to pick a menu per language" antipattern several downstream themes grew independently — see the README's Menu locations section for the migration path off it, including translating the kept menu's links for every language the old per-language menu copies covered. New dependency:drupal:menu_ui, reusing itsadminister menupermission rather than declaring a new one; adding it does not affectdrush updbon a site that already has drupal_kit enabled — Drupal never re-validates an enabled module's dependencies against an updated.info.yml, and the route/permission both degrade gracefully (route inaccessible, local task hidden with itsmenu_ui-owned base route) on a site that has not enabledmenu_ui.
Pull Requests
- #153 — docs(changelog): r4032login is one of three 403 handlers, not a requirement
- #154 — feat(menu): menu locations, theme-declared slots with one menu each
Full Changelog: v3.2.0...v3.3.0