How to fix a very common Wagtail UX issue in two lines of code
Make your users happier with this simple fix
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:
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. 👇
This Week in Wagtail
A weeklyish newsletter with Wagtail tips, news, and more.