Skip to content

Building a Plugin

Andy Byers edited this page Sep 12, 2017 · 1 revision

This guide will walk through creating a basic plugin that will inject some content into the Article page to enable discussions via the DISQUS platform.

Create Directory Structure

  • disqus
    • templates
      • disqus
        • inject.html
        • index.html
    • init.py
    • plugin_settings.py
    • hooks.py

init.py

This can be left empty for this project.

plugin_settings.py

PLUGIN_NAME = 'Disqus Plugin'
DESCRIPTION = 'A plugin that injects the Disqus discussion tool into an article page.'
AUTHOR = 'Joe Bloggs' # Should be your name!
VERSION = 1.0
SHORT_NAME = 'disqus'
MANAGER_URL = 'disqus_index'

First we define the constants of the plugin, then we define an install function:

from utils import models


def install():
    new_plugin, created = models.Plugin.objects.get_or_create(name=SHORT_NAME, version=VERSION, enabled=True)

    if created:
        print('Plugin {0} installed.'.format(PLUGIN_NAME))
    else:
        print('Plugin {0} is already installed.'.format(PLUGIN_NAME))
        
    models.PluginSetting.objects.get_or_create(name='disqus_shortname', plugin=new_plugin, types='text',
                                               pretty_name='Disqus Shortname', description='Shortname of Disqus forum',
                                               is_translatable=False)
    models.PluginSetting.objects.get_or_create(name='disqus_enabled', plugin=new_plugin, types='boolean',
                                               pretty_name='Enable Disqus', description='Enable Disqus',
                                               is_translatable=False)

Ths block sets up the plugin and creates a couple of dummy settings for us.

This plugin will hook into the article_footer_block hook, so we should also define a hook for that.

def hook_registry():
    # On site load, the load function is run for each installed plugin to generate
    # a list of hooks.
    return {'article_footer_block': {'module': 'plugins.disqus.hooks', 'function': 'inject_disqus'}}

In hooks.py we define the function we referenced above 'inject_disqus' its purpose is to return HTML to the hook templatetag for insertion into the HTML of the main view template.

from django.template import loader, RequestContext

from plugins.disqus import plugin_settings
from utils import models, setting_handler


def inject_disqus(context):
    request = context.get('request')
    plugin = models.Plugin.objects.get(name=plugin_settings.SHORT_NAME)
    disqus_shortname = setting_handler.get_plugin_setting(plugin, 'disqus_shortname', request.journal)
    disqus_enabled = setting_handler.get_plugin_setting(plugin, 'disqus_enabled', request.journal)

    if not disqus_enabled.value:
        return

    template = loader.get_template('disqus/inject.html')
    disqus_context = {'disqus_shortname': disqus_shortname.processed_value}
    html_content = template.render(disqus_context)

    return html_content

The hook uses a template to render it's content and we add this to templates/disqus/inject.html:

<div id="disqus_thread"></div>

<script type="text/javascript">
  /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
  var disqus_shortname = '{{ disqus_shortname }}';
  var disqus_identifier = 'article.identifier.identifier'; // REPLACE
  var disqus_title = '{{ article.title }}’';  // REPLACE

  /* * * DON'T EDIT BELOW THIS LINE * * */
  (function() {
  var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
  dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
  (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
  })();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>

Next we need to define a management page and we start with urls.py:

from django.conf.urls import url

from plugins.disqus import views

urlpatterns = [
    url(r'^$', views.index, name='disqus_index'),
]

The name of our index page matches the defined MANAGER_URL above, this allows us to click through the plugin's admin page from the Plugins page in Manager.

Next we add the index view:

from django.shortcuts import render, redirect
from django.contrib import messages
from django.core.urlresolvers import reverse

from plugins.disqus import forms
from plugins.disqus import plugin_settings

from utils import setting_handler
from utils import models


def index(request):
    plugin = models.Plugin.objects.get(name=plugin_settings.SHORT_NAME)
    disqus_shortname = setting_handler.get_plugin_setting(plugin, 'disqus_shortname', request.journal, create=True,
                                                          pretty='Disqus Shortname', types='text').processed_value
    disqus_enabled = setting_handler.get_plugin_setting(plugin, 'disqus_enabled', request.journal, create=True,
                                                        pretty='Enable Disqus', types='boolean').processed_value
    admin_form = forms.DisqusAdminForm(initial={'disqus_shortname': disqus_shortname, 'disqus_enabled': disqus_enabled})

    if request.POST:
        admin_form = forms.DisqusAdminForm(request.POST)

        if admin_form.is_valid():
            for setting_name, setting_value in admin_form.cleaned_data.items():
                setting_handler.save_plugin_setting(plugin, setting_name, setting_value, request.journal)
                messages.add_message(request, messages.SUCCESS, '{0} setting updated.'.format(setting_name))

            return redirect(reverse('disqus_index'))

    template = "disqus/index.html"
    context = {
        'admin_form': admin_form,
    }

    return render(request, template, context)

And its template:

{% extends "admin/core/base.html" %}
{% load foundation %}

{% block page_title %}Disqus Admin{% endblock page_title %}
{% block title %}Disqus Plugin Admin{% endblock %}

{% block body %}
    <div class="box">
        <div class="content">
            <div class="row expanded">
                <div class="large-6 columns">
                    <form method="POST">
                        {% csrf_token %}
                        {{ admin_form|foundation }}
                        <button class="button success" type="submit">Save</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
{% endblock body %}

Wiki has moved to read the docs.

Clone this wiki locally