Customize the CKAN Theme

Introduction

The CKAN frontend can be fully customized by developing a CKAN theme. If you want more control, CKAN themes can customize all aspects of CKAN’s frontend, including changing any of CKAN’s templates or template snippets, adding custom snippets and helper functions, customizing CSS and JavaScript, and adding static files such as images. Follow the tutorial below to learn how to develop your custom CKAN theme.

Note

The information provided inside this section will explain the main topic that you have to consider creating a CKAN Theme extension. For more information about that we recommend to visit the CKAN documentation.

Creating a CKAN extension

A CKAN theme is simply a CKAN plugin that contains some custom templates and static files, so before getting started on our CKAN theme we’ll have to create an extension and plugin.

  • Use the ‘paster create’ command to create an empty extension:

    . /usr/lib/ckan/default/bin/activate
    cd /usr/lib/ckan/default/src
    paster --plugin=ckan create -t ckanext ckanext-example_theme
    
  • Create the file ckanext-example_theme/ckanext/example_theme/plugin.py with the following contents:

    import ckan.plugins as plugins
    
    
    class ExampleThemePlugin(plugins.SingletonPlugin):
            '''An example theme plugin.
    
            '''
            pass
    
  • Edit the entry_points in ckanext-example_theme/setup.py ckan.plugins:

    entry_points='''
            [ckan.plugins]
            example_theme=ckanext.example_theme.plugin:ExampleThemePlugin
    ''',
    
  • Run python setup.py develop:

    . /usr/lib/ckan/default/bin/activate
    cd /usr/lib/ckan/default/src/ckanext-example_theme
    python setup.py develop
    
  • Add the plugin to the ckan.plugins setting in your /etc/ckan/default/development.ini file:

    ckan.plugins = stats text_preview recline_preview example_theme
    
  • Restert CKAN

Customize CKAN’s HTML templates

Every CKAN page is generated by rendering a particular template. For each page of a CKAN site there’s a corresponding template file (for example the front page is generated from the ‘ckan/templates/home/index.html’ file).

In general you can customize the CKAN front-end replacing the default template files. Before that our plugin needs to register its own custom template directory containing templates file that override the default ones.

Edit the ckanext-example_theme/ckanext/example_theme/plugin.py file that we created earlier, so that it looks like this:

'''plugin.py

'''
import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit


class ExampleThemePlugin(plugins.SingletonPlugin):
        '''An example theme plugin.

        '''
        # Declare that this class implements IConfigurer.
        plugins.implements(plugins.IConfigurer)

        def update_config(self, config):

                # Add this plugin's templates dir to CKAN's extra_template_paths, so
                # that CKAN will use this plugin's custom templates.
                toolkit.add_template_directory(config, 'templates')

This new code does a few things:

  • It imports CKAN’s plugins toolkit module:

    import ckan.plugins.toolkit as toolkit
    

    The plugins toolkit is a Python module containing core functions, classes and exceptions for CKAN plugins to use.

  • It calls implements() to declare that it implements the IConfigurer plugin interface:

    plugins.implements(plugins.IConfigurer)
    

    This tells CKAN that our ExampleThemePlugin class implements the methods declared in the IConfigurer interface. CKAN will call these methods of our plugin class at the appropriate times.

  • It implements the update_config() method, which is the only method declared in the IConfigurer interface:

    def update_config(self, config):
    
        # Add this plugin's templates dir to CKAN's extra_template_paths, so
        # that CKAN will use this plugin's custom templates.
        toolkit.add_template_directory(config, 'templates')
    

    CKAN will call this method when it starts up, to give our plugin a chance to modify CKAN’s configuration settings. Our update_config() method calls add_template_directory() to register its custom template directory with CKAN. This tells CKAN to look for template files in ckanext-example_theme/ckanext/example_theme/templates whenever it renders a page. Any template file in this directory that has the same name as one of CKAN’s default template files, will be used instead of the default file.

Extending a Template

CKAN provides a custom Jinja tag {% ckan_extends %} that you can use to declare that our template file (i.e. home/index.html) extends the default template, instead of completely replacing it. In order to do that basically you have to edit your template file and add one line:

{% ckan_extends %}

When CKAN processes our template file, the {% ckan_extends %} tag tells it to process the default file first.

Replacing template blocks

Jinja templates can contain blocks that child templates can override. For example, CKAN’s default home/index.html template has a block that contains the Jinja and HTML code for the “featured groups” that appear on the front page by default:

{% block secondary_content %}
  <div class="row group-listing">
          {% for group in c.group_package_stuff %}
          <div class="span6">
                  <div class="box">
                  {% snippet 'snippets/group_item.html', group=group.group_dict,
                                         truncate=50, truncate_title=35 %}
                  </div>
          </div>
          {% endfor %}
  </div>
{% endblock %}

When a custom template file extends one of CKAN’s default template files using {% ckan_extends %}, it can replace any of the blocks from the default template with its own code by using {% block %}. For example:

{% ckan_extends %}

{% block secondary_content %}
  Hello block world!
{% endblock %}

Adding static files

You may need to add some custom static files to your CKAN site and use them from your templates, for example image files or any other static files that should be returned as-is by the webserver (as opposed to Jinja template files, which CKAN renders before returning them to the user).

By adding a directory to CKAN’s extra_public_paths config setting, a plugin can make a directory of static files available to be used or linked to by templates. Let’s add a static image file, and change the home page template to use our file as the promoted image on the front page.

Note

If you’re adding JavaScript or CSS files, consider using Fanstatic instead of extra_public_paths, to take advantage of extra features. See Adding JavaScript and CSS file using Fanstatic.

  • First, create a public directory in your extension with and put your image file in it:

    ckanext-example_theme/
      public/
            your-image.jpg
    
  • Then in plugin.py, register your public directory with CKAN by calling the add_public_directory() function. Add this line to the update_config() function:

    def update_config(self, config):
    
        # Add this plugin's templates dir to CKAN's extra_template_paths, so
        # that CKAN will use this plugin's custom templates.
        toolkit.add_template_directory(config, 'templates')
    
        # Add this plugin's public dir to CKAN's extra_public_paths, so
        # that CKAN will use this plugin's custom static files.
        toolkit.add_public_directory(config, 'public')
    
  • Now if you want to replace default images in CKAN pages, you need basically to override the related template/snippet file creating them inside the appropriate sub directory in your extension.

    For example for the prompted.html snippet:

                 ckanext-example_theme/
                   templates/
                         home/
                           snippets/
                                 promoted.html
    
    You can edit something like that::
    
                 {% ckan_extends %}
    
                 {% block home_image_caption %}
                   {{ _("CKAN's data previewing tool has many powerful features") }}
                 {% endblock %}
    
                 {# Replace the promoted image. #}
                 {% block home_image_content %}
                   <a class="media-image" href="#">
                         <img src="/your-image.jpg" alt="Featured image"
                                  width="420" height="220" />
                   </a>
                 {% endblock %}
    
    After calling `{% ckan_extends %}` to declare that it extends (rather than completely replaces) the default `promoted.html` snippet,
    this custom snippet overrides two of promoted.html's template blocks. The first block replaces the caption text of the promoted image.
    The second block replaces the <img> tag itself, pointing it at our custom static image file::
    
            {% block home_image_content %}
                   <a class="media-image" href="#">
                         <img src="/promoted-image.jpg" alt="Featured image"
                                  width="420" height="220" />
                   </a>
            {% endblock %}
    
  • You need to reload the browser page in orer to see the modifications:

Customizing CKAN’s CSS

Extensions can add their own CSS files to modify or extend CKAN’s default CSS. Create an example_theme.css file in your extension’s public directory:

ckanext-example_theme/
  public/
        example_theme.css

You can add here your custom CSS, for example:

.account-masthead {
        background-color: rgb(40, 40, 40);
}

To make CKAN use our custom CSS we need to override the base.html template, this is the base template which the templates for all CKAN pages extend, so if we include a CSS file in this base template then the file will be included in every page of your CKAN site. To do this you have to create the file:

ckanext-example_theme/
  templates/
        base.html

and put this Jinja code in it:

{% ckan_extends %}

{% block styles %}
  {{ super() }}
  <link rel="stylesheet" href="/example_theme.css" />
{% endblock %}