Wagtailmenus 3.0 release notes

What’s new?

Wagtailmenus now ALWAYS uses ‘specific’ page data to rendering menus

Previously, developers needed to specify how specific pages should be fetched when rendering menus. The purpose of this was to keep performance optimal in projects where access to specific field values or method overrides was unnecessary for rendering menus. However, this flexibility came with a trade off: Making an educated decision about which option to use required some in-depth understanding of how some things in Wagtail work. The options were also slightly different for between menu types, and were difficult to explain in a way that made sense to everyone.

The ‘default’ behaviour was also sub-optimal, as additional queries would often be made to fetch individual instances of MenuPage or AbstractLinkPage. If used quite widely, this could quietly push up the number of database queries to a point where fetching the specific pages in advance would have been far more performant.

In the case of ‘main’ and ‘flat’ menus, separate queries were also used to fetch page data for top and sub levels, resorting in two calls to get_base_page_queryset(), as well as individual queries to fetch specific page data for each top-level item.

These issues are all resolved by always fetching specific page data, and doing so as efficiently as possible, using a single call to PageQuerySet.specific(). While this may may will hurt performance slightly in some scenarios, from what I understand about how developers use wagtailmenus, performance should be improved in a lot of cases, and working with wagtailmenus should easier as a result of these changes.

See the upgrade considerations section below for notes on how these changes might affect your project.

Minor changes & bug fixes

  • Added support for Django 2.2 (no code changes necessary).

  • Added support for Wagtail 2.5 (no code changes necessary).

  • Added support for Wagtail 2.6 (no code changes necessary).

  • Added support for Wagtail 2.7.

  • Added support for Python 3.8.

  • Removed recommendation / automatic integration for wagtail-condensedinlinepanel.

  • Optimised ‘derive page from URL’ and ‘derive section root’ logic.

  • Fixed bug #329, which prevented level-specific template naming from working as specified in the docs.

  • Fixed bug #323, which prevented StreamField from working properly when creating or editing menus with custom item models.

Upgrade considerations

Changes to Menu.get_sub_menu_templates()

If you are overriding this method on a custom menu class you will need to update the method’s signature to accept a level argument with a default value of 2. If you are calling super().get_sub_menu_templates() from within the override method, you should also pass the level value through to that, like so:

MyCustomMenu(OriginalMenuClass):

    def get_sub_menu_templates(self, level=2):
        # your custom here
        ...
        # passing level on to super() version
        return super().get_sub_menu_templates(level)

Settings to control default ‘specific’ usage have been removed

If you are using either of the following settings to override default wagtailmenus behaviour in your project, you should clean up your settings file by removing the relevant lines, as they are now defunct.

  • WAGTAILMENUS_DEFAULT_CHILDREN_MENU_USE_SPECIFIC

  • WAGTAILMENUS_DEFAULT_SECTION_MENU_USE_SPECIFIC

Hooks no longer receive the use_specific keyword argument

If your project uses these hooks to conditionally change something based on this value, you should revise your code to assume that specific pages are always being used. If the use_specific argument is included in your hook function signature, you should probably remove from there also.

Changes to Menu.get_pages_for_display()

If you are using a custom main or flat menu class in your project that overrides this method, you should ensure your custom method is updated to fetch page data for top-level menu items as well as for sub levels ( use super() where possible, and modify the result of that).

You should also avoid referencing top_level_items or get_top_level_items() from within this method, as doing so will now result in a circular reference (use get_base_menuitem_queryset() to access menu item data instead).

Changes to Menu.get_base_menuitem_queryset()

This method now uses select_related() to prefetch a few page fields for menu items that link to pages. If you’re overriding this method, or using the menus_modify_base_menuitem_queryset hook to alter the queryset, you might want to review your code to ensure you’re not adding additional complexity to the query unnecessarily.

If you are doing anything to limit the result based on page-specific values, you should look at overriding get_base_page_queryset() instead, as any menu items linking to pages should only ever be displayed if the page data is included in that resulting queryset.

Planned removals

Following a standard deprecation period a two minor releases, the following functionality has now been removed.