Navigation registry

How a content feature contributes one entry to the public main navigation, so the menu is composed from the installed features instead of hardcoded per product.


Table of contents

  1. What it is
  2. SPL rationale: the menu is derived, not configured
  3. The register_nav_item API
  4. How the theme composes the menu
  5. The admin Menus editor
  6. Legacy fallback: SITE_NAV
  7. See also

What it is

The navigation registry is a small framework module — splent_framework.nav.nav_registry — that lets each content feature declare one entry in the public main navigation from inside its init_feature(app).

A feature that owns a public-facing page (a blog, a projects listing, a team page) calls register_nav_item(...) when it loads. The theme then reads every declared entry and renders the main menu from them.

Unlike template hooks, which inject HTML into a layout slot, a nav entry is a plain piece of structured data (key, label, href, order, icon) that the theme is free to reorder, relabel, hide, or merge with custom links.


SPL rationale: the menu is derived, not configured

This is the key point. In a Software Product Line, the main menu is a point of variability, and that variability is resolved at derivation time from the set of installed features:

  • Install a content feature → its entry appears in the menu.
  • Remove it and re-derive the product → its entry disappears.

The product no longer carries a hand-written list of menu links. Two products built from different feature selections get different menus for free, because each menu is exactly the union of the entries its installed features registered. Adding a page to a product is the same action as adding the feature that owns it.


The register_nav_item API

Import it from splent_framework.nav.nav_registry and call it inside init_feature(app):

from splent_framework.blueprints.base_blueprint import create_blueprint
from splent_framework.nav.nav_registry import register_nav_item

post_bp = create_blueprint(__name__)

def init_feature(app):
    register_nav_item(key="post", label="Blog", href="/blog", order=50)

def inject_context_vars(app):
    return {}
Parameter Required Description
key yes Stable identifier for the entry, unique per feature (e.g. "post"). Used to dedupe and to reconcile against runtime overrides.
label yes Text shown in the menu (e.g. "Blog").
href yes Target URL or path (e.g. "/blog").
order no Sort weight; lower comes first. Defaults to 100.
icon no Optional icon identifier for themes that render icons. Defaults to None.

The call is idempotent by key: registering the same key twice does not create a duplicate entry.

Companion functions:

  • get_nav_items() — returns all declared entries, sorted by (order, label).
  • clear_nav_items() — empties the registry.

You rarely call these two yourself. The framework’s FeatureManager calls clear_nav_items() before loading features in register_features(), so the registry only ever holds the entries for this product’s installed features; the theme calls get_nav_items() at render time.

Other content features register their entries the same way — for example projects, tools, team, and events each call register_nav_item(...) from their own init_feature.


How the theme composes the menu

A declared entry is the base menu. On top of it sits an optional override that the admin can edit at runtime. The theme’s nav.py reconciles the two with compose_nav() every time a page renders:

  1. Start from the base entries returned by get_nav_items().
  2. Load the override JSON from the settings store under the key site_nav.
  3. Drop any override entry whose feature is no longer installed (its key is gone from the base).
  4. Append any newly-installed feature whose entry is not yet in the override.
  5. Apply _safe_href to custom links so external/relative URLs are well-formed.
  6. Dedupe by key.

This gives two levels of variability:

Level When What it controls
Derivation product:derive Which features registered an entry — the base menu.
Runtime admin Menus editor Reorder, hide, or relabel feature entries, and add custom external links.

Because reconciliation runs at render time, an override can never go stale: if a feature is removed and the product is re-derived, its entry simply disappears from the rendered menu even if it still lingers in the stored override.


The admin Menus editor

The runtime override is produced by the Menus editor shipped in splent_feature_theme at /admin/menus. The editor lets an administrator:

  • reorder feature entries,
  • hide entries they don’t want shown,
  • relabel entries, and
  • add custom external links.

It saves the result as an override JSON document in the settings store under the site_nav key. That document is exactly what compose_nav() reconciles against the base on every request — it never replaces the base, it layers on top of it.


Legacy fallback: SITE_NAV

If no installed feature registered a nav entry, the theme falls back to the product-level config app.config["SITE_NAV"] (the legacy site.nav list — see Theme system). This keeps older products rendering a menu during migration.

New products no longer set SITE_NAV: they let the menu derive from their installed content features and, optionally, refine it through the Menus editor.


See also


Back to top

splent. Distributed by an LGPL license v3. Contact us: drorganvidez@us.es