Andrew Barrett
Andrew Barrett

Reputation: 19911

django-cms redirect top level menu to first child

I would like to redirect the top menu items in a page I'm writing to point at their children if they have any. E.g. this site has a top level About, with several CMS pages underneath. When a user clicks on about, I want to show the first child page under the top-level about menu.

I can do it like the below, but it feels wrong. I know I can do a static redirect, but I don't want to do that, as the first child might change (it's a CMS system after all) and I don't want the people entering data into the CMS to have to manage a redirect. So I prefer the below to a configured redirect.

This is a pretty common requirement, is there a standard way of doing this? I think I might be able to do it with a navigation modifier, so I might try that route next.

    <div style="display:none;">{% show_menu 0 1 1 %}</div>
    <div id="topmenu">
      <ul>
      {% for child in children %}
          <li>
          {% if child.children %}
          <a href="{{child.children.0.get_absolute_url}}">
          {% else %}
          <a href="{{child.get_absolute_url}}">
          {% endif %}
          {{ child.get_menu_title }}
          </a>
          </li>
      {% endfor %}
      </ul>
    </div>

About the above, I need to have the show_menu in there otherwise the data isn't there for my custom menu. Is there any way for this not to be needed?

The thing I dislike the most about the above, is that the /about/ page is still active. It's not the worst thing in the world if someone browses there, they'll get an empty page, but I'd rather that not happen. I think if I wrote a navigation extension the same disadvantage would be there. I guess I need a programmatic redirect to redirect to the first child if that page is hit. Thoughts? I can probably do it in template logic, but that seems crazy.

Upvotes: 2

Views: 1711

Answers (2)

benzkji
benzkji

Reputation: 1867

2018: updated version, that works in cms 3.4+ and new middleware style compatible available here. Once you added the /firstchild, you'll need to edit/publish the redirecting page in the cms pages's change list, as, you guess it, will redirect.


solution with middleware and custom redirect field value of "/firstchild", to trigger redirects.

  • plus: you won't have any blank pages
  • plus: it's flexible, as it allows pages that will not be redirected to subpages
  • plus: no action needed when the first child's url changes
  • minor drawback: there is always a redirect ( 301, though, not that bad ;)
  • minor drawback: configuration is a bit nerdy, as you will have to enter "/firstchild" into the "redirect" field. definitely not end-user friendly, but works. the cms itself doesnt provide a better solution at all (not even in 2018).

from django.shortcuts import redirect

# redirect to first subpage if the "redirect" field is exactly "_subpage"
class RedirectSubpageMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        if request.current_page:
            page = request.current_page
            if "slug" in view_kwargs and page.get_redirect() == "/firstchild":
                subpages = request.current_page.children.all()
                if subpages.count():
                    # can redirect! must make uri!
                    return redirect(subpages[0].get_absolute_url(), permanent=True)
        return None

Upvotes: 3

mcneo
mcneo

Reputation: 189

You might consider setting the CMS_REDIRECTS = True in the settings.py file.

Then you can go into the /about/ page in the admin and add the redirect to /about/child-page

Note: I haven't actually tried this, I just happened to stumble across this information this morning.

Upvotes: 3

Related Questions