Skip to content

Menus & Widgets ​

Introduction ​

In WordPress a menu location or a widget area exists only once the theme declares it in functions.php — register_nav_menus(), register_sidebar() — so a new place for a menu, or a new column of widgets, is a code change and a deploy. In kitloom both are managed in the admin: a location is added on the Menu Locations screen, a widget zone on Appearance → Widgets, and each is there the moment it is saved — named, assigned a menu or filled with widgets, read by the theme and by every JSON client. No code, no deploy, no theme to edit.

What the theme does is draw: it asks for a location's menu or a zone's widgets by id. A theme may still declare the places it needs, so a fresh site has them; it does not have to.

A location is a place the site shows a menu in — the header, the footer, a social strip. The Menu Locations screen (Filament Appearance → Menu Locations, Nova Appearance → Menus → Menu Locations on the Nova skeleton; the package alone puts it in a Menus section) has two tabs:

  • Assigned Menus — one select per location, as WordPress's "Manage Locations": which menu is in it.
  • Locations — the locations themselves. Add location asks for an id (lower case letters, digits, - and _; it cannot be changed later) and a name. A location can be renamed and removed; removing one releases its menu, and the menu itself stays.

Where locations come from, in this order:

  1. The theme — kitloom-navigation.locations in config, and what the theme registers in bootTheme() with $this->app->make(MenuLocations::class)->register(['studio' => 'Studio header']), as register_nav_menus(). These are shown, named by the theme and cannot be removed; the admin says Declared by the theme next to them.
  2. The admin — the locations added on the Locations tab (the kitloom_menu_locations option). A name given here also wins over the theme's.
  3. The data — the keys nav_menu_locations already holds. A site brought over from WordPress shows its primary, footer, menu-1 before anybody declares them, named from the key until someone names them.

Every location, whatever its source, takes a menu on the Assigned Menus tab and in the menu form's Display location. The menu's items are edited on Menus.

Widget zones ​

A zone (WordPress's sidebar) is a column, a footer, a strip that holds widgets. Appearance → Widgets (Nova on the Nova skeleton; the package alone puts it under Settings) has a tab per zone, with its widgets in order and each one's form, and a last tab, Zones, where Add zone asks for an id and a name; a zone can be renamed and removed, and the widgets of a removed zone go to the inactive widgets, as in WordPress.

Where zones come from, in this order:

  1. The configuration — kitloom-wp-schema.sidebars, a list of ids.
  2. The theme — what it registers in bootTheme() with $this->app->make(SidebarRegistry::class)->register(['journal-sidebar' => 'Sidebar']), as register_sidebar(). Like the configured ones, these cannot be removed in the admin.
  3. The admin — the zones added on the Zones tab (the kitloom_sidebars option).
  4. The data — the keys of sidebars_widgets: a site brought over from WordPress shows its sidebars before anybody declares them.

The widgets themselves are the ones WordPress keeps (sidebars_widgets, widget_<type>): text and custom HTML, the standard widgets of the Widgets module, a theme's own types, and block widgets.

Showing them in a theme ​

The theme reads locations and zones by id through the page parts, so a location or zone added in the admin is drawn the moment the theme asks for it:

PartKeyGives
Which menu is in a locationKitloom\Navigation\Parts\LocationsmenuLocationsmenu('header') — the menu's slug, or null when the location has none
The menusKitloom\Navigation\Parts\Menusmenusget('main') — the menu's name and its items as a tree, or null; built when the theme first asks for that menu; in JSON and Vue props, the menus in the locations
A zone's widgetsKitloom\Site\Page\Parts\Widgetswidgetsin('promo') — each widget's id, type, title and drawn content
blade
@php($slug = $page->part(\Kitloom\Navigation\Parts\Locations::class)->menu('header'))
@php($items = $slug !== null ? ($page->part(\Kitloom\Navigation\Parts\Menus::class)->get($slug)['items'] ?? []) : [])
@foreach ($page->part(\Kitloom\Site\Page\Parts\Widgets::class)->in('promo') as $widget)
    <section class="widget">{!! $widget['content'] !!}</section>
@endforeach
js
// A Vue theme: the same parts as props.
const menu = (location) => page.props.menus?.[page.props.menuLocations?.[location]]?.items ?? [];
const widgets = (zone) => page.props.widgets?.[zone] ?? [];

A zone also goes into any text with the [sidebar id="promo"] shortcode, and one widget with [widget id="custom_html-4"] — see Shortcodes. In the page's JSON the same data is under menuLocations, menus and widgets; see Headless & APIs.

A site builder therefore adds a location or a zone in the admin and names it in the theme's template; a generated theme (Generating a Theme) comes with a header and a footer-links location, a social one with --with=social, and two zones, a sidebar and the footer, and draws a zone only while it has widgets.

AI agents ​

With AI agents installed, an agent whose user has edit_theme_options manages both as the admin does: menu_save puts a menu in its locations, and widgets_save sets a zone's widgets — and naming a zone the site does not have, with a label, adds it.

Next ​

  • Writing a Theme — a theme's bootTheme(), where it declares the places it needs.
  • Templates — every page part.
  • Widgets — the standard widgets and blocks.

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]