.. include:: ./substitutions.rst

============================
Customizing CKAN's templates
============================

CKAN pages are generated from Jinja2_ template files. This tutorial will walk
you through the process of writing your own template files to modify and
replace the default ones, and change the layout and content of CKAN pages.

.. seealso::

   :doc:`/contributing/string-i18n`
     How to mark strings for translation in your template files.


-------------------------
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. For a detailed explanation of the steps below, see
:doc:`/extensions/tutorial`.

1. Use the ``paster create`` command to create an empty extension:

   .. parsed-literal::

      |activate|
      cd |virtualenv|/src
      paster --plugin=ckan create -t ckanext |extension_dir|

2. Create the file |plugin.py| with the following contents:

   .. literalinclude:: /../ckanext/example_theme/v01_empty_extension/plugin.py

3. Edit the ``entry_points`` in |setup.py| to look like this::

    entry_points='''
        [ckan.plugins]
        example_theme=ckanext.example_theme.plugin:ExampleThemePlugin
    ''',

4. Run ``python setup.py develop``:

   .. parsed-literal::

    cd |extension_dir|
    python setup.py develop

5. Add the plugin to the ``ckan.plugins`` setting in your |development.ini|
   file::

    ckan.plugins = stats text_view recline_view example_theme

6. Start CKAN in the development web server:

   .. parsed-literal::

    $ paster serve --reload |development.ini|
    Starting server in PID 13961.
    serving on 0.0.0.0:5000 view at http://127.0.0.1:5000

   Open the `CKAN front page`_ in your web browser.  If your plugin is in the
   :ref:`ckan.plugins` setting and CKAN starts without crashing, then your
   plugin is installed and CKAN can find it. Of course, your plugin doesn't
   *do* anything yet.


.. _template overriding:

---------------------------------
Replacing a default template file
---------------------------------

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 <https://github.com/ckan/ckan/blob/master/ckan/templates/home/index.html>`_
file, the ``/about`` page is generated from
`ckan/templates/home/about.html <https://github.com/ckan/ckan/blob/master/ckan/templates/home/about.html>`_,
the datasets page at ``/dataset`` is generated from
`ckan/templates/package/search.html <https://github.com/ckan/ckan/blob/master/ckan/templates/package/search.html>`_,
etc.

To customize pages, our plugin needs to register its own custom template
directory containing template files that override the default ones.
Edit the |plugin.py| file that we created earlier, so that it looks like
this:

.. literalinclude:: /../ckanext/example_theme/v02_empty_template/plugin.py

This new code does a few things:

1. It imports CKAN's :doc:`plugins toolkit </extensions/plugins-toolkit>`
   module:

   .. literalinclude:: /../ckanext/example_theme/v02_empty_template/plugin.py
      :start-after: import ckan.plugins as plugins
      :end-before: class ExampleThemePlugin(plugins.SingletonPlugin):

   The plugins toolkit is a Python module containing core functions, classes
   and exceptions for CKAN plugins to use. For more about the plugins toolkit,
   see :doc:`/extensions/tutorial`.

2. It calls :py:func:`~ckan.plugins.implements` to declare that it
   implements the :py:class:`~ckan.plugins.interfaces.IConfigurer` plugin
   interface:

   .. literalinclude:: /../ckanext/example_theme/v02_empty_template/plugin.py
      :start-after: # Declare that this class implements IConfigurer.
      :end-before: def update_config(


   This tells CKAN that our
   :py:class:`~ckanext.example_theme.v2.plugin.ExampleThemePlugin` class
   implements the methods declared in the
   :py:class:`~ckan.plugins.interfaces.IConfigurer` interface. CKAN will call
   these methods of our plugin class at the appropriate times.

3. It implements the
   :py:meth:`~ckan.plugins.interfaces.IConfigurer.update_config` method, which
   is the only method declared in the
   :py:class:`~ckan.plugins.interfaces.IConfigurer` interface:

   .. literalinclude:: /../ckanext/example_theme/v02_empty_template/plugin.py
      :pyobject: ExampleThemePlugin.update_config

   CKAN will call this method when it starts up, to give our plugin a chance to
   modify CKAN's configuration settings. Our
   :py:meth:`~ckanext.example_theme.v2.plugin.ExampleThemePlugin.update_config`
   method calls :py:func:`~ckan.plugins.toolkit.add_template_directory` to
   register its custom template directory with CKAN.
   This tells CKAN to look for template files in |templates_dir| 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.

Now, let's customize the CKAN front page. We first need to discover which
template file CKAN uses to render the front page, so we can replace it.
Set :ref:`debug` to ``true`` in your |development.ini| file::

    [DEFAULT]

    # WARNING: *THIS SETTING MUST BE SET TO FALSE ON A PRODUCTION ENVIRONMENT*
    debug = true

.. _debug footer:

Reload the `CKAN front page`_ in your browser, and you should see a *Debug*
link in the footer at the bottom of the page. Click on this link to open the
debug footer. The debug footer displays various information useful for CKAN
frontend development and debugging, including the names of the template files
that were used to render the current page:

.. image:: /images/debug-footer.png
   :alt: The debug footer.

The first template file listed is the one we're interested in::

 Template name: home/index.html
 Template path: /usr/lib/ckan/default/src/ckan/ckan/templates/home/index.html

This tells us that ``home/index.html`` is the root template file used to render
the front page. The debug footer appears at the bottom of every CKAN page, and
can always be used to find the page's template files, and other information
about the page.

.. note::

   Most CKAN pages are rendered from multiple template files.
   The first file listed in the debug footer is the root template file of the
   page. All other template files used to render the page (listed further down
   in the debug footer) are either included by the root file, or included by
   another file that is included by the root file.

   To figure out which template file renders a particular part of the page you
   have to inspect the
   `source code of the template files <https://github.com/ckan/ckan/tree/master/ckan/templates>`_,
   starting with the root file.

Now let's override ``home/index.html`` using our plugins' custom ``templates``
directory. Create the |templates_dir| directory, create a ``home`` directory
inside the ``templates`` directory, and create an empty ``index.html`` file
inside the ``home`` directory:

.. parsed-literal::

   |extension_dir|/
     ckanext/
       example_theme/
         templates/
           home/
             index.html  <-- An empty file.

If you now restart the development web server (kill the server using Ctrl-c,
then run the ``paster serve`` command again) and reload the `CKAN front page`_
in your web browser, you should see an empty page, because we've replaced the
template file for the front page with an empty file.


.. note::

   If you run ``paster serve`` with the ``--reload`` option, then it isn't
   usually necessary to restart the server after editing a Python file,
   a template file, your CKAN config file, or any other CKAN file. If you've
   added a new file or directory, however, you need to restart the server
   manually.


------
Jinja2
------

CKAN template files are written in the `Jinja2`_ templating language. Jinja
template files, such as our ``index.html`` file, are simply text files that,
when processed, generate any text-based output format such as ``HTML``,
``XML``, ``CSV``, etc. Most of the template files in CKAN generate ``HTML``.

We'll introduce some Jinja2 basics below. Jinja2 templates have many more
features than these, for full details see the
`Jinja2 docs`_.


.. _expressions and variables:

Expressions and variables
=========================

Jinja2 *expressions* are snippets of code between ``{{ ... }}`` delimiters,
when a template is rendered any expressions are evaluated and replaced with
the resulting value.

The simplest use of an expression is to display the value of a variable, for
example ``{{ foo }}`` in a template file will be replaced with the value of the
variable ``foo`` when the template is rendered.

CKAN makes a number of global variables available to all templates. One such
variable is :py:data:`app_globals`, which can be used to access certain global
attributes including some of the settings from your CKAN config file. For
example, to display the value of the :ref:`ckan.site_title` setting from your
config file you would put this code in any template file:

.. literalinclude:: /../ckanext/example_theme/v03_jinja/templates/home/index.html
   :language: django
   :start-after: Jinja variable example
   :end-before: End example

.. note::

   The :py:data:`app_globals` variable is also sometimes called :py:data:`g`
   (an alias), you may see :py:data:`g` in some CKAN templates.
   See :doc:`variables-and-functions`.

.. note::

   Not all config settings are available to templates via
   :py:data:`app_globals`. The :ref:`sqlalchemy.url` setting, for example,
   contains your database password, so making that variable available to
   templates might be a security risk.

   If you've added your own custom options to your config file, these will not
   be available in :py:data:`app_globals` automatically.
   See :ref:`accessing custom config settings from templates`.

.. note::

   If a template tries to render a variable or attribute that doesn't exist,
   rather than crashing or giving an error message, the Jinja2 expression
   simply evaluates to nothing (an empty string). For example, these Jinja2
   expressions will output nothing::

     {{ app_globals.an_attribute_that_does_not_exist }}

     {{ a_variable_that_does_not_exist }}

   If, on the other hand, you try to render an attribute of a variable that
   doesn't exist, then Jinja2 will crash. For example, this Jinja2 expression
   will crash with an
   ``UndefinedError: 'a_variable_that_does_not_exist' is undefined``::

     {{ a_variable_that_does_not_exist.an_attribute_that_does_not_exist }}

   See the `Jinja2 variables docs <http://jinja.pocoo.org/docs/templates/#variables>`_
   for details.

.. note::

   Jinja2 expressions can do much more than print out the values of variables,
   for example
   they can call Jinja2's `global functions <http://jinja.pocoo.org/docs/templates/#list-of-global-functions>`_,
   CKAN's :ref:`template helper functions <template helper functions>` and any
   :ref:`custom template helper functions <custom template helper functions>`
   provided by your extension,
   and use any of the 
   `literals and operators <http://jinja.pocoo.org/docs/templates/#expressions>`_
   that Jinja provides.

   See :doc:`variables-and-functions` for a list of variables and
   functions available to templates.


Tags
====

:ref:`ckan.site_title` is an example of a simple string variable.
Some variables, such as :ref:`ckan.plugins`, are lists, and can be looped over
using Jinja's ``{% for %}`` tag.

Jinja *tags* are snippets of code between ``{% ... %}`` delimiters that control
the logic of the template. For example, we can output a list of the currently
enabled plugins with this code in any template file:

.. literalinclude:: /../ckanext/example_theme/v03_jinja/templates/home/index.html
   :language: django
   :start-after: Jinja for-loop example
   :end-before: End example

Other variables, such as :ref:`ckan.tracking_enabled`, are booleans, and can be
tested using Jinja's ``{% if %}`` tag:

.. literalinclude:: /../ckanext/example_theme/v03_jinja/templates/home/index.html
   :language: django
   :start-after: Jinja if example
   :end-before: End example


Comments
========

Finally, any text between ``{# ... #}`` delimiters in a Jinja2 template is a
*comment*, and will not be output when the template is rendered:

.. literalinclude:: /../ckanext/example_theme/v03_jinja/templates/home/index.html
   :language: django
   :start-after: Jinja comment example
   :end-before: End example


-----------------------------------------------
Extending templates with ``{% ckan_extends %}``
-----------------------------------------------

CKAN provides a custom Jinja tag ``{% ckan_extends %}`` that we can use to
declare that our ``home/index.html`` template extends the default
``home/index.html`` template, instead of completely replacing it.
Edit the empty ``index.html`` file you just created, and add one line:

.. literalinclude:: /../ckanext/example_theme/v04_ckan_extends/templates/home/index.html
   :language: django

If you now reload the `CKAN front page`_ in your browser, you should see the
normal front page appear again. When CKAN processes our ``index.html`` file,
the ``{% ckan_extends %}`` tag tells it to process the default
``home/index.html`` file first.


----------------------------------------------
Replacing template blocks with ``{% block %}``
----------------------------------------------

Jinja templates can contain *blocks* that child templates can override.  For
example, CKAN's default ``home/layout1.html`` template (one of the files used
to render the CKAN front page) has a block that contains the Jinja and HTML
code for the "featured group" that appears on the front page:

.. literalinclude:: /../ckan/templates/home/layout1.html
   :language: django
   :start-after: {# Start template block example. #}
   :end-before: {# End template block example. #}

.. note::

   This code calls a :ref:`template snippet <snippets>` that contains the
   actual Jinja and HTML code for the featured group, more on snippets later.

.. note::

   The CKAN front page supports a number of different layouts: layout1,
   layout2, layout3, etc. The layout can be chosen by a sysadmin using the
   :ref:`admin page <admin page>`. This tutorial assumes your CKAN is set to
   use the first (default) layout.

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 %}``. Create the file
|layout1.html| with these contents:

.. literalinclude:: /../ckanext/example_theme/v05_block/templates/home/layout1.html
   :language: django

This file extends the default ``layout1.html`` template, and overrides the
``featured_group`` block.  Restart the development web server and reload the
`CKAN front page`_ in your browser.  You should see that the featured groups
section of the page has been replaced, but the rest of the page remains intact.

.. note::

   Most template files in CKAN contain multiple blocks.
   To find out what blocks a template has, and which block renders a particular
   part of the page, you have to look at the
   `source code of the default template files <https://github.com/ckan/ckan/tree/master/ckan/templates>`_.


------------------------------------------------------
Extending parent blocks with Jinja's ``{{ super() }}``
------------------------------------------------------

If you want to add some code to a block but don't want to replace the entire
block, you can use Jinja's ``{{ super() }}`` tag:

.. literalinclude:: /../ckanext/example_theme/v06_super/templates/home/layout1.html
   :language: django

When the child block above is rendered, Jinja will replace the
``{{ super() }}`` tag with the contents of the parent block.
The ``{{ super() }}`` tag can be placed anywhere in the block.


.. _template helper functions:

-------------------------
Template helper functions
-------------------------

Now let's put some interesting content into our custom template block.
One way for templates to get content out of CKAN is by calling CKAN's
*template helper functions*.

For example, let's replace the featured group on the front page with an
activity stream of the site's recently created, updated and deleted datasets.
Change the code in |layout1.html| to this:

.. literalinclude:: /../ckanext/example_theme/v07_helper_function/templates/home/layout1.html
   :language: django

Reload the `CKAN front page`_ in your browser and you should see a new activity
stream:

.. image:: /images/recently-changed-packages-activity-stream.png
   :alt: The recently changed packages activity stream.

To call a template helper function we use a Jinja2 *expression* (code wrapped
in ``{{ ... }}`` brackets), and we use the global variable :py:data:`h`
(available to all templates) to access the helper:

.. literalinclude:: /../ckanext/example_theme/v07_helper_function/templates/home/layout1.html
   :language: django
   :start-after: {% block featured_group %}
   :end-before: {% endblock %}

To see what other template helper functions are available, look at the
:doc:`template helper functions reference docs <template-helper-functions>`.


.. _custom template helper functions:

-----------------------------------------
Adding your own template helper functions
-----------------------------------------

Plugins can add their own template helper functions by implementing CKAN's
:py:class:`~ckan.plugins.interfaces.ITemplateHelpers` plugin interface.
(see :doc:`/extensions/tutorial` for a detailed explanation of CKAN plugins and
plugin interfaces).

Let's add another item to our custom front page: a list of the most "popular"
groups on the site (the groups with the most datasets).  We'll add a custom
template helper function to select the groups to be shown.  First, in our
``plugin.py`` file we need to implement
:py:class:`~ckan.plugins.interfaces.ITemplateHelpers` and provide our helper
function. Change the contents of ``plugin.py`` to look like this:

.. literalinclude:: /../ckanext/example_theme/v08_custom_helper_function/plugin.py

We've added a number of new features to ``plugin.py``. First, we defined a
function to get the most popular groups from CKAN:

.. literalinclude:: /../ckanext/example_theme/v08_custom_helper_function/plugin.py
   :pyobject: most_popular_groups

This function calls one of CKAN's *action functions* to get the groups from
CKAN.  See :doc:`/extensions/tutorial` for more about action functions.

Next, we called :py:func:`~ckan.plugins.implements` to declare that our class
now implements :py:class:`~ckan.plugins.interfaces.ITemplateHelpers`:

.. literalinclude:: /../ckanext/example_theme/v08_custom_helper_function/plugin.py
   :start-after: # Declare that this plugin will implement ITemplateHelpers.
   :end-before: def update_config(self, config):

Finally, we implemented the
:py:meth:`~ckan.plugins.interfaces.ITemplateHelpers.get_helpers` method from
:py:class:`~ckan.plugins.interfaces.ITemplateHelpers` to register our function
as a template helper:

.. literalinclude:: /../ckanext/example_theme/v08_custom_helper_function/plugin.py
   :pyobject: ExampleThemePlugin.get_helpers

Now that we've registered our helper function, we need to call it from our
template. As with CKAN's default template helpers, templates access custom
helpers via the global variable :py:data:`h`.
Edit |layout1.html| to look like this:

.. literalinclude:: /../ckanext/example_theme/v08_custom_helper_function/templates/home/layout1.html
   :language: django

Now reload your `CKAN front page`_ in your browser. You should see the featured
organization section replaced with a list of the most popular groups:

.. image:: /images/most-popular-groups.png
   :alt: The most popular groups.

Simply displaying a list of group titles isn't very good. We want the groups to
be hyperlinked to their pages, and also to show some other information about
the group such as its description and logo image. To display our groups nicely,
we'll use CKAN's *template snippets*...

.. _snippets:

-----------------
Template snippets
-----------------

*Template snippets* are small snippets of template code that, just like helper
functions, can be called from any template file. To call a snippet, you use
another of CKAN's custom Jinja2 tags: ``{% snippet %}``. CKAN comes with a
selection of snippets, which you can find in the various ``snippets``
directories in `ckan/templates/ <https://github.com/ckan/ckan/tree/master/ckan/templates>`_,
such as `ckan/templates/snippets/ <https://github.com/ckan/ckan/tree/master/ckan/templates/snippets>`_
and `ckan/templates/package/snippets/ <https://github.com/ckan/ckan/tree/master/ckan/templates/package/snippets>`_.
For a complete list of the default snippets available to templates, see
:doc:`template-snippets`.

``ckan/templates/group/snippets/group_list.html`` is a snippet that renders a
list of groups nicely (it's used to render the groups on CKAN's ``/group`` page
and on user dashboard pages, for example):

.. literalinclude:: /../ckan/templates/group/snippets/group_list.html
   :language: django

(As you can see, this snippet calls another snippet, ``group_item.html``, to
render each individual group.)

Let's change our |layout1.html| file to call this snippet:

.. literalinclude:: /../ckanext/example_theme/v09_snippet/templates/home/layout1.html
   :language: django

Here we pass two arguments to the ``{% snippet %}`` tag:

.. literalinclude:: /../ckanext/example_theme/v09_snippet/templates/home/layout1.html
   :language: django
   :start-after: {# Call the group_list.html snippet. #}
   :end-before: {% endblock %}

the first argument is the name of the snippet file to call. The second
argument, separated by a comma, is the list of groups to pass into the snippet.
After the filename you can pass any number of variables into a snippet, and
these will all be available to the snippet code as top-level global variables.
As in the ``group_list.html`` docstring above, each snippet's docstring
should document the parameters it requires.

If you reload your `CKAN front page`_ in your web browser now, you should see
the most popular groups rendered in the same style as the list of groups on
the ``/groups`` page:

.. image:: /images/most-popular-groups-snippet.png
   :alt: The most popular groups, rendered by a default snippet.

This style isn't really what we want for our front page, each group is too big.
To render the groups in a custom style, we can define a custom snippet...


---------------------------------
Adding your own template snippets
---------------------------------

Just as plugins can add their own template helper functions, they can also add
their own snippets. To add template snippets, all a plugin needs to do is add a
``snippets`` directory in its ``templates`` directory, and start adding files.
The snippets will be callable from other templates immediately.

.. note::

   For CKAN to find your plugins' snippets directories, you should already have
   added your plugin's custom template directory to CKAN, see :ref:`template
   overriding`.

Let's create a custom snippet to display our most popular groups, we'll put
the ``<h3>Most popular groups</h3>`` heading into the snippet and make it nice
and modular, so that we can reuse the whole thing on different parts of the
site if we want to.

Create a new directory |snippets_dir| containing a file named
``example_theme_most_popular_groups.html`` with these contents:

.. literalinclude:: /../ckanext/example_theme/v10_custom_snippet/templates/snippets/example_theme_most_popular_groups.html
   :language: django

.. note::

   As in the example above, a snippet should have a docstring at the top of the
   file that briefly documents what the snippet does and what parameters it
   requires. See :ref:`snippet docstrings best practice`.

This code uses a Jinja2 ``for`` loop to render each of the groups, and calls a
number of CKAN's template helper functions:

* To hyperlink each group's name to the group's page, it calls
  :py:func:`~ckan.lib.helpers.url_for`.

* If the group has a description, it calls
  :py:func:`~ckan.lib.helpers.markdown_extract` to render the description
  nicely.

* If the group doesn't have a description, it uses the :py:func:`_` function to
  mark the ``'This group has no description'`` message for translation.
  When the page is rendered in a user's web browser, this string will be shown
  in the user's language (if there's a translation of the string into that
  language).

* When rendering the group's number of datasets, it uses the
  :py:func:`ungettext` function to mark the message for translation with
  localized handling of plural forms.

The code also accesses the attributes of each group: ``{{ group.name }}`,
``{{ group.display_name }}``, ``{{ group.description }}``,
``{{ group.packages }}``, etc. To see what attributes a group or any other CKAN
object (packages/datasets, organizations, users...) has, you can use
:doc:`CKAN's API </api/index>` to inspect the object. For example to find out what
attributes a group has, call the :py:func:`~ckan.logic.action.get.group_show`
function.

Now edit your |layout1.html| file and change it to use our new snippet instead
of the default one:

.. literalinclude:: /../ckanext/example_theme/v10_custom_snippet/templates/home/layout1.html
   :language: django

Restart the development web server and reload the `CKAN front page`_ and you
should see the most popular groups rendered differently:

.. image:: /images/most-popular-groups-custom-snippet.png
   :alt: The most popular groups, rendered by a custom snippet.

.. warning::

   Default snippets can be overridden.
   If a plugin adds a snippet with the same name as one of CKAN's default
   snippets, the plugin's snippet will override the default snippet wherever
   the default snippet is used.

   Also if two plugins both have snippets with the same name, one of the
   snippets will override the other.

   To avoid unintended conflicts, we recommend that snippet filenames begin
   with the name of the extension they belong to, e.g.
   ``snippets/example_theme_*.html``.
   See :ref:`snippet filenames best practice`.

.. note::

   Snippets don't have access to the global template context variable,
   :py:data:`c` (see :doc:`variables-and-functions`).
   Snippets *can* access other global variables such as :py:data:`h`,
   :py:data:`app_globals` and :py:data:`request`, as well as any variables
   explicitly passed into the snippet by the parent template when it calls the
   snippet with a ``{% snippet %}`` tag.


-------------------------
HTML tags and CSS classes
-------------------------

Our additions to the front page so far don't look very good or fit in very well
with the CKAN theme. Let's make them look better by tweaking our template to
use the right HTML tags and CSS classes.

There are two places to look for CSS classes available in CKAN:

1. The `Bootstrap 2.3.2 docs <bootstrap>`_. All of the HTML, CSS and JavaScript
   provided by Bootstrap is available to use in CKAN.

2. CKAN's development primer page, which can be found on any CKAN site at
   ``/development/primer.html``, for example
   `demo.ckan.org/development/primer.html <http://demo.ckan.org/development/primer.html>`_.

   The primer page demonstrates many of the HTML and CSS elements available in
   CKAN, and by viewing the source of the page you can see what HTML tags and
   CSS classes they use.

Edit your ``example_theme_most_popular_groups.html`` file to look like this:

.. literalinclude:: /../ckanext/example_theme/v11_HTML_and_CSS/templates/snippets/example_theme_most_popular_groups.html
   :language: django

This simply wraps the code in a ``<div class="box">``,
a ``<header class="module-heading">``,
and a ``<section class="module-content">``. We also added Bootstrap's
``class="unstyled"`` to the ``<ul>`` tag to get rid of the bullet points.
If you reload the `CKAN front page`_, the most popular groups should look much
better.

To wrap your activity stream in a similar box, edit ``layout1.html`` to look
like this:

.. literalinclude:: /../ckanext/example_theme/v11_HTML_and_CSS/templates/home/layout1.html
   :language: django

Reload the `CKAN front page`_, and you should see your activity stream and
most popular groups looking much better:


.. image:: /images/html_and_css.png
   :alt: The activity stream and most popular groups, with better CSS.


.. _accessing custom config settings from templates:

-----------------------------------------------
Accessing custom config settings from templates
-----------------------------------------------

Not all CKAN config settings are available to templates via
:py:data:`app_globals`. In particular, if an extension wants to use its own
custom config setting, this setting will not be available. If you need to
access a custom config setting from a template, you can do so by wrapping the
config setting in a helper function.

.. seealso::

   For more on custom config settings, see
   :doc:`/extensions/custom-config-settings`.

.. todo::

   I'm not sure if making config settings available to templates like this is
   a very good idea. Is there an alternative best practice?

Let's add a config setting, ``show_most_popular_groups``, to enable or disable
the most popular groups on the front page. First, add a new helper function to
``plugin.py`` to wrap the config setting.

.. literalinclude:: /../ckanext/example_theme/custom_config_setting/plugin.py
   :language: python

.. literalinclude:: /../ckanext/example_theme/custom_config_setting/plugin.py
   :language: python
   :pyobject: show_most_popular_groups

.. note::

   Names of config settings provided by extensions should include the name
   of the extension, to avoid conflicting with core config settings or with
   config settings from other extensions.
   See :ref:`extension config setting names best practice`.

Now we can call this helper function from our ``layout1.html`` template:

.. literalinclude:: /../ckanext/example_theme/custom_config_setting/templates/home/layout1.html
   :language: django
   :start-after: is True, otherwise call the super block. #}

If the user sets this config setting to ``True`` in their CKAN config file,
then the most popular groups will be displayed on the front page, otherwise
the block will fall back to its default contents.
