0

I'm creating a menu using snipets.

The menu items have the option to have a internal page as destination, or an external page (e.g. google.com).

The internal option works great, but the external option opens in a new tag, with the hostname attached to the external link:

http://127.0.0.1:8000/google.com

Not sure if something is wrong with my Orderable model or what's going on.

Code:

class MenuItem(Orderable):

    link_title = models.CharField(
        blank=True,
        null=True,
        max_length=50
    )
    link_url = models.CharField(
        max_length=500,
        blank=True,
    )
    link_page = models.ForeignKey(
        "wagtailcore.Page", #app y modelo de tu proyecto
        blank=True, 
        null=True,
        related_name="+",
        on_delete=models.CASCADE,
    )
    open_in_new_tab = models.BooleanField(default=False, blank=True,)

    page = ParentalKey("Menu", related_name="menu_items")

    panels = [
        FieldPanel("link_title"),
        FieldPanel("link_url"),
        PageChooserPanel("link_page"),
        FieldPanel("open_in_new_tab"),
    ]

    # @tood add properties 
    # link
    @property
    def link(self):
        if self.link_page:
            return self.link_page.url
        elif self.link_url:
            return self.link_url
        return "#"

    @property
    def title(self):
        if self.link_page and not self.link_title:
            return self.link_page.title
        elif self.link_title:
            return self.link_title
        return 'Missing title'

@register_snippet
class Menu(ClusterableModel):

    title = models.CharField(max_length=100)
    slug = AutoSlugField(populate_from="title", editable=True)

    panels = [
        MultiFieldPanel([
            FieldPanel("title"),
            FieldPanel("slug")
        ], heading="Menu"),
        InlinePanel("menu_items", label="Menu item")
    ]

    def __str__(self):
        return self.title

html:

<div class="collapse navbar-collapse" id="navbarCollapse">
        <ul>
            <li>
                <a href="/">Home</a>
            </li>
            {% for item in navigation.menu_items.all %}
                <li>
                    <a href="{{ item.link }}" class="nav-link" {% if item.open_in_new_tab %} target="_blank" {% endif %}>{{ item.title }}</a>
                </li>
            {% endfor %}
        </ul>
        <form class="form-inline ml-auto">
            <a href="" class="btn btn-outline-secondary">Ingresar</a>
            <a href="" class="btn btn-primary ml-2">Registro</a>
        </form>
    </div>

Found this other question, but it differs from my approache:

Making external links open in a new window in wagtail

Screenshoot:

enter image description here

Omar Gonzales
  • 3,806
  • 10
  • 56
  • 120

1 Answers1

2

Your code looks perfectly fine to me. It's just that you've entered your URL incorrectly. You'll need to add the http(s):// part so that the link will actually point to https://google.com instead of http://127.0.0.1:8000/google.com.

Also, I recommend to change link_url from a CharField to a URLField, for example:

class MenuItem(Orderable):

    # ...

    link_url = models.URLField(
        max_length=500,
        blank=True,
    )

The reason is because, although the two fields are identical, URLField has built-in logic (i.e. a validator) that checks for a correct URL pattern. So when you enter an invalid URL in the admin like google.com without https://, your menu won't save. Remember to run manage.py makemigrations and manage.py migrate once you have the field replaced.

acarasimon96
  • 293
  • 2
  • 8
  • Simon, is there a way to autocomplete the `https://` as most people don't type it? – Omar Gonzales May 30 '20 at 16:36
  • 1
    I don't think a `URLField` can do that for you. You just have to remember to add it yourself. Also, some sites don't use HTTPS, so it's wise to use `http://` instead if you don't remember the protocol the site uses. – acarasimon96 May 30 '20 at 17:27