.. _intro-tutorial:

=================
Merengue Tutorial
=================

In this tutorial, we will:

    * Develop a Merengue project.
    * Develop a Merengue plugin.
    * Start managing content inside Merengue as an editor.

Creating a Project
==================

We will assume you have :ref:`Merengue installed <topics-install>` and that you
want to create a `Merengue CMS`_ website (check out the
`merengueprojectorg`_ directory in the repository for a working example).

.. _merengueprojectorg: http://dev.merengueproject.org/browser/sites/merengueprojectorg
.. _Merengue CMS: http://www.merengueproject.org

Let's start the project:

.. code-block:: bash

    $ merengue-admin.py startproject merengueprojectorg

This command will create a ``merengueprojectorg`` directory, containing these files
and directories::

    .
    |-- ...
    |-- settings.py
    |-- urls.py
    |-- apps/
    |   `-- website/
    |-- fixtures/
    |-- locale/
    |-- media/
    |   |-- themes/
    |   |   |-- ...
    |   |   |-- merengue/
    |   |   `-- yaco/
    |   `-- tinyimages/
    |-- merengue/
    |   |-- ...
    |-- plugins/
    |   |-- ...
    `-- templates/
        |-- themes/
        |   |-- ...
        |   |-- merengue/
        |   `-- yaco/
        `-- website/

Here is a brief description of the files and directories:

 * ``settings.py``: project settings.
 * ``urls.py``: project root url resolvers.
 * ``apps/``: for project-specific Django applications. It comes with a skeleton ``website`` app.
 * ``fixtures/``: an empty directory for holding project fixtures.
 * ``locale/``: directory for project translations.
 * ``media/``: root directory for multimedia files.
 * ``media/themes/``: root for all themes directories, each one containing its own multimedia files.
 * ``merengue/``: symbolic link to Merengue API.
 * ``plugins/``: plugins directory, with some plugins preinstalled.
 * ``templates/``: templates project directory.
 * ``templates/themes/``: specific templates for themes.


Change Project Settings
=======================

The project settings are in the ``merengueprojectorg/settings.py`` file, which should be
familiar to Django users.

First of all, you need to define your database connection (see `database setup`_
in the Django tutorial). Let's assume you are using SQLite (you will also need to
install `pysqlite`_) to keep things simple.

.. _pysqlite: http://trac.edgewall.org/wiki/PySqlite
.. _database setup: http://docs.djangoproject.com/en/1.3/intro/tutorial01/#database-setup

.. code-block:: python

       DATABASE = {
           'default': {
               'ENGINE': 'django.db.backends.sqlite3',
               'NAME': 'merengueprojectorg.db',
               'USER': '',
               'PASSWORD': '',
               'HOST': '',
               'PORT': '',
           }
       }

Other settings you should define:

.. code-block:: python

       ADMINS = (
           ('Your Name', 'youremail@yourdomain.org'), # put your name and email
       )


Database Bootstrap
==================

.. code-block:: bash

       $ python manage.py syncdb --migrate

.. admonition:: Note

    This is a `django-south`_ command, and is equivalent to executing
    ``python manage.py syncdb`` and then ``python manage.py migrate``.

If there is a problem with this command, please create a ticket in
`Merengue trac`_. Please specify your database engine and the version of Merengue
you are using. To continue this tutorial without problems, try this quick workaround:

  1. Remove the ``merengueprojectorg.db`` file.
  2. Remove south from the ``INSTALLED_APPS`` tuple in the ``merengueprojectorg/merengue/settings.py`` file.
  3. Run ``python manage.py syncdb``
  4. Add south to the ``INSTALLED_APPS`` tuple again.
  5. Run ``python manage.py syncdb``
  6. Run ``python manage.py migrate --fake``

.. _Merengue trac: http://dev.merengueproject.org/newticket
.. _django-south: http://south.aeracode.org/


Play with Your New Merengue Project
===================================

After the project settings are defined and the database created, you can run
a development server and see what the default Merengue theme looks like. We
hope you will like it!:

.. code-block:: bash

       $ python manage.py runserver
       Django version 1.3, using settings 'merengueprojectorg.settings'
       Development server is running at http://127.0.0.1:8000/
       Quit the server with CONTROL-C.

Now open your favourite web browser, and point it to ``http://localhost:8000`` .
You should see something like this:

.. image:: _images/merengue_theme_in_new_project.png

For more information about using Merengue, you can read our comprehensive
:ref:`user guide <topics-userguide>`.


.. _intro-tutorial-theme:


Creating the *merengueprojectorg* Theme
=======================================

In Merengue, the preferred method of changing the look and feel is to create a theme.

First, you need to create both a templates and a media directory for the
``merengueprojectorg`` theme:

.. code-block:: bash

    $ cd merengueprojectorg
    $ mkdir templates/themes/merengueprojectorg
    $ mkdir media/themes/merengueprojectorg
    $ mkdir media/themes/merengueprojectorg/img
    $ mkdir media/themes/merengueprojectorg/css

If you go to the Merengue admin application (open ``http://localhost:8000/admin/``
in your browser and use ``admin``/``admin`` as credentials), you will see that
Merengue has registered ``merengueprojectorg`` as a new theme:

.. image:: _images/merengueprojectorg_theme_in_admin.png

If you activate the ``merengueprojectorg`` theme you will see a blank theme
(without CSS styles) since we didn't put anything yet in the directories created above:

.. image:: _images/merengueprojectorg_theme_recently_created.png

You can now add stylesheets to define the look and feel. There are several
ways to accomplish this but one of the easiest is to create a ``base.html``
template in the ``templates/themes/merengueprojectorg/`` directory and then
hook your stylesheets from there. But first we will see how this template
works by writing our very own ``hello world`` template:

.. code-block:: html+django

    <h1>Hello world!</h1>

If you refresh your browser page, you will see a big **Hello world!** greeting. No tutorial
is complete until there is a ``hello world`` example, right?

But wait a second... how is this template loaded? Let's talk a little bit about
Merengue theming internals... Merengue implements a new Django template loader,
so when some part of the code tries to load a template (in a ``render_to_response``
call or in an `extends`_ or `include`_ tag) Merengue will look first into the template
directory of the current/active theme.

.. _`extends`: http://docs.djangoproject.com/en/1.3/ref/templates/builtins/#extends
.. _`include`: http://docs.djangoproject.com/en/1.3/ref/templates/builtins/#include

By placing the ``base.html`` template in the ``merengueprojectorg`` theme, you are
overriding `merengue/base/templates/base.html`_, which extends itself from
`merengue/base/templates/base/layout.html`_. That's the reason you see a huge
*hello world* instead of the normal Merengue layout. This pattern is repeated all over
during the development cycle of a theme so you better get used to it, huh?

You may be thinking, why this double template inheritance? and I'm glad you asked.
The answer is:  we usually need to reuse some of the Merengue layout stuff, and
if this code would have been located in ``merengue/base/templates/base.html`` we
could not have extended this template from your theme. In fact, if you try to extend
``base.html`` inside your theme ``base.html`` template you will get a ``nice``
infinite recursion error.

.. _`merengue/base/templates/base.html`: http://dev.merengueproject.org/browser/trunk/merengueproj/merengue/base/templates/base.html
.. _`merengue/base/templates/base/layout.html`: http://dev.merengueproject.org/browser/trunk/merengueproj/merengue/base/templates/base/layout.html

Let's reuse the Merengue base layout in your ``base.html`` template:

.. code-block:: html+django

    {% extends "base/layout.html" %}

    {% block extrastyles %}
      <link href="{{ THEME_MEDIA_URL }}css/layout.css" rel="stylesheet" type="text/css" />
    {% endblock %}

Now if you refresh your browser window, you will again see the Merengue default web layout.

.. admonition:: Note

    ``THEME_MEDIA_URL`` will be replaced with the relative media location of the active
    theme in Merengue admin. Using this context variable instead of hardcoding
    ``/media/themes/merengueprojectorg/css/layout.css`` or
    ``{{ MEDIA_URL }}themes/merengueprojectorg/css/layout.css`` is considered a best
    practice.

Of course, you need to create the ``layout.css`` CSS file, that will be in
``media/themes/merengueprojectorg/css/`` directory, to begin customizing the look
and feel of your site.

Next, we will add a couple of images, `header_bg.jpg`_ and `header_logo.jpg`, into
the ``media/themes/merengueprojectorg/img`` directory, to begin the header layout.

After this, we'll write some CSS rules in the ``layout.css`` file. Listed below, is the
fragment of this file in which we put the header images and other related stuff:

.. code-block:: css

    html {
        background-color: #BCB9AD;
    }

    body {
        font: 12px Helvetica, sans-serif;
        color: #717171;
    }

    a {
        color: #cfa570;
        text-decoration: none;
    }

    #container {
        margin: 0 auto;
        padding-bottom: 100px;
        width: 960px;
    }

    #header {
        background: url(../img/header_bg.jpg) no-repeat top center;
    }

    #headerlogo {
        height: 98px;
        background: url(../img/header_logo.jpg) no-repeat top left;
    }

    #content {
        float: left;
        width: 470px;
        padding: 0 10px;
    }

    body div#content-zone {
        width: auto;
    }

    /* more stuff below ... */

.. _`header_bg.jpg`: http://dev.merengueproject.org/browser/sites/merengueprojectorg/media/themes/merengueprojectorg/img/header_bg.jpg
.. _`header_logo.jpg`: http://dev.merengueproject.org/browser/sites/merengueprojectorg/media/themes/merengueprojectorg/img/header_logo.jpg

If you have done this correctly, then refresh your browser window and you should see
a page similar to this screenshot:

.. image:: _images/merengueprojectorg_theme_with_logo.png

Next, we will add a ``Django based CMS framework for perfectionists with deadlines``
phrase into header. Feel free to change the wording if you do not consider yourself
a perfectionist :-). If you take a look at `merengue/base/templates/base/layout.html`_
template, you will find a fragment similar to this:

.. code-block:: html+django

    # more stuff ...

    <div id="headerlogo">
      {% block headerlogo %}
        {% include "inc.headerlogo.html" %}
      {% endblock %}
    </div>

    # more stuff ...

There are two ways to include text near the logo:

 1. Overriding the ``headerlogo`` block in our ``base.html`` template.
 2. Creating a ``inc.headerlogo.html`` template in the ``merengueprojectorg`` theme template directory.

In this example, we are going to use the second option. Create a ``inc.headerlogo.html``
file in the ``templates/themes/merengueprojectorg`` directory with the following
content:

.. code-block:: html+django

    <a href="{% url website.views.index %}">
      <img src="{{ THEME_MEDIA_URL }}img/header_logo.jpg"/>
    </a>
    <div class="logophrase">
      Django based CMS framework for perfectionists with deadlines
    </div>

Finally, add some CSS for the logo phrase:

.. code-block:: css

    .logophrase {
        font-family: 'HelveticaNeue-UltraLight','Helvetica Neue UltraLight','Helvetica Neue',Arial,Helvetica,sans-serif;
        font-weight: 100;
        float: right;
        font-size: 15px;
        padding-top: 60px;
        padding-right: 20px;
        color: #b3a99d;
    }

You should see now a page header with a logo and a phrase to the right:

.. image:: _images/merengueprojectorg_theme_with_logo_and_phrase.png

To see a finished version of the `www.merengueproject.org`_ theme, you have to:

 1. Copy the content of the `merengueproject base.html template`_.
 2. Copy the complete `merengueproject layout.css file`_.
 3. Copy all the `images from merengueproject img directory`_.

.. _www.merengueproject.org: http://www.merengueproject.org
.. _`merengueproject base.html template`: http://dev.merengueproject.org/browser/sites/merengueprojectorg/templates/themes/merengueprojectorg/base.html
.. _`merengueproject layout.css file`: http://dev.merengueproject.org/browser/sites/merengueprojectorg/media/themes/merengueprojectorg/css/layout.css
.. _`images from merengueproject img directory`: http://dev.merengueproject.org/browser/sites/merengueprojectorg/media/themes/merengueprojectorg/img

.. admonition:: More Information

    For more information about Merengue theming, you can read :ref:`working with themes <topics-themes-index>`


The Theme is Finished, What Next?
====================================

After finishing the ``merengueprojectorg`` theme, you should get an index page like
this:

.. image:: _images/merengueprojectorg_after_finishing_theme.png

However, the `www.merengueproject.org`_ website looks different:

.. image:: _images/merengueprojectorg_index.png

By comparing the two screenshots above, you can see that there is more work to do:

 * Non programming tasks (content managing):

   * Create portal links (*Demo*, *Documentation*, *Features*, etc.).
   * Disable navigation block.
   * Change the main content title and description.

 * Programming tasks (python or templates):

   * Index page changes:

     * Remove breadcrumbs only for the home page.
     * Include an image on the left hand side of the main content area.

   * Implement a ``features`` plugin, with:

     * A `features list`_, containing a categorized list of all Merengue features.
     * A features block, to show some Merengue features in the index page (such as *collaborative editing*, *geolocation*, etc.).
     * A customization of the Merengue admin interface that allows the user manage the features and categories from a Django admin site.

.. _`features list`: http://www.merengueproject.org/features/


Non-Programming Tasks
=====================

All of the non-programming tasks can be handled in the Merengue admin interface. For more
information about how to do this, please read the :ref:`Merengue user guide <topics-userguide>`


Customizing the Index Page
==========================

When a Merengue project is created with the ``startproject`` command, a ``website``
application is created inside the ``apps`` directory. This is a skeleton application
useful for holding specific project views that do not fit into any plugin.

One example would be the index page. In fact, the ``website`` app comes with a default
index page view already implemented and included in the root ``urls.py``. This is the
default implementation:

.. code-block:: python

    from plugins.core.config import PluginConfig as CoreConfig
    from merengue.base.models import BaseContent

    def index(request):
        """ Index page. You can override this as you like """
        core_config = CoreConfig().get_config()
        main_content_index = core_config['home_initial_content'].get_value()
        content = BaseContent.objects.get(pk=main_content_index)
        return render_to_response('website/index.html',
                                  {'content': content},
                                  context_instance=RequestContext(request))

By default, this implementation takes some initial content and shows it, rendering
a ``website/index.html`` template. Let's explain this code fragment line by line:

 * ``core_config = CoreConfig().get_config()``. Load ``plugins.core`` `configuration`_
 * ``main_content_index = core_config['home_initial_content'].get_value()``. Get the ID of the content that will be shown on the index page.
 * ``content = BaseContent.objects.get(pk=main_content_index)``. Use the ``BaseContent`` model (the parent model of all managed content) to retrieve the content to be shown.
 * ``return render_to_response('website/index.html', ...``. Render the template that will show the content.

We do not need to change anything in this view for the `www.merengueproject.org`_ index,
but we need to change several things in the template.

The template ``website/index.html`` has the following default content:

.. code-block:: html+django

    {% extends "content_view.html" %}

    {% load block_tags %}

    {% block aftercontentbody %}
        {% render_blocks "homepage" %}
    {% endblock %}

This template extends ``content_view.html``, the generic Merengue template used
to show content in a detail view. This base template extends others, in the following order:

  * ``content.html``
  * ``base/content.html``
  * ``base.html``
  * ``base/layout.html``

``content.html`` and ``base.html`` are placeholder templates that only extend
``base/content.html`` and ``base/layout.html`` respectively. Why are these templates
only placeholders and have no unique content of their own? Because they will likely be
overriden in the active theme -- custom templates may extend the ``base/content.html``
or ``base/layout.html`` files (see the infinite recursion problem described earlier).

The only change we need to do in the default index template ``base/content.html``
is to render all of the visual blocks placed in a ``homepage`` place. See the
:ref:`blocks documentation <topics-blocks>` for more information. The
``aftercontentbody`` block is defined in the ``base/content.html`` template and is
rendered just after the content data.

.. admonition:: More Information

    We recommend that you explore both the ``base/content.html`` and ``base/layout.html``
    files in order to understand Merengue layout, blocks, actions, etc.

.. _`configuration`: http://dev.merengueproject.org/browser/trunk/merengueproj/plugins/core/config.py

Now we need to remove the breadcrumbs and position an image close to the main content text.

The new template will look like this (including comments to explain new fragments):

.. code-block:: html+django

    {% extends "content_view.html" %}

    {% load block_tags %}

    {% block breadcrumbswrapper %}{# remove breadcrumbs in the homepage #}{% endblock %}

    {% block contentdescription %}
      {# put image with description #}
      <div class="contentDescriptionIndex">
        <img alt="Merengue demo" src="{{ THEME_MEDIA_URL }}img/preview_merengue.jpg" />
        {{ content.description|safe }}
      </div>
    {% endblock %}

    {% block aftercontentbody %}
      {% render_blocks "homepage" %}
    {% endblock %}


Developing a Plugin
===================

Merengue *plugins* are installable components that add some functionality or
change existing Merengue features. See the :ref:`Plugins documentation <topics-plugins-overview>`
for more information.

In this tutorial, we will implement a ``features`` plugin that:

 * Adds two new content types (Feature and FeatureCategory) for Merengue features and their categories.
 * Implements a features block to show some features in the home page.
 * Implements a listing view to show all the features.

.. admonition:: Note

    If you want to inspect the finished ``features`` plugin, you can browse
    the `features plugin code`_ in our Trac system.

.. _`features plugin code`: http://dev.merengueproject.org/browser/sites/merengueprojectorg/plugins/features

Creating a Plugin
-----------------

A plugin is a Django application with some restrictions:

 * It must be located in the project's ``plugins`` directory.
 * It must have a plugin configuration file, named ``config.py`` with a ``PluginConfig`` class inside.

So, to build the simplest plugin possible, we do the following:

.. code-block:: bash

    $ cd merengueprojectorg/plugins
    $ mkdir features
    $ touch features/__init__.py
    $ touch features/models.py
    $ touch features/config.py

Then, put the following code in ``plugins/features/config.py`` (the plugin configuration
file):

.. code-block:: python

    from merengue.pluggable import Plugin

    class PluginConfig(Plugin):
        name = 'Features'
        description = 'Features Display Plugin'
        version = '0.0.1'

This fragment only sets the plugin metadata, without changing functionality. Our
``features`` plugin is still a very simple plugin.

Merengue should now recognize this python module as a plugin:

.. image:: _images/merengueprojectorg_with_features_plugin.png

Creating Plugin Models
----------------------

Before installing the plugin, we should create its models:

.. code-block:: python

    from django.db import models
    from django.utils.translation import ugettext_lazy as _

    from merengue.base.models import BaseContent, BaseCategory
    from merengue.base.managers import BaseContentManager

    class FeatureCategory(BaseCategory):
        pass

    class Feature(BaseContent):
        icon = models.ImageField(verbose_name=_('icon'), upload_to='feature_icons',
                                 null=True, blank=True)
        show_in_home = models.BooleanField(verbose_name=_('show in home'),
                                           null=False)
        categories = models.ManyToManyField(FeatureCategory,
                                            verbose_name=_('category'),
                                            blank=True, null=True, db_index=True)

        objects = BaseContentManager()

``BaseCategory`` is the base model for all categorizations, and ``BaseContent``
will be a non-abstract model (see `Django model inheritance`_) for all managed
content. If your model inherits from ``BaseContent`` it will have all of the Merengue
features related to content management for free. ``BaseContentManager`` is a special
manager with a lot of cool query methods, like getting content by workflow status.

.. _`Django model inheritance`: http://docs.djangoproject.com/en/1.3/topics/db/models/#id5

These models will be created automatically when you install the plugin in the
admin site. Please, do it now before continuing further. Then, let's check the
tables created in our sqlite3 database:

.. code-block:: bash

    $ python manage.py dbshell
    sqlite> .tables feature
    features_feature             features_featurecategory
    features_feature_categories

We can now play with features and feature categories using the Django ORM as follows:

.. code-block:: bash

   $ python manage.py shell

.. code-block:: python

    >>> from plugins.features.models import Feature, FeatureCategory
    >>> category = FeatureCategory.objects.create(name_en='Look and feel')
    >>> feature = Feature.objects.create(name_en='Skinnable')
    >>> feature.categories.add(category)
    >>> Feature.objects.published()  # testing workflow
    []
    >>> feature.status
    u'draft'
    >>> feature.status = 'published'
    >>> feature.save()
    >>> Feature.objects.published()
    [<Feature: Skinnable>]
    >>> feature.name_es = 'Aspecto cambiable' # testing model translation
    >>> feature.save()
    >>> feature.name # 'name' attribute will retrieve name_en
    'Skinnable'
    >>> from django.utils.translation import activate
    >>> activate('es')
    >>> feature.name # 'name' attribute now get 'name_es'
    'Aspecto cambiable'

The features, as we said previously, will be managed content, like documents,
news items, etc. Let's check:

.. code-block:: python

    >>> from merengue.base.models import BaseContent
    >>> BaseContent.objects.all()
    [<BaseContent: Skinnable>, <BaseContent: Welcome to Merengue>]
    >>> BaseContent.objects.all().values('class_name', 'name_en')
    [{'class_name': u'feature', 'name_en': u'Skinnable'}, {'class_name': u'document', 'name_en': u'Welcome to Merengue'}]

To enable these models in the Merengue admin site, you will need to define a plugin
admin section implementing the ``get_model_admins`` method in ``config.py``:

.. code-block:: python

    from plugins.features.admin import FeatureAdmin, FeatureCategoryAdmin
    from plugins.features.models import Feature, FeatureCategory

    class PluginConfig(Plugin):
        # stuff ...

        @classmethod
        def get_model_admins(cls):
            return [(Feature, FeatureAdmin),
                    (FeatureCategory, FeatureCategoryAdmin)]

Both ``FeatureAdmin`` and ``FeatureCategoryAdmin`` are `Django model admins`_.

.. _`Django model admins`: http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-objects

Of course, as you can see, these ``ModelAdmin`` classes are defined in the ``plugins.features.admin``
module. This implies that there is an ``admin.py`` file inside the plugin package with this content:

.. code-block:: python

    from merengue.base.admin import BaseContentAdmin, BaseCategoryAdmin
    from plugins.features.models import Feature, FeatureCategory

    class FeatureCategoryAdmin(BaseCategoryAdmin):
        pass

    class FeatureAdmin(BaseContentAdmin):
        pass

Both ``BaseCategoryAdmin`` and ``BaseContentAdmin`` are Django ``ModelAdmin``
subclasses, but with extra features. You can customize the usual ModelAdmin
options and add new ones. See `merengue.base.admin`_ module for more
information.

.. _`merengue.base.admin`: http://dev.merengueproject.org/browser/trunk/merengueproj/merengue/base/admin.py

Now, if you access the admin site, you will see a ``Features`` plugin admin site:

.. image:: _images/merengueproject_admin_with_features.png

If you click on it, you will access both the ``FeatureAdmin`` and ``FeatureCategoryAdmin``:

.. image:: _images/merengueproject_features_admin.png

Now, you can add features via the admin site.

Rendering New Blocks
--------------------

This section is about creating new blocks with Merengue. The blocks in Merengue
can be placed in various locations. See:ref:`Merengue blocks <topics-blocks>` for
more information about blocks.

We want to implement a ``features`` block to render some Merengue features (from
the ``Feature`` model). This is shown in next screenshot:

.. image:: _images/merengueprojectorg_features_block.png

To create a Merengue block your code must extend the ``merengue.block.blocks.Block``
class and implement the ``render`` class method. You can see an example of a ``features``
block implementation below:

.. code-block:: python

    from merengue.block.blocks import Block
    from plugins.features.models import Feature

    class FeatureBlock(Block):
        name = 'mainfeatures'
        default_place = 'homepage'

        @classmethod
        def render(cls, request, place, context):
            features_list = Feature.objects.published().filter(show_in_home=True)
            return cls.render_block(request, template_name='features/block_mainfeatures.html',
                                    block_title='Some features',
                                    context={'features_list': features_list})

Usually block code lives in a ``blocks.py`` file inside your plugin directory.
We will explain the most significant lines of code:

* ``name`` should be a name without spaces and special characters, and will identify the block.
* ``default_place`` is the default location for placing the block when activated. You can change this location later (inside the admin interface).
* ``render`` is a callback function that will be called when Merengue renders a block in the location defined for that block.

Now, the only thing to do is to create the ``features/block_mainfeatures.html`` template:

.. code: bash

    $ cd plugins/features
    $ mkdir -p templates/features
    $ touch templates/features/block_mainfeatures.html

The content of this template is as follows:

.. code-block:: html+django

    {% extends "block.html" %}

    {% block blocktitle %}
      <h1>Merengue main features</h1>
    {% endblock %}

    {% block blockbody %}
    <div id="features">
      {% for feature in features_list %}
        <div>
          {% if feature.icon %}
            <img src="{{ feature.icon.url }}"/>
          {% endif %}
          <h2 title="{{ feature }}"><a href="{{ feature.get_absolute_url }}">{{ feature }}</a></h2>
          <div class="description">
            {{ feature.description|safe|truncatewords_html:20 }}
          </div>
      </div>
      {% endfor %}
    </div>
    {% endblock %}

This template is self-explanatory. It is important to note that there is a base
template for blocks (named ``block.html``) that should be used in your blocks
in order to maintain a similar look and feel (as was done in the previous example).

Now the ``features`` block is finished. You will need to register it in the
plugin itself to inform Merengue that this block exists. This is done inside the plugin
config:

.. code-block:: python

    from plugins.features.blocks import FeatureBlock

    class PluginConfig(Plugin):
        # old stuff ...

        @classmethod
        def get_blocks(cls):
            return [FeatureBlock]

Since the ``features`` plugin is already installed and activated, the new block
is not registered unless we deactivate and reactivate the plugin again in the
admin interface.

If you look in the admin screen at the list of blocks (after you reactivate the
block), you will see a new block registered:

.. image:: _images/merengueprojectorg_blocks_admin.png

As you can see, the block is "placed at", by default, on the ``homepage`` because we
defined this in our block. You can change this location in the ``blocks.py`` file, or by
using the Merengue `block reordering interface`_.

.. _`block reordering interface`: http://www.merengueproject.org/features/visual-blocks-management/

Now, you can create one or two features, adding text and also an icon, if you want.
You will then need to publish those features and mark the *show in home* flag in
order to see them in our ``features`` block. After that, if you go to home page,
you will see something like this:

.. image:: _images/merengueprojectorg_after_finishing_features_block.png

.. admonition:: Note

    You may have noticed that the title of the block *Merengue main features* is not shown
    on the homepage. The reason being that it is hidden using CSS in the ``merengueprojectorg``
    theme.

Implementing Plugin Views
-------------------------

The last thing you will do in creating the ``feature`` plugin is define two views:

* A feature listing view. See it in the `production site`_.
* A features detail view, like `visual block management`_.

.. _`production site`: http://www.merengueproject.org/features/
.. _`visual block management`: http://www.merengueproject.org/features/visual-blocks-management/

The first step consists of registering a URL namespace for your plugin, adding
a ``url_prefixes`` attribute in the ``PluginConfig`` class like this:

.. code-block:: python

    from merengue.pluggable import Plugin
    # ...

    class PluginConfig(Plugin):
        # ...
        url_prefixes = (
            ('features', 'plugins.features.urls'),
        )
        # ...

The code above reserves a ``/features`` prefixe in the URLs to be handled by
our plugin, in the ``plugins.features.urls`` module. Of course, you can
add several URL namespaces in each individual plugin, if necessary.

Now, if we try to access the development server, we will get an error,
because the ``urls`` module and views are not implemented.

So, next, we  create an ``urls.py`` file inside your plugin, with content just like
a normal Django urls module:

.. code-block:: python

    from django.conf.urls.defaults import patterns, url

    urlpatterns = patterns('plugins.features.views',
        url(r'^$', 'features_index', name='features_index'),
        url(r'^(?P<features_slug>[\w-]+)/$', 'features_view', name='features_view'),
    )

``features_index`` and ``features_view`` will be the listing and detail views, respectively, of
the Merengue feature plugin. Again, you will get an error if you try to access the development web server,
because these views are not implemented. You need to create a ``views.py`` file
with content similar to this:

.. code-block:: python

    from django.shortcuts import get_object_or_404
    from merengue.base.views import content_view, content_list
    from plugins.features.models import Feature, FeatureCategory

    def features_index(request):
        categories_list = FeatureCategory.objects.all()
        features = Feature.objects.published()
        return content_list(request, features,
                            template_name='features/features_index.html',
                            paginate_by=12,
                            extra_context={'categories_list': categories_list})

    def features_view(request, features_slug):
        features_view = get_object_or_404(Feature, slug=features_slug)
        return content_view(request, features_view,
                            template_name='features/features_view.html')

These two views are typical of views used in the Django world. The only thing to note is the
use of the ``content_list`` and ``content_view`` views from Merengue. The usage of
these views (available within Merengue) allows us to reuse code (although their
usage is optional).

The last thing to do is to implement the ``features/features_index.html`` and
``features/features_view.html`` templates. These two templates should be placed
in a ``templates/features`` directory inside your plugin directory, and never in
your theme, because they deal with the content itself, not the appearance of that content.


The ``features/features_index.html`` template would look as follows:

.. code-block:: html+django

    {% extends "content_list.html" %}

    {% load i18n inlinetrans %}

    {% block extrabreadcrumbs %}
      <span class="breadcrumbSeparator">→</span> <a href="{% url features_index %}" title="{% trans "Features" %}">{% inline_trans "Features" %}</a>
    {% endblock %}

    {% block listtitle %}{% trans "Features index" %}{% endblock %}

    {% block listing %}
    <ul class="contentList">
      {% for feature in content_list %}
      <li>
        <a href="{{ feature.get_absolute_url }}" title="{{ feature }}">
         {{ feature }}
        </a>
      </li>
      {% endfor %}
    </ul>
    {% endblock %}

Additional notes:

* This template extends a ``content_list.html`` template, which handles things
  like pagination, and adds useful blocks to override things like ``listing`` or ``listtitle``. 

* It uses the ``inline_trans`` template tag to translate labels, instead of the
  usual Django ``trans`` one. This is so we can use the `inline WYSIWYG translation tool`_
  that comes standard with Merengue.

* As mentioned earlier, the template that is extended is named ``content_list.html`` and not
  ``base/content_list.html``.  This allows for theming to override this plugin's template.

* We use the ``get_absolute_url`` method implemented in ``BaseContent``.

The resulting view, if you access the ``/features/`` URL, looks something like this:

.. image:: _images/merengueprojectorg_features_index.png

If you click on any link to the feature you will see that it works, even if
you do not specifically request the feature detail view from Merengue. The reason
for this being that the ``Feature`` model inherits the ``BaseContent`` model which
has a default implementation of the URL returned in ``get_absolute_url``.

In fact, ``get_absolute_url`` will not return the final content detail URL. It
will return an intermediate URL (something like ``/cms/base/public_redirect/features/feature/4/``)
which does some checks and then redirects the browser to the URL returned in the
first of these two methods implemented in the model:

1. ``content.link_by_user(user)``
2. ``content.public_link()``

The first method is tried first because sometimes you need different behaviour
depending whether the user is allowed to see the content (permissions need to be
checked, or a login is required). If the first method is not implemented, Merengue
will call the second one (which is implemented in ``BaseContent`` model). That is
how you will see a default page displayed, even if you have not implemented method #2.

But, to conform to Django best practices, we have to use ``features_view`` as our
content link. In Merengue this means we implement a ``public_link`` method in our
``Feature`` model, instead of a ``get_absolute_url`` method:

.. code-block:: python

    from django.db.models import permalink

    class Feature(BaseContent):
        # ...

        @permalink
        def public_link(self):
            return ('features_view', [self.slug])

Now, all of the features links will try to call the ``features_view`` view. Before
we finish, you will need to implement the last template, ``features/features_view.html``:

.. code-block:: html+django

    {% extends "content_view.html" %}

    {% load i18n inlinetrans action_tags %}

    {% block beforecontentbreadcrumbs %}
        <span class="breadcrumbSeparator">→</span><a href="{% url features_index %}" title="{% trans "Features" %}">{% inline_trans "Features" %}</a>
    {% endblock %}

    {% block contentbody %}
      Categories: {{ content.categories.all|join:"," }}
    {% endblock %}

This template extends ``content_view.html`` which include some features like a
multimedia viewer (you can try to add some images or videos to the feature).

The resulting view looks like this:

.. image:: _images/merengueprojectorg_features_view.png

.. admonition:: Note

    Some parts of the `templates used in the original features plugin`_ have been ommited
    for readability reasons.

.. _`inline WYSIWYG translation tool`: http://www.merengueproject.org/features/inline-translation-tool/
.. _`templates used in the original features plugin`: http://dev.merengueproject.org/browser/sites/merengueprojectorg/plugins/features/templates/features

The tutorial ends here. At this point you should know how to begin a Merengue
project, design new themes, and develop your own plugins.
