sqwale
sqwale

Reputation: 575

Wagtail / Django inbuilt main menu

Started a project working with Wagtail CMS and what I understood of their principal of pages is that it is hierarchical leading me to the conclusion that pages are either parent/child related or siblings.

So how I have done it is have my main page landing and all other pages would be children of this page.

Here is my structure

                                   Home page
                        /             |                     \
                    News            About us               Events
                  /  |   \                             /     |     \
          n_item   n_item  n_item               e_item   e_item   e_item

So they are 6 types of pages

  1. Home page * (unique)
  2. News * (unique)
  3. n_item (News Item)
  4. About Us * (unique)
  5. Events * (unique)
  6. e_item (Event Item)

I then ticked the "Show in menus:" in the promote tab for the starred pages (*) in the above list.

The n_item and e_item will allow the editor (non technical) person to add as many of these pages as they wanted as they will be listed as part of the contents in the "News" and "Events" pages respectively.

Ideally the editor should not create siblings to Home Page,News, About us and events. Is it also possible to limit wagtails functionality of where editors can add pages if they are not super users?

But there doesn't seem to be a clear simple way (maybe a tag) to generate my menu. This is what I have found in my research.

  1. page url and slug url which i cant get to seem to work in every template that is not being referenced directly by that pages template. It would also mean its not that dynamic
  2. django-simple-menu doesn't seem dynamic to me as i have to manual link pages in code. Plus if this is the way wagtail intended to do it, it seems like a waste of maintaining page hierarchy internally.
  3. List item seems to have been deprecated but even if it wasn't it seems cumbersome for the same reasons as 1 and 2

Upvotes: 3

Views: 2418

Answers (2)

TomRavn
TomRavn

Reputation: 1244

I wanted to have automatically generated menu too but only first level with home. I might did something naive but it works. I am using Wagtail 2.5.1 and Django 2.2.2.

My Wagtail page structure look like this:

                                 Home page
                    /                                   \
                Blog                                   About
              /  |   \                            
      n_item   n_item  n_item 

I am using bootstrap4 so this is my nav in base.html template:

{% with root_p=request.site.root_page %}

        {# this is static item for home #}
        <ul class="navbar-nav ml-auto">
          <li class="nav-item">
                <a class="nav-link {% if '/' == request.path %} active {% endif %}" href="{{root_p.url}}">{{root_p.slug}}</a>
          </li>

        {# Here I am looping home's childrens #}
          {% for nav in root_p.get_children.live %}
              {% if nav.show_in_menus %}
                  <li class="nav-item">
                      <a class="nav-link {% if nav.slug in request.path %} active {% endif %}" href="{{nav.url}}">{{nav.slug}}</a>
                  </li>
              {% endif %}
          {% endfor %}
        </ul>

{% endwith %}

This is result: wagtail automatically generated menu

Now I am able to change slug, tick/untick "show in menus" and my bootstrap menu reflect these changes.

EDIT: My last answer does not solve custom order of menu items. We can order items by standard fields in Page model "first_published_at" or alphabetically by "title" name. But I needed make it custom. So I added custom integer field in each my page model. Then wagtail users can change order of menu items using "promote tab".

My current page structure look like this:

                             Home
                /              |           \
         Case studies      Services      Contact

My page model: (example of services only)

class ServicesPage(Page):

    template = "home/services.html"
    max_count = 1     
    subpage_types = []
    menu_order = models.IntegerField(default = 0, help_text = "Setup custom menu order")

    promote_panels = Page.promote_panels + [
       FieldPanel('menu_order'),
   ]
    class Meta:
        verbose_name = "Services"
        verbose_name_plural = "Services"

This is how it looks in promote tab of each page model enter image description here

Last step is edit navbar loop in base template:

{% with root_p=request.site.root_page %}
      {% for nav in root_p.get_children.specific.live|dictsort:"menu_order" %}
      {% if nav.show_in_menus %}
      <li class="nav-item {% if nav.slug in request.path %} active {% endif %}">
          <a class="nav-link" href="{{nav.url}}">{{nav.title}}</a>
      </li>
      {% endif %}
      {% endfor %}
{% endwith %}

For ordering I am using default django template filter dictsort. I guess it is not best way how to do that, but it works.

Upvotes: 2

tomd
tomd

Reputation: 1451

Have you seen https://github.com/rkhleics/wagtailmenus? It's designed to "manage and render multi-level navigation and simple flat menus in a consistent, flexible way".

Upvotes: 1

Related Questions