Guide: Customising output

{% seo_head %} renders everything in one call. When you need finer-grained control, such as rendering individual blocks in specific places or changing the HTML structure, you have two mechanisms: granular template tags and template overrides.


Granular template tags

Instead of {% seo_head %}, use individual tags to place each block exactly where you want it:

{% load seo_suite %}
<head>
  <meta charset="utf-8">
  {% seo_title %}
  {% seo_meta %}
  {% seo_canonical %}
  {% seo_hreflang %}
  {% seo_opengraph %}
  {% seo_twitter %}
  {% seo_jsonld %}
  {% seo_extra_head %}
</head>

Each tag reads the same seo context variable set by the context processor or SeoViewMixin. All tags are safe to call on a page with no SEO context; they render nothing.

Tag Renders
{% seo_title %} <title> element
{% seo_meta %} meta description, meta keywords, meta robots
{% seo_canonical %} <link rel="canonical">
{% seo_hreflang %} <link rel="alternate" hreflang> elements
{% seo_opengraph %} <meta property="og:*"> elements
{% seo_twitter %} <meta name="twitter:*"> elements
{% seo_jsonld %} <script type="application/ld+json"> blocks
{% seo_extra_head %} Extra fragments from registered renderers and the seo_head_rendering signal

Rendering h1 in the body

The h1 field is not rendered by any of the head tags (it goes in the <body>, not <head>). Access it via the context variable:

<h1>{{ seo.h1|default:seo.title }}</h1>

Overriding the HTML templates

Every partial template is stored under templates/seo_suite/ and can be overridden by placing your own version in any app that comes before seo_suite in INSTALLED_APPS, or in a DIRS-based template directory.

The template names and what they receive:

Template Context variables
seo_suite/head.html seo, jsonld_blocks (list of serialised strings), extra_fragments
seo_suite/_title.html seo
seo_suite/_meta.html seo
seo_suite/_canonical.html seo
seo_suite/_hreflang.html seo
seo_suite/_opengraph.html seo
seo_suite/_twitter.html seo
seo_suite/_jsonld.html jsonld_blocks
seo_suite/_extra_head.html extra_fragments

Example: add a custom title wrapper

Create templates/seo_suite/_title.html in your project:

{# myproject/templates/seo_suite/_title.html #}
{% if seo.full_title %}
<title>{{ seo.full_title }}</title>
<meta property="og:title" content="{{ seo.full_title }}">
{% endif %}

The seo object is a FinalizedSeoMetadata instance; see SeoMetadata attributes for all available properties.

Example: add a nonce to JSON-LD script tags

{# myproject/templates/seo_suite/_jsonld.html #}
{% for block in jsonld_blocks %}
<script type="application/ld+json" nonce="{{ request.csp_nonce }}">{{ block }}</script>
{% endfor %}

Adding extra head content via signals

The seo_head_rendering signal fires every time {% seo_head %} or {% seo_extra_head %} renders. Receivers can return an HTML string (or a list of strings) to be appended to the <head>:

# myapp/apps.py
from django.apps import AppConfig


class MyAppConfig(AppConfig):
    name = "myapp"

    def ready(self):
        from seo_suite.signals import seo_head_rendering
        seo_head_rendering.connect(my_head_fragment)


def my_head_fragment(sender, request, metadata, **kwargs):
    if metadata and metadata.canonical_url:
        return f'<link rel="preconnect" href="https://fonts.gstatic.com">'
    return None

Receivers may return a single string, a list of strings, or None. All non-empty strings are collected and rendered by {% seo_extra_head %}.


Accessing the seo object in templates

Whether you use {% seo_head %} or individual tags, the full FinalizedSeoMetadata object is available as {{ seo }} in any template that uses the seo_suite.context.seo context processor. Useful attributes:

{{ seo.full_title }}          {# title + title_suffix #}
{{ seo.title }}               {# title only #}
{{ seo.h1 }}                  {# page heading #}
{{ seo.meta_description }}    {# meta description string #}
{{ seo.canonical_url }}       {# absolute canonical URL #}
{{ seo.robots }}              {# robots directive #}
{{ seo.og }}                  {# dict of og:* values #}
{{ seo.twitter }}             {# dict of twitter:* values #}