Skip to content

v3.3.0

Choose a tag to compare

@github-actions github-actions released this 01 Oct 11:51
· 16 commits to main since this release

What's Changed

Added

  • Menu locations — drupal_kit.menu_locations service, config object and admin form (Drupal\drupal_kit\Services\MenuLocations, Drupal\drupal_kit\Form\MenuLocationsForm, route drupal_kit.menu_locations at /admin/structure/menu/locations). A theme declares named menu "slots" under menu_locations: in its <theme>.info.yml — the same shape as regions: — a site builder assigns one menu to each slot on the new form (config shape locations: { <theme>: { <slot>: <menu machine name> } }), and the theme reads the slot's items as data through MenuLocations::items(), in EntityHelper::getMenu()'s own shape.

    One menu per slot in the default language, not one menu per slot per language. menu_link_content is itself content-translatable and EntityHelper::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): ?string has no langcode parameter and no per-language fallback logic as a result. items() render-caches its build in the render bin, 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, including languages:language_content and route.menu_active_trails:<menu> — into an optional accumulator; the stored cache entry itself carries config:drupal_kit.menu_locations too, 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_translation module — optional, never a hard dependency. The slot's config leaf type (drupal_kit.menu_locations.menu_name in config/schema/drupal_kit.schema.yml) is marked translatable: true with a form_element_class of the new Drupal\drupal_kit\FormElement\MenuSelect, which renders as a <select> of every menu on the "Translate" tab config_translation adds to the menu locations form (registered via the new drupal_kit.config_translation.yml mapper) — the same kind of widget the default-language form itself uses, not config_translation's own default (a plain textfield). Saved as a genuine language config override, resolved by ConfigFactory::get() transparently, with no special-casing in MenuLocations at all: menuName()/items() read the config through the injected factory exactly like any other value, so a site without config_translation (or language) installed simply never sees an override applied. That override follows the interface language (languages:language_interface, via core's LanguageConfigFactoryOverride), 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 in MenuLocations' own class docblock and the README for a site where it would not be.

    slots() and menuName() 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() installs drupal_kit.menu_locations (create-only, idempotent) for a site that already had the module enabled before this feature shipped, since config/install only 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 its administer menu permission rather than declaring a new one; adding it does not affect drush updb on 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 its menu_ui-owned base route) on a site that has not enabled menu_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