Wagtailで自由度の高い外部リンクを設定できるようにする[wagtail-draftail-snippet]

Wagtailの外部リンクの挿入で、relやtargetなどの属性を柔軟に設定できるようにします。

Wagtailで自由度の高い外部リンクを設定できるようにする[wagtail-draftail-snippet]

Wagtailではリンクの挿入が簡単にできるようになっていますが、外部のリンクを設定する際にはそのリンク先(href)の設定しかできません。例えばrel="nofollow"target="_blank"といった属性をリンクに追加することができません。

そのため、特定のタグを含めたキャンペーン用のリンクやアフィリエイト用のリンクを設定することができず、メディアの運営で不便なことがあります。また、アフィリエイトなどで同じ商品のリンクのURLが変わったりする場合にも、サイト内に多くのリンクを仕込んでいると修正が大変になります。リンクのパラメータを自由に設定でき、テンプレートのような形で保存しておいて使いまわせるような仕組みがあると便利です。

これは、wagtail-draftail-snippetというライブラリで解決できます。

WagtailにはSnippetと呼ばれる機能がありますが、このSnippetの機能を拡張してカスタマイズしたリンクを簡単に挿入できるようにするものになります。

インストール

pipでパッケージをインストールします。

$ pip install wagtail-draftail-snippet

settings.pyの変更

wagtail_draftail_snippetsettings.pyファイルのINSTALLED_APPSに追加します。

# settings.py

INSTALLED_APPS = [
    ...
    'wagtail_draftail_snippet',
    ...
]

RichTextBlockのfeaturesの設定

Wagtailでは、featuresという引数でRichTextBlockで利用できる機能を制限することができます。そのfeatures引数の中に、"snippet-link"という値を設定しましょう。

# models.py

# RichTextFieldで直接利用する場合の例
body = RichTextField(features=["bold", "italic", "h1", "h2", "h3", "snippet-link"]) # "snippet-link"を追加


# blocks.pyなどでクラスを継承する例
from wagtail.core import blocks

class RichTextBlock(blocks.RichTextBlock):
    def __init__(self):
        super().__init__(features=[
            'h2', 'h3', 'h4', 'bold', 'italic', 'link',
            'image', 'ol', 'ul', 'hr', 'embed', 'code',
            'snippet-link']) # この行を追加

    class Meta:
        template = "articles/blocks/richtext_block.html"
        icon = "doc-full"
        label = "RichText"

テンプレートの設定

リンクをどのように表示するかを設定するテンプレートを作成します。

wagtail-draftail-snippetでは、Snippetとして登録されているモデルと、それに対応する{app_name}/{model_name}_snippet_link.html という形式のテンプレートを設定すればRichText上でそのsnippetの情報を利用することができるようになります。

例えば、キャンペーンやアフィリエイトなどの情報を管理するadsという名前のDjangoアプリケーションがあるとしましょう。その中で、以下のようにAffiliateLinkという名前のモデルをWagtailのSnippetとして設定します。

# models.py

from django.db import models
from wagtail.admin.edit_handlers import FieldPanel
from wagtail.snippets.models import register_snippet

@register_snippet
class AffiliateLink(models.Model):
    """Affiliate Link"""
    snippet_name = models.CharField("Snippet Name", max_length=100)
    href = models.CharField(max_length=300)
    rel = models.CharField(blank=True, max_length=50)
    target  = models.CharField(blank=True, max_length=20)
    name = models.CharField(blank=True, max_length=50)

    panels = [
        FieldPanel("snippet_name"),
        FieldPanel("href"),
        FieldPanel("rel"),
        FieldPanel("target"),
        FieldPanel("name"),
    ]

    def __str__(self):
        return self.snippet_name

    class Meta:
        verbose_name = "Affiliate Link"
        verbose_name_plural = "Affiliate Links"

AffiliateLinkモデルをsnippetとして設定すると、adminから各要素を設定できるようになります。今回の例では、特定のキャンペーンページ用のリンクを設定しています。

wagtailのadminからAffiliateLinkを新規作成

新しいキャンペーン用のリンクを設定する

新しいsnippetを作成することができたら、これをRichText上で利用できるようにしましょう。wagtail-draftail-snippetで指定されている形でテンプレートを作成しましょう。

今回はadsアプリケーションのAffiliateLinkモデルをsnippetにしているので、ads/ affiliatelink_snippet_link.htmlという名前でテンプレートを作成する必要があります。AffiliateLinkモデルで設定した要素に合わせて、以下のようなテンプレートを作成します。

<a href="{{ object.href }}"
  {% if object.name %}name={{ object.name }}{% endif %}
  {% if object.rel %}rel="{{ object.rel }}"{% endif %}
  {% if object.target %}target={{ object.target }}{% endif %}
  >

<!-- 終了タグは書かない -->

このテンプレートでは、AffiliateLinkモデルの各要素から情報を取得し、もしそのパラメータがあればリンクの要素に付け加えています。必要があればAffiliateLinkモデルとテンプレートに要素を追加することでより柔軟な形に変更することも可能です。

ここまでの設定でRichTextからAffiliateLinkのsnippetから簡単にリンクを挿入できるようになりました。プレビュー画面などで確認すると、AffiliateLinkのsnippetから設定したパラメータでリンクが挿入されていることがわかります。

snippetで作成したリンクを挿入