Many sites have settings which are used all over the place. Instead of hardcoding them in the settings file, I use a different approach and make them configurable in the Wagtail admin. Wagtail provides the Site Settings option to do this.

First, start with defining the settings in your model class. Since they are site-wide in my case, I tend to put them in a separate app called base:

base/models.py

from django.db import models
from wagtail.contrib.settings.models import BaseSetting, register_setting

@register_setting(icon='mail')
class SocialMedia(BaseSetting):

    twitter = models.CharField(max_length=255)
    twitter.verbose_name = 'Username'

    twitter_sitename = models.CharField(max_length=255, blank=True)
    twitter_sitename.verbose_name = 'Site Name'

    twitter_description = models.TextField(blank=True)
    twitter_description.verbose_name = 'Site Description'

    twitter_image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        default=None,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    twitter_image.verbose_name = 'Site Images'

    facebook = models.URLField()
    facebook.verbose_name = 'URL'

    email = models.EmailField()

    github = models.CharField(max_length=255)
    github.verbose_name = 'Username'

    instagram = models.CharField(max_length=255)
    instagram.verbose_name = 'Username'

    linkedin = models.CharField(max_length=255)
    linkedin.verbose_name = 'Username'

    content_panels = [
        MultiFieldPanel(
            [
                FieldPanel('twitter'),
                FieldPanel('twitter_sitename'),
                FieldPanel('twitter_description'),
                ImageChooserPanel('twitter_image'),
            ],
            heading="Twitter",
        ),
        MultiFieldPanel(
            [FieldPanel('email')],
            heading="Email",
        ),
        MultiFieldPanel(
            [FieldPanel('facebook')],
            heading="Facebook",
        ),
        MultiFieldPanel(
            [FieldPanel('github')],
            heading="GitHub",
        ),
        MultiFieldPanel(
            [FieldPanel('instagram')],
            heading="Instagram",
        ),
        MultiFieldPanel(
            [FieldPanel('linkedin')],
            heading="LinkedIn",
        ),
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading="Social Media"),
    ])

This creates a new setting option in the settings menu which the admin can use to configure the different social media settings. It extends from BaseSetting which provides the core editing capabilities. I also configured a couple of content panels to group the information together.

If you go into the settings, you'll get a form like this:

Defining the settings is one thing, you need to be able to use them as well. The first thing you need to do is to register the settings context processor:

mysite/settings/base.py

TEMPLATES = [
    {
        ...
        'OPTIONS': {
            'context_processors': [
                ...
                'wagtail.contrib.settings.context_processors.settings',
            ]
        }
    }
]

You can use them in your templates through {{ settings }}:

{% load wagtailimages_tags %}

{% image settings.base.SocialMedia.twitter_image max-512x512 as twitter_image %}
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="{{ settings.base.SocialMedia.twitter_sitename }}">
<meta name="twitter:description" content="{{ settings.base.SocialMedia.twitter_description }}">
<meta name="twitter:site" content="@{{ settings.base.SocialMedia.twitter }}">
<meta name="twitter:image" content="{{ self.get_site.root_url }}{{ twitter_image.url }}" />

Note that the app name is used to reference them. Since I defined them in the app called base, I refer to them as:

{{ settings.base.SocialMedia.twitter_sitename }}

If they would have been defined in an app called blog, you would need to refer to them as follows:

{{ settings.blog.SocialMedia.twitter_sitename }}

You can also use them from within your Python code:

def view(request):
    social_media = SocialMedia.for_request(request)
    ...

Related Posts

  • Change the Wagtail site domain via a management command
  • Making publish the default action in Wagtail
  • Migrating your Wagtail site to a different database engine
  • Programatically creating redirects in Wagtail
  • Adding a panel to the admin homepage in Wagtail