Making Wagtail pages more SEO friendly with Wagtail Metadata

Wagtail pages are great for creating a lot of rich content straight out of the box, but for SEO optimization, they need some tweaking.

Here, I subclass the Page model with some help from the wagtail-metadata plug-in.

This subclassed model becomes the base for all site pages and holds all the data for og metadata, twitter cards, page description etc..


With a new site, and an empty core app, start off with installing wagtail-metadata:

pip install wagtail-metadata

Add 'wagtailmetadata' to installed apps.

The plugin provides various mixins to use. Source code and documentation is available on GitHub:

GitHub - neon-jungle/wagtail-metadata: A tool to assist with metadata for social media and search engines.

A tool to assist with metadata for social media and search engines. - GitHub - neon-jungle/wagtail-metadata: A tool to assist with metadata for social media and search engines.

The title, image and description in the above block have been scraped directly from the metadata of that page. I'll show how's that's done in a later blog, but for now, what the wagtail-metadata plug in will do is allow the same to be created for any page you create.

To see in action, copy the URL of this page and paste into a new post on a dynamic site such as Facebook, you'll see the preview card without needing to submit the post.


I'm using a slightly modified version of the WagtailImageMetadataMixin class to make a new mixin.

I generally keep critical site-wide functionality like this in a separate 'core' app. I'll have all my site settings and hooks and other customisations here as much as is practical.

# core.models.py

from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _
from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel
from wagtail.core.models import Page
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtailmetadata.models import WagtailImageMetadataMixin

def get_image_model_string():
    try:
        image_model = settings.WAGTAILIMAGES_IMAGE_MODEL
    except AttributeError:
        image_model = 'wagtailimages.Image'
    return image_model

class SEOPageMixin(WagtailImageMetadataMixin, models.Model):
    search_image = models.ForeignKey(
        get_image_model_string(),
        null=True,
        blank=False,
        related_name='+',
        on_delete=models.SET_NULL,
        verbose_name=_('Search Image'),
        help_text=_("The image to use on previews of this page on external links and search results. \
                     This will also be the image used for blog posts on the index pages.")
    )

    summary = models.TextField(
        null=False,
        blank=False,
        help_text=_("A summary of the page to be used on index pages. \
                     If Meta Description is left blank, this text will be used on search results and link previews.")
    )

    content_panels = Page.content_panels + [
        FieldPanel('summary'),
    ]
    
    promote_panels = [
        MultiFieldPanel([
            FieldPanel('slug'),
            ImageChooserPanel('search_image'),
            FieldPanel('seo_title'),
            FieldPanel('search_description'),
        ], _('Common page configuration')),
    ]

    def get_meta_url(self):
        return self.full_url

    def get_meta_title(self):
        return self.seo_title or self.title

    def get_meta_description(self):
        return self.search_description or self.summary

    def get_meta_image(self):
        return self.search_image

    class Meta:
        abstract = True

The SEOPage mixin creates 'page summary' and 'search image' fields and adds them to the Content and Promote panels respectively.

The get_meta methods will be used later in the template to render all the metadata:

  • The meta title will come from the optional Title Tag (seo_title) on the Promote tab if filled in, otherwise from the page title.
  • The meta description will come from the optional Meta Description (search_description) on the Promote tab if filled in, otherwise the new Page Summary field will be used.

It's a good idea to use the Title Tag and Meta Description fields on the promote tab.

The Title Tag gives you the opportunity to add in common modifiers that can help in ranking (such as How to, Review, Best, Tips, Top, Find, Buy, Free, Easy) that you might not want appearing in the content title.

Summary provides an opportunity to give a meaningful page brief in your website (such as internal search results and product or blog page listing cards), while Meta Description allows you to enter a briefer, more Search Engine friendly summation - this becomes the description snippet on Google for instance. Google will show around 160 characters initially, with an ellipse to see more up to a point. It's a good idea to get your message in that first 160 characters.

Note, I took the opportunity to remove FieldPanel('show_in_menus'), from the Promote Panel as I use my own menu system that ignores this setting. If you use this, you'll need to add that back in.

We're not quite there as this is the mixin. We need to make the new SEO Page abstract class from this:

class SEOPage(SEOPageMixin, Page):
    pass

    class Meta:
        abstract = True

Your page models should all now inherit SEOPage (either directly or indirectly) so that, for example, your home page model might look like:

class HomePage(SEOPage):

    --- class property definition ---

    content_panels = SEOPage.content_panels + [
        --- class panels definition ---
 ]

Finally in the <head> section of your base.html (or in your head.html if you configure your site this way), load seo_metadata_tags and the appropriate code to place all of your metadata.

{% load static seo_metadata_tags %}
....
{% meta_tags as meta_tags %}
{% if meta_tags is not None %}{{ meta_tags }}{% endif %}
....

For this site (and others), I load a few more tags that may or not help with ranking - the shifting sands of Google algorithms might have made some of these obsolete already but they're included anyway:

<meta property="og:type" content="website"/>
<meta name="robots" content="index, follow, archive, imageindex, odp, snippet, translate, max-snippet:-1, max-image-preview:large, max-video-preview:-1" />
<meta name="target" content="all"/>
<meta name="audience" content="all"/>
<meta name="coverage" content="Worldwide"/>
<meta name="distribution" content="Global">
<meta name="rating" content="safe for kids"/>

og:type is wanted by Facebook in case you're using something like Facebook OAuth (as this site is), along with

<meta property="fb:app_id" content="fb-app-ID" />

I suspect the others in the list are redundant these days but there is nothing that will impact SEO negatively there.

The rendered meta tags for this page then become:

<meta name="robots" content="index, follow, archive, imageindex, odp, snippet, translate, max-snippet:-1, max-image-preview:large, max-video-preview:-1" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="How To: Making Wagtail pages more SEO friendly with Wagtail Metadata">
<meta name="twitter:description" content="Wagtail pages are great for creating a lot of rich content straight out of the box, but for SEO optimization, they need some tweaking.">
<meta name="twitter:image" content="https://www.enzedonline.com/media/images/Screenshot_2021-08-25_135400.original.png">
<meta property="og:url" content="https://enzedonline.com/en/tech-blog/making-wagtail-pages-more-seo-friendly-with-wagtail-metadata/" />
<meta property="og:title" content="How To: Making Wagtail pages more SEO friendly with Wagtail Metadata" />
<meta property="og:description" content="Wagtail pages are great for creating a lot of rich content straight out of the box, but for SEO optimization, they need some tweaking." />
<meta property="og:site_name" content="Enzed Online" />
<meta property="og:image" content="https://www.enzedonline.com/media/images/Screenshot_2021-08-25_135400.original.png" />
<meta property="og:image:width" content="688" />
<meta property="og:image:height" content="272" />
<meta itemprop='url' content='https://enzedonline.com/en/tech-blog/making-wagtail-pages-more-seo-friendly-with-wagtail-metadata/'/>
<meta itemprop="name" content="How To: Making Wagtail pages more SEO friendly with Wagtail Metadata">
<meta itemprop='description' content='Wagtail pages are great for creating a lot of rich content straight out of the box, but for SEO optimization, they need some tweaking.' />
<meta itemprop='image' content='https://www.enzedonline.com/media/images/Screenshot_2021-08-25_135400.original.png' />
<title>How To: Making Wagtail pages more SEO friendly with Wagtail Metadata</title>
<meta name="description" content="Wagtail pages are great for creating a lot of rich content straight out of the box, but for SEO optimization, they need some tweaking.">
<meta property="og:type" content="website"/>
<meta name="target" content="all"/>
<meta name="audience" content="all"/>
<meta name="coverage" content="Worldwide"/>
<meta name="distribution" content="Global">
<meta name="rating" content="safe for kids"/>

There's obviously a lot more that can be done to boost ranking from the perspective of site development, but this covers using the Wagtail Metadata plugin.

Happy coding! Feel free to leave any questions or feedback below in the comment section.

 
Comments
Sign In to leave a comment.

Next Post

Open Wagtail Rich Text Block Links in a New Tab

Open Wagtail Rich Text Block Links in a New Tab

You'd think this would be something you could do out of the box, but the makers of Wagtail have stated that this is against their philosophy and won't ever be implementing it. Here's a simple fix to circumvent that decision.

 

Previous Post

Wagtail Introduction

Wagtail Introduction

Wagtail is a leading open source CMS utilising Python and the Django framework. Tens of thousands of organisations worldwide, including Google, Mozilla, NASA, and the British NHS are now using Wagtail. In case you're new to Wagtail, and looking to learn as a developer, I've gathered some great learning resources here to get you started.