============================== Wagtailmenus 3.0 release notes ============================== .. contents:: :local: :depth: 1 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: .. code-block:: python 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) Menu models no longer have a ``use_specific`` field --------------------------------------------------- If you are subclassing ``AbstractMainMenu`` or ``AbstractFlatMenu`` to create custom menu models for your project, be sure to run Django's ``makemigrations`` command to remove the field from your custom models. Also be sure to remove any reference to the field from custom panels definitions or model methods. Menu tags no longer support the ``use_specific`` option ------------------------------------------------------- If you are using this option with any of the built-in template tags in your page or menu templates, you should remove the use of the option, as it is now defunct. For example, this: .. code-block:: html {% main_menu max_levels=2 use_specific=3 %} Should be simplified to: .. code-block:: html {% main_menu max_levels=2 %} 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 :ref:`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. ``Menu.pages_for_display`` now returns a dictionary --------------------------------------------------- If you have any custom menu functionality that depends on this value being a list or queryset, you'll need to update your code to account for the fact that the return value is now a dictionary of page objects, keyed by page id. In the case of main and flat menus, pages for the top-level menu items will also be included in the return value, in addition to those needed for sub menus. ``Menu.clear_page_cache()`` has been removed -------------------------------------------- Menu instances are intended to be rendered only once after being prepared for rendering. So, this method (originally added to aid with testing) no longer serves any useful purpose. ``Menu.set_use_specific()`` has been removed -------------------------------------------- This method is defunct, as specific page data is always used to render menus. ``Menu.set_max_levels()`` has been removed ------------------------------------------ A menu instance's ``max_levels`` attribute value is simply set directly in ``Menu.prepare_to_render()`` where required. Planned removals ---------------- Following a standard deprecation period a two minor releases, the following functionality has now been removed. ``Menu.get_instance_for_rendering()`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In an effort to make method names more reflective of their functionality, this method has been replaced by two methods: ``create_from_collected_values()`` and ``get_from_collected_values()``. The former is implemented on menu classes that are not model based (where instances must be created from scratch each time, for example: ``ChildrenMenu``, ``SectionMenu``, ``SubMenu``), and the latter is implemented on model-based menu classes, where a corresponding object must be retrieved from the database (so, ``AbstractMainMenu``, ``MainMenu``, ``AbstractFlatMenu`` and ``FlatMenu``). ``render_from_tag()`` automatically calls one or the other, depending on whether the class inherits from ``django.db.models.Model``. If you're using custom menu classes in your project, and are overriding ``get_instance_for_rendering()`` for any of those classes, you should update your code to override one of the new methods instead. Both of these new methods accept the same arguments, and return the same values, so the transition should be very easy. ``Menu.get_contextual_vals_from_context()`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In an effort to make method names more reflective of their functionality, and to help dissuade users from overriding functionality that could be subject to change in future, this method has been renamed to ``_create_contextualvals_obj_from_context()`` (becoming a private method in the process). ``Menu.get_option_vals_from_options()`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In an effort to make method names more reflective of their functionality, and to help dissuade users from overriding functionality that could be subject to change in future, this method has been renamed to ``_create_optionvals_obj_from_values()`` (becoming a private method in the process).