An app to help you manage menus in your Wagtail projects more consistently.
Django template tags for rendering menus in templates with extensive customization options. WagtailMenus provides a comprehensive set of template tags for different menu types, each supporting various styling options, hierarchy levels, active state management, and custom template selection.
Load the template tags in your Django templates:
{% load menu_tags %}Renders the primary site navigation menu using the main menu model configured for the current site.
def main_menu(
context,
max_levels=None,
apply_active_classes=True,
allow_repeating_parents=True,
show_multiple_levels=True,
template='',
sub_menu_template='',
sub_menu_templates=None,
use_absolute_page_urls=False,
add_sub_menus_inline=None,
**kwargs
):
"""
Render the main navigation menu for the current site.
Args:
context: Template context
max_levels (int, optional): Maximum menu depth to display
apply_active_classes (bool): Add CSS classes for active menu items
allow_repeating_parents (bool): Show parent items in sub-menus
show_multiple_levels (bool): Display hierarchical menu structure
template (str): Custom template path for menu rendering
sub_menu_template (str): Template for sub-menu sections
sub_menu_templates (str|list): Comma-separated or list of sub-menu templates
use_absolute_page_urls (bool): Generate absolute URLs for pages
add_sub_menus_inline (bool): Render sub-menus inline vs separate
**kwargs: Additional context variables for templates
Returns:
Rendered menu HTML string
"""Renders a custom menu identified by a unique handle, commonly used for footer menus, sidebars, or special navigation sections.
def flat_menu(
context,
handle,
max_levels=None,
show_menu_heading=True,
apply_active_classes=False,
allow_repeating_parents=True,
show_multiple_levels=True,
template='',
sub_menu_template='',
sub_menu_templates=None,
fall_back_to_default_site_menus=None,
use_absolute_page_urls=False,
add_sub_menus_inline=None,
**kwargs
):
"""
Render a flat menu by its unique handle.
Args:
context: Template context
handle (str): Unique identifier of the flat menu to render
max_levels (int, optional): Maximum menu depth to display
show_menu_heading (bool): Display menu title/heading
apply_active_classes (bool): Add CSS classes for active items
allow_repeating_parents (bool): Show parent items in sub-menus
show_multiple_levels (bool): Display hierarchical structure
template (str): Custom template path for menu rendering
sub_menu_template (str): Template for sub-menu sections
sub_menu_templates (str|list): Templates for different sub-menu levels
fall_back_to_default_site_menus (bool): Use default site menu if handle not found
use_absolute_page_urls (bool): Generate absolute URLs for pages
add_sub_menus_inline (bool): Render sub-menus inline vs separate
**kwargs: Additional context variables for templates
Returns:
Rendered menu HTML string
"""Renders navigation for the current page's section, showing the hierarchical context within the site structure.
def section_menu(
context,
show_section_root=True,
show_multiple_levels=True,
apply_active_classes=True,
allow_repeating_parents=True,
max_levels=None,
template='',
sub_menu_template='',
sub_menu_templates=None,
use_absolute_page_urls=False,
add_sub_menus_inline=None,
**kwargs
):
"""
Render a section menu for the current page's section.
Args:
context: Template context
show_section_root (bool): Include the section root page in menu
show_multiple_levels (bool): Display hierarchical structure
apply_active_classes (bool): Add CSS classes for active items
allow_repeating_parents (bool): Show parent items in sub-menus
max_levels (int, optional): Maximum menu depth (default from settings)
template (str): Custom template path for menu rendering
sub_menu_template (str): Template for sub-menu sections
sub_menu_templates (str|list): Templates for different sub-menu levels
use_absolute_page_urls (bool): Generate absolute URLs for pages
add_sub_menus_inline (bool): Render sub-menus inline vs separate
**kwargs: Additional context variables for templates
Returns:
Rendered menu HTML string
"""Renders a menu of child pages for the current page, useful for showing sub-sections or related pages.
def children_menu(
context,
parent_page=None,
allow_repeating_parents=True,
apply_active_classes=False,
max_levels=1,
template='',
sub_menu_template='',
sub_menu_templates=None,
use_absolute_page_urls=False,
add_sub_menus_inline=None,
**kwargs
):
"""
Render a menu of child pages.
Args:
context: Template context
parent_page (Page, optional): Parent page (defaults to current page)
allow_repeating_parents (bool): Show parent items in sub-menus
apply_active_classes (bool): Add CSS classes for active items
max_levels (int): Maximum menu depth to display
template (str): Custom template path for menu rendering
sub_menu_template (str): Template for sub-menu sections
sub_menu_templates (str|list): Templates for different sub-menu levels
use_absolute_page_urls (bool): Generate absolute URLs for pages
add_sub_menus_inline (bool): Render sub-menus inline vs separate
**kwargs: Additional context variables for templates
Returns:
Rendered menu HTML string
"""Renders sub-menu sections within other menus, typically used for nested navigation structures. Must be used within the context of another menu tag.
def sub_menu(
context,
menuitem_or_page,
allow_repeating_parents=None,
apply_active_classes=None,
template='',
use_absolute_page_urls=None,
add_sub_menus_inline=None,
**kwargs
):
"""
Render a sub-menu for a specific menu item or page.
Args:
context: Template context
menuitem_or_page: Menu item or page to render sub-menu for
allow_repeating_parents (bool, optional): Show parent items in sub-menus (inherits from context)
apply_active_classes (bool, optional): Add CSS classes for active items (inherits from context)
template (str): Custom template path for sub-menu rendering
use_absolute_page_urls (bool, optional): Generate absolute URLs for pages (inherits from context)
add_sub_menus_inline (bool, optional): Render sub-menus inline vs separate (inherits from context)
**kwargs: Additional context variables for templates
Returns:
Rendered sub-menu HTML string
Raises:
SubMenuUsageError: If used outside of proper menu context
"""Helper functions used internally by the template tags.
def split_if_string(val, separator=','):
"""
Split a string into a tuple or return the value unchanged.
Args:
val: String to split or other value to return as-is
separator (str): Character to split on
Returns:
tuple: Split values if input was string, otherwise original value
"""{% load menu_tags %}
<!-- Simple main menu -->
{% main_menu %}
<!-- Main menu with custom settings -->
{% main_menu max_levels=3 apply_active_classes=True template='menus/main_menu.html' %}
<!-- Footer menu -->
{% flat_menu 'footer-links' max_levels=1 show_menu_heading=False %}<!-- Section navigation with custom template -->
{% section_menu show_section_root=True max_levels=2 template='menus/section.html' %}
<!-- Children menu for current page -->
{% children_menu max_levels=1 apply_active_classes=True %}
<!-- Multi-level menu with custom sub-menu templates -->
{% main_menu max_levels=4 sub_menu_templates='menus/sub_level_2.html,menus/sub_level_3.html' %}<!-- In a custom menu template -->
<ul class="menu">
{% for item in menu_items %}
<li class="menu-item{% if item.active %} active{% endif %}">
<a href="{{ item.href }}">{{ item.text }}</a>
{% if item.has_children_in_menu %}
{% sub_menu item template='menus/sub_menu.html' %}
{% endif %}
</li>
{% endfor %}
</ul>The menu template tags provide these context variables to templates:
<!-- Available in menu templates -->
{{ menu_items }} <!-- List of menu items -->
{{ current_page }} <!-- Current page object -->
{{ current_site }} <!-- Current site object -->
{{ menu_heading }} <!-- Menu title (flat menus) -->
{{ max_levels }} <!-- Maximum levels being displayed -->
{{ use_absolute_page_urls }} <!-- URL generation setting --><!-- Only show menu if it has items -->
{% flat_menu 'sidebar-menu' as sidebar_menu %}
{% if sidebar_menu %}
<nav class="sidebar-navigation">
{{ sidebar_menu }}
</nav>
{% endif %}
<!-- Show different menus based on section -->
{% if current_page.get_ancestors.0.slug == 'products' %}
{% section_menu template='menus/products_nav.html' %}
{% else %}
{% main_menu max_levels=2 %}
{% endif %}# Template tag parameter types
class TemplateTagParams:
context: dict
max_levels: int | None
apply_active_classes: bool
allow_repeating_parents: bool
show_multiple_levels: bool
template: str
sub_menu_template: str
sub_menu_templates: str | list[str] | None
use_absolute_page_urls: bool
add_sub_menus_inline: bool | None
handle: str # For flat_menu
show_menu_heading: bool # For flat_menu
show_section_root: bool # For section_menu
parent_page: 'Page' | None # For children_menuInstall with Tessl CLI
npx tessl i tessl/pypi-wagtailmenus