Skip to content

Configurable mega-menu promo-tile images (URL-matched, locale-stable) #461

Description

@hta218

Summary

Let the content team assign a custom image to a mega-menu promo tile from global theme settings, and match that image to the tile by the tile's collection URL (locale-stable) with a breadcrumb-path fallback.

A promo tile is a childless menu item one level below a top-level nav entry — the square/landscape image card rendered at the end of a mega menu. Today its image comes from the linked collection's image (resource.image), which the content team can't change without affecting that collection's image everywhere else it's used.

Why match by URL (locale-stable)

A tile must be identified by something stable across markets. Menu item titles are localized per market, so identifying a tile by its title / breadcrumb only works on the market whose titles equal the configured value; on other locales the lookup misses and the tile falls back to the placeholder.

The tile's collection URL is handle-based and locale-stable. After normalizing away the locale path prefix, a single configured URL matches the same tile on every market.

Theme settings (global)

Per tile slot (N configurable pairs), three inputs:

  • Path (text, optional) — breadcrumb built from menu titles, e.g. Women / Clothing / Dresses. Legacy/fallback match.
  • URL (text, optional) — the tile's collection URL, pasted from any market, e.g. https://example.com/en-us/collections/dresses.
  • Image (image picker).

Matching logic

Build two lookups from settings — byUrl (normalized URL → image) and byBreadcrumb (normalized breadcrumb → image). At render, resolve each tile's image in priority order:

  1. URLbyUrl.get(normalizeMenuUrl(tile.url))
  2. BreadcrumbbyBreadcrumb.get(normalizeBreadcrumb(root / parentTitle / tileTitle))
  3. undefined → keep the existing fallback chain: resource.image → placeholder.

URL normalization

normalizeMenuUrl(url):

  • strip protocol + host (works for absolute and relative inputs);
  • strip a leading locale segment matching ^/[a-z]{2}-[a-z]{2} (e.g. /en-us, /de-at);
  • drop query string + hash, strip trailing slash, lowercase.

→ e.g. /collections/<handle>. Stripping the locale prefix is the crux: one pasted URL matches the tile on every market.

Backward compatibility

Additive and opt-in: the URL input is optional. With no URL set, tiles match by the path/breadcrumb exactly as today, so shipping the change does not alter existing behaviour — filling in URLs is a content-only step, no code change required.

Suggested touch points

  • Mega-menu image util: input-name helpers, normalizeMenuUrl, buildMegaMenuImageMap (returns { byUrl, byBreadcrumb }), getMegaMenuImage (URL-first, breadcrumb fallback).
  • Theme settings schema: a mega-menu images group with path + URL + image inputs per pair.
  • Header mega-menu components (desktop + mobile): pass the tile's URL into the image lookup.
  • Unit tests: normalizeMenuUrl (absolute/relative, locale prefix, query, trailing slash, casing), map building, and lookup priority.

Acceptance criteria

  • A tile with a configured URL renders its image on all markets, including non-default locales, matched by the locale-normalized URL.
  • A tile with only a path configured behaves as before.
  • A tile with neither falls back to the collection image, then the placeholder.

Metadata

Metadata

Assignees

Labels

Projects

Status
Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions