.. _intro-tutorial:

=================
Merengue tutorial
=================

Throughout this tutorial, we will:

    * Develop a Merengue project.
    * Develop a Merengue plugin.
    * Learn a bit to use Merengue from manager point of view.

Creating a project
==================

We will assume you have :ref:`Merengue installed <topics-install>` and you want to create a
`www.merengueproject.org`_ website (see `sources`_ for a finished result).

.. _sources: http://dev.merengueproject.org/browser/sites/merengueprojectorg
.. _www.merengueproject.org: http://www.merengueproject.org

Let's start your project:

.. code-block:: bash

    $ merengue-admin.py startproject merengueprojectorg

This command will create a ``merengueprojectorg`` directory, with this hierarchy::

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

Here are a brief description of these directories:

 * ``settings.py``: project settings.
 * ``urls.py``: project root url resolvers file.
 * ``apps/``: for project specific Django applications. It comes with a skel ``website`` app.
 * ``fixtures/``: a empty directory for store project fixtures.
 * ``locale/``: directory for project translations.
 * ``media/``: multimedia root directory.
 * ``media/themes/``: root for all themes multimedia directories.
 * ``merengue/``: link to Merengue API.
 * ``plugins/``: plugins directory, with builtins plugins inside.
 * ``templates/``: templates project directory.
 * ``templates/themes/``: specific templates for themes.


Change project settings
=======================

Project settings will be in ``merengueprojectorg/settings.py`` file.

First of all you have to define your database connection (see `database setup`_
in Django tutorial). Let's suppose you will use SQLite (you need `pysqlite`_ installed)

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

.. code-block:: python

       DATABASE_ENGINE = 'sqlite3'
       DATABASE_NAME = 'merengueprojectorg.db'
       DATABASE_USER = ''
       DATABASE_PASSWORD = ''
       DATABASE_HOST = ''
       DATABASE_PORT = ''

Other settings to define:

.. code-block:: python

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


Build database
==============

.. code-block:: bash

       $ python manage.py syncdb --migrate

.. admonition:: Note

    This command is executed by `django-south`_, and is equal to execute first
    a ``python manage.py syncdb`` plus ``python manage.py migrate``
    commands.

If there is a problem with this command, please create a ticket in
`Merengue trac`_, specifying your database engine and your Merengue version. To
continue the tutorial without problems you can do this quick fix:

  1. Remove ``merengueprojectorg.db`` file.
  2. Remove south from the ``INSTALLED_APPS`` tuple in ``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 project settings was defined and database was built, you can run
development server and see the Merengue default theme:

.. code-block:: bash

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

You can now access to ``http://localhost:8000``, and you will see something
like that:

.. image:: _images/merengue_theme_in_new_project.png

To more information about using Merengue, you can read :ref:`user guide <topics-userguide>`


.. _intro-tutorial-theme:


Creating *merengueprojectorg* theme
===================================

In Merengue you can change look and feel by developing themes.

First of all you have to create both a templates and a media directory for the
``merengueprojectorg``:

.. code-block:: bash

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

Now in Merengue admin (enter with ``admin``/``admin`` in
``http://localhost:8000/admin/``), you can see how Merengue has registered
``merengueprojectorg`` as a new theme:

.. image:: _images/merengueprojectorg_theme_in_admin.png

If you activate ``merengueprojectorg`` theme you will see a blank theme
(without CSS styles):

.. image:: _images/merengueprojectorg_theme_recently_created.png

You then need to add a stylesheet to defining look and feel. One of the ways
accomplish that is create a ``base.html`` template in
``templates/themes/merengueprojectorg/`` directory. You can begin with a
``hello world`` template:

.. code-block:: html+django

    <h1>Hello world!</h1>

If you reload browser, you will se a big **Hello world!** greeting.

But, why is this template loaded? Let's talk a little 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 a `extends`_ or `include`_ tag) Merengue will look first into the template
directory of active theme.

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

With this ``base.html`` template placed at ``merengueprojectorg`` theme, you are
overriding `merengue/base/templates/base.html`_, that extends from
`merengue/base/templates/base/layout.html`_. This is the reason you see a huge
*hello world* instead of normal Merengue layout.

But, why this double template inheritance? Because we usually need to reuse some of the
Merengue layout stuff, and if this code was located in
``merengue/base/templates/base.html`` we could not extends this template from your
theme. In fact, if you try to extends ``base.html`` inside your theme ``base.html``
you will get an 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 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 reload browser you will see again the Merengue default web layout.

.. admonition:: Note

    ``THEME_MEDIA_URL`` will be replaced for relative media location of active
    theme in Merengue admin. It's better use this context variable that hardcode
    ``/media/themes/merengueprojectorg/css/layout.css`` or
    ``{{ MEDIA_URL }}themes/merengueprojectorg/css/layout.css``.

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

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

After this, we put some CSS in the ``layout.css`` file. There is the fragment
in which we put header images and other 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(/media/themes/merengueprojectorg/img/header_bg.jpg) no-repeat top center;
    }

    #headerlogo {
        height: 98px;
        background: url(/media/themes/merengueprojectorg/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 done well and reload your browser, you should see a web page similar to
this screenshot:

.. image:: _images/merengueprojectorg_theme_with_logo.png

.. admonition:: About media linking

    All images in ``layout.css`` are linked with a hardcoded path
    ``/media/themes/merengueprojectorg/img/``. This is because CSS are static
    and served directly by web server. Merengue cannot replace any contextual
    variable here.

Next, we will add a ``Django based CMS framework for perfectionists with deadlines``
phrase into header. If you take a look at `merengue/base/templates/base/layout.html`_
template, you will see a fragment like this:

.. code-block:: html+django

    # more stuff ...

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

    # more stuff ...

So, you have two ways to include a 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.

This time, we will do second choice. You have to create a ``inc.headerlogo.html``
file in the ``templates/themes/merengueprojectorg`` directory with this 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 logo and phrase at right side:

.. image:: _images/merengueprojectorg_theme_with_logo_and_phrase.png

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

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

.. _`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:: Deep into

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


Analyzing work to do after finishing theme
==========================================

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

.. image:: _images/merengueprojectorg_after_finishing_theme.png

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

.. image:: _images/merengueprojectorg_index.png

Comparing both screenshots, you can see some tasks to do:

 * Non programming tasks (content managing):

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

 * Programming tasks (python or templates):

   * Index page changes:

     * Remove breadcrumbs only for home page.
     * Include a image in the left of main content.

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

     * A `features listing`_, with a categorized listing of all Merengue features.
     * A features block, to show some Merengue features in index page (such as *collaborative edition*, *geolocation*, etc.)
     * A plugin custom admin for adding features and categories in admin site.

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


Non programming tasks
=====================

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


Customizing index page
======================

When a Merengue project is created in ``startproject`` command, a ``website``
application is created inside ``apps``. This is a skel app thought for implement
project specific views that not fit in any plugin. 

One example would be index page. In fact, ``website`` app come with a default
index page view implemented, and included in root ``urls.py``, with this
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 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 a initial content and show it, rendering
a ``website/index.html``. We will 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 in index page.
 * ``content = BaseContent.objects.get(pk=main_content_index)``. Use ``BaseContent`` model (parent model of all managed contents) to get the content to be shown.
 * ``return render_to_response('website/index.html', ...``. Render template that will show the content.

This logic is the same we need for `www.merengueproject.org`_ index, but we
need to change several things in template.

The template ``website/index.html`` have this 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
for contents detail view. This base template extends others, in this order:
  * ``content.html``
  * ``base/content.html``
  * ``base.html``
  * ``base/layout.html``

``content.html`` and ``base.html`` are placeholders templates that only extends
``base/content.html`` and ``base/layout.html`` respectively. Why are only
placeholders and have no own content? Because these will be likely overrided in
active theme and those may want to extend from ``base/content.html`` or
``base/layout.html`` (see infinite recursion problem described before).

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

.. admonition:: Deep into

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

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

Now we need to remove breadcrumbs and put a image nearby main content text.

The new template will be this (included comments to explain new fragments):

.. code-block:: html+django

    {% extends "content_view.html" %}

    {% load block_tags %}

    {% block breadcrumbswrapper %}{# remove breadcrumbs in 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 for adding some functionality or
changing existing Merengue features. See :ref:`Plugins documentation <topics-plugins-overview>`
for more information.

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

 * Add two new content types (Feature and FeatureCategory) that represent Merengue features with its categories.
 * Implement a features blocks to show some features in home page.
 * Implement a listing view for all features.

.. admonition:: Note

    If you want to inspect the finished ``features`` plugin, you can see
    `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 have to be located in the project ``plugins`` directory.
 * It need to have a plugin configuration file, named ``config.py`` with a ``PluginConfig`` class inside.

So, to build the dummiest plugin possible we have to do:

.. code-block:: bash

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

And write next code in ``plugins/features/config.py`` (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 set the plugin metadata, without changing functionality. Our
``features`` plugin is for now a dummy plugin.

With this data Merengue should recognize this python module as plugin:

.. image:: _images/merengueprojectorg_with_features_plugin.png

Creating plugin models
----------------------

Before installing 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
contents. If your model inherits from ``BaseContent`` it will have all Merengue
features referred to content management. ``BaseContentManager`` is a special
manager with a lot of query features, like getting contents by workflow status.

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

These models will be created automatically when you install the plugin in
admin site. Please, do it. After that, 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 know 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 contents, like documents,
news items, etc. Let's check it:

.. 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 Merengue admin site you need define a plugin admin,
implementing ``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 see, these ``ModelAdmin`` classes are defined in ``plugins.features.admin``
module. This implies creates a ``admin.py`` file inside plugin 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. So, you could make use of usual options,
but also you have others. 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 to admin site, you will see a ``Features`` plugin admin site:

.. image:: _images/merengueproject_admin_with_features.png

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

.. image:: _images/merengueproject_features_admin.png

Now you can add features in admin site.

Rendering new blocks
--------------------

This section is about creating new blocks with Merengue. The blocks in Merengue
can be placed in several places and renders a fragment with information. See
:ref:`Merengue blocks <topics-blocks>` for more information about blocks.

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

.. image:: _images/merengueprojectorg_features_block.png

To create a Merengue block you have to extends from ``merengue.block.blocks.Block``
class and implement the ``render`` class method. You can see a possible ``features``
block implementation:

.. 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 blocks code live in a ``blocks.py`` file into your plugin directory.
We will explain main lines:

* ``name`` should be a name without spaces and special characters, and will identify block.
* ``default_place`` is the default place to locate the block when you activate this. You can change this location in admin later.
* ``render`` is a callback function that will be called when Merengue is rendering blocks in location defined for that block.

Now only remains 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 was 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 similar look&feel, like it is done in the previous example.

Now the ``features`` block is finished. Now you need to register it in the
plugin to say Merengue that this block exists. This is done in the plugin
config:

.. code-block:: python

    from plugins.features.blocks import FeatureBlock

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

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

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

If you look in admin blocks after reactivate block, you will see a new block
registered:

.. image:: _images/merengueprojectorg_blocks_admin.png

As you see, the block is placed by default in ``homepage`` place, because we
defined this in our block. But you can change location if you want, and even
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 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 note that block *Merengue main features* title is not shown in
    homepage. This is because is hidden using CSS in ``merengueprojectorg``
    theme.

Implementing plugin views
-------------------------

Last thing you will do in ``feature`` plugin is a definition of two views:

* A feature listing view. See it in `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 thing you would do is register a URL namespace for your plugin, adding
a ``url_prefixes`` attribute in ``PluginConfig`` class like this:

.. code-block:: python

    from merengue.pluggable import Plugin
    # ...

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

Previous code will reserve a ``/features`` prefixes in URLs to be handled in
our plugin, concretely in ``plugins.features.urls`` module. Of course you can
add several URL namespaces in every plugin.

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

So, next thing to do is create an ``urls.py`` file inside your plugin, with a
content as usual in every 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 view of
a Merengue feature. Again, you will get an error if you access to web server,
because those views are not implemented. You need to create a ``views.py`` file
with a 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 usual from the Django world. The only thing to note is the
use of ``content_list`` and ``content_view`` Merengue views, that helps to reuse
code, although is optional.

Last thing to do is implementing 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 define what you want to see (content) and not how you want
to see (look and feel).

The ``features/features_index.html`` content would be 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 %}

Some thing to say:

* It extends a ``content_list.html`` template, that concerns about thins like pagination, and add useful blocks to override like ``listing`` or ``listtitle``. 

* It uses ``inline_trans`` templatetag to translate labels, instead of Django ``trans`` one. This is because we can use the `inline WYSIWYG translation tool`_ that came with Merengue.

* Again, the extended template is ``content_list.html`` and not ``base/content_list.html``, because we want to be overridable in themes.

* We use ``get_absolute_url`` method that is implemented in ``BaseContent``.

The resulting view if you access to ``/features/`` URL is something like this:

.. image:: _images/merengueprojectorg_features_index.png

If you click in any link to the feature you will see that it works, even if
you do not say to Merengue what is the feature detail view. This is because
``Feature`` model inherits from ``BaseContent`` that have 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 a middle URL (something like ``/cms/base/public_redirect/features/feature/4/``)
that do some checks and then redirect 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 try is because sometimes you need different behaviour depending the
user is seeing the content (check permissions, or some login like that). If
first method is not implemented, Merengue will call the second one, that is
implemented in ``BaseContent`` model. That is because you see a default page
even if you have no implemented that method.

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

.. code-block:: python

    from django.db.models import permalink

    class Feature(BaseContent):
        # ...

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

Now all the features links will try to call ``features_view`` view. Before
finish, you 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`` that include some features like
multimedia viewer (you can try to add some images or videos to the feature).

The result view is like this:

.. image:: _images/merengueprojectorg_features_view.png

.. admonition:: Note

    Some fragments of `templates in original features plugin`_ have been ommited
    for readability reason.

.. _`inline WYSIWYG translation tool`: http://www.merengueproject.org/features/inline-translation-tool/
.. _`templates in 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 start a Merengue
project, design new themes, and develop your own plugins.
