How the menu system works

Basic concepts

Soft Roots

A soft root is a page that acts as the root for a menu navigation tree.

Typically, this will be a page that is the root of a significant new section on your site.

When the soft root feature is enabled, the navigation menu for any page will start at the nearest soft root, rather than at the real root of the site’s page hierarchy.

This feature is useful when your site has deep page hierarchies (and therefore multiple levels in its navigation trees). In such a case, you usually don’t want to present site visitors with deep menus of nested items.

For example, you’re on the page “Introduction to Bleeding”, so the menu might look like this:

School of Medicine
    Medical Education
    Departments
        Department of Lorem Ipsum
        Department of Donec Imperdiet
        Department of Cras Eros
        Department of Mediaeval Surgery
            Theory
            Cures
                Bleeding
                    * Introduction to Bleeding <current page>
                    Bleeding - the scientific evidence
                    Cleaning up the mess
                Cupping
                Leaches
                Maggots
            Techniques
            Instruments
        Department of Curabitur a Purus
        Department of Sed Accumsan
        Department of Etiam
    Research
    Administration
    Contact us
    Impressum

which is frankly overwhelming.

By making “Department of Mediaeval Surgery” a soft root, the menu becomes much more manageable:

Department of Mediaeval Surgery
    Theory
    Cures
        Bleeding
            * Introduction to Bleeding <current page>
            Bleeding - the scientific evidence
            Cleaning up the mess
        Cupping
        Leaches
        Maggots
    Techniques
    Instruments

Registration

The menu system isn’t monolithic. Rather, it is composed of numerous active parts, many of which can operate independently of each other.

What they operate on is a list of menu nodes, that gets passed around the menu system, until it emerges at the other end.

The main active parts of the menu system are menu generators and modifiers.

Some of these parts are supplied with the menus application. Some come from other applications (from the cms application in django CMS, for example, or some other application entirely).

All these active parts need to be registered within the menu system.

Then, when the time comes to build a menu, the system will ask all the registered menu generators and modifiers to get to work on it.

Generators and Modifiers

Menu generators and modifiers are classes.

Generators

To add nodes to a menu a generator is required.

There is one in cms for example, which examines the Pages in the database and adds them as nodes.

These classes are sub-classes of menus.base.Menu. The one in cms is cms.menu.CMSMenu.

In order to use a generator, its get_nodes() method must be called.

Modifiers

A modifier examines the nodes that have been assembled, and modifies them according to its requirements (adding or removing them, or manipulating their attributes, as it sees fit).

An important one in cms (cms.menu.SoftRootCutter) removes the nodes that are no longer required when a soft root is encountered.

These classes are sub-classes of menus.base.Modifier. Examples are cms.menu.NavExtender and cms.menu.SoftRootCutter.

In order to use a modifier, its modify() method must be called.

Note that each Modifier’s modify() method can be called twice, before and after the menu has been trimmed.

For example when using the {% show_menu %} template tag, it’s called:

This corresponds to the state of the nodes list before and after menus.templatetags.menu_tags.cut_levels(), which removes nodes from the menu according to the arguments provided by the template tag.

This is because some modification might be required on all nodes, and some might only be required on the subset of nodes left after cutting.

Nodes

Nodes are assembled in a tree. Each node is an instance of the menus.base.NavigationNode class.

A NavigationNode has attributes such as URL, title, parent and children - as one would expect in a navigation tree.

It also has an attr attribute, a dictionary that’s provided for you to add arbitrary attributes to, rather than placing them directly on the node itself, where they might clash with something.

Warning

You can’t assume that a menus.base.NavigationNode represents a django CMS Page. Firstly, some nodes may represent objects from other applications. Secondly, you can’t expect to be able to access Page objects via NavigationNodes. To check if node represents a CMS Page, check for is_page in menus.base.NavigationNode.attr and that it is True.