Get started

How To

6 Dec 2023

How to fix a very common Wagtail UX issue in two lines of code

Make your users happier with this simple fix

Meagen Voss

Meagen Voss

Wagtail community manager

Imagine you're a content creator using Wagtail. You want to create a new blog. So you click to add a new child page to the main page for your blog. And then you get something like this:

This is a screenshot of a Wagtail menu asking you to choose from multiple page types, including Home page, Blog index page, blog tag index page, and form page.

Lemme tell you straight up Wagtail developers: this makes your content creators feel unloved. Because you're forcing them make an extra click when there is only one page type that will ever be used for the blog.

Now, Wagtail defaults to offering all available page types because, under some circumstances, multiple page types are needed. For example, you'll usually have a list of page types to choose from available under your root page listing. But many times, content creators don't need the full list of options and you're introducing unnecessary friction into their workflow by making them choose a page type.

Fortunately, it's very easy to spare your users from making that extra click. In this example, you only need to add two lines of code to fix the issue. We'll be modifying the example code for the BlogIndexPage and BlogPage models from the Wagtail Getting Started tutorial.

What we want to do is make it so that a new "Blog page" is created automatically when we click "Add child page" under the blog index page. So first, we're going to modify the BlogIndexPage model and configure a setting at the bottom of the model called subpage_types.

class BlogIndexPage(Page):
    intro = RichTextField(blank=True)

    def get_context(self, request):
        context = super().get_context(request)
        blogpages = self.get_children().live().order_by('-first_published_at')
        context['blogpages'] = blogpages
        return context

    content_panels = Page.content_panels + [
        FieldPanel('intro')
    ]

    subpage_types = ['blog.BlogPage']

The format for the configuration is appname.ModelName. Our app in this example is called blog, so that's why we configured subpage_types with blog.BlogPage. With that setting configured, only pages with the BlogPage model will be created when you add a new child page to BlogIndexPage.

Now, if "Blog page" is only ever going to be used for the blog, you want to make sure that it can't be used as a child page for another index page. For example, if you have another index page type called "Candy Index Page" that lists individual pages for candy types, you're probably not going to want to a content creator to use the blog page type for that index page.

So, to make sure pages with the BlogPage model are used only for pages with the BlogIndexPage, we're going to configure a setting called parent_page_types.

class BlogPage(Page):
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    # Add the main_image method:
    def main_image(self):
        gallery_item = self.gallery_images.first()
        if gallery_item:
            return gallery_item.image
        else:
            return None

    search_fields = Page.search_fields + [
        index.SearchField('intro'),
        index.SearchField('body'),
    ]

    content_panels = Page.content_panels + [
        FieldPanel('date'),
        FieldPanel('intro'),
        FieldPanel('body'),
        InlinePanel('gallery_images', label="Gallery images"),
    ]

    parent_page_types = ['blog.BlogIndexPage']

After adding blog.BlogIndexPage to parent_page_types, pages with the BlogPage model can now only be used by pages with the BlogIndexPage model.

There you go! All you need to do to spare your content creator from making extra clicks is two lines of code. Please go use these settings in your projects. It will make your content creators dance with joy. Or at least whine a little less about extra clicking. 😂

Like this tip? Get more tips and news in our newsletter. 👇