Raf Rasenberg
Raf Rasenberg

Reputation: 674

How to generate a custom link in Wagtail using Wagtail hooks

So I want to add a extra link in the Wagtail admin. I am following the docs (Register Admin Menu Item Hook) and using this hook to contruct a new menu item.

They use this hook for adding menu items:

@hooks.register('register_admin_menu_item')
def register_edit_menu_item():
    return MenuItem('Edit profile', 'edit_link', classnames='icon icon-folder-inverse', order=10000)

This should become a link which starts editing a page that is owned by the current logged in user. In a template I use this code to create a direct link to edit the profile of a user:

{% with request.user.owned_pages.all as pages %}
   {% if pages.exists %}
      {% for p in pages %}
         {% if p.get_parent.id == 17 %}
         <a class="list-group-item" href="/dashboard/pages/{{ p.id }}/edit/"><i class="fe-icon-edit mr-1 text-muted"></i>Edit profile</a>
         {% endif %}
      {% endfor %}
   {% endif %}
{% endwith %}

This is working just fine, it links directly to the page that it is supposed to link to. However how do I implement a condition like this where I generate the menu link based on the current logged in user?

I would think something like:

if request.user.owned_pages.exists():
   for p in request.user.owned_pages.all():
      if p.get_parent.id == 17:
         edit_link = "/dashboard/pages/" + p.id + "/edit/"

But how can I implement something like this into the Wagtail menu hook?

Upvotes: 1

Views: 1015

Answers (1)

gasman
gasman

Reputation: 25227

The default implementation of MenuItem assumes that the URL will be constant over all page requests, meaning that we can pass that fixed URL to the MenuItem constructor inside the register_admin_menu_item hook (that runs on server startup).

In your case, this isn't true, so you'll need to define a custom subclass of MenuItem. If you look at the code for MenuItem, you'll see that it implements a get_context(self, request) method to gather all the template variables it needs to render the menu item, including url. You can override this method to set a dynamic URL in place of the fixed one:

class EditProfileMenuItem(MenuItem):
    def get_context(self, request):
        context = super().get_context(request)

        edit_link = None
        if request.user.owned_pages.exists():
           for p in request.user.owned_pages.all():
              if p.get_parent().id == 17:
                 edit_link = "/dashboard/pages/" + p.id + "/edit/"

        if edit_link:
            context['url'] = edit_link

        return context

You can then use this subclass in the register_admin_menu_item hook, in place of MenuItem:

@hooks.register('register_admin_menu_item')
def register_edit_menu_item():
    return EditProfileMenuItem('Edit profile', 'edit_link', classnames='icon icon-folder-inverse', order=10000)

(Depending on your requirements you may want to override the is_shown method too, so that the menu item is hidden from those users who don't have a profile.)

Upvotes: 2

Related Questions