#################
2.4 release notes
#################

*****************
What's new in 2.4
*****************


.. _upgrade-to-2.4:

.. warning:: Upgrading from previous versions

    2.4 introduces some changes that **require** action if you are upgrading
    from a previous version.

    You will need to read the sections :ref:`migrations-upgrade` and
    :ref:`cms-moderator-upgrade` below.


Introducing Django 1.5 support, dropped support for Django 1.3 and Python 2.5
=============================================================================

Django CMS 2.4 introduces Django 1.5 support.

In django CMS 2.4 we dropped support for Django 1.3 and Python 2.5.
Django 1.4 and Python 2.6 are now the minimum required versions.


.. _migrations-upgrade:

Migrations overhaul
===================

In version 2.4, migrations have been completely rewritten to address issues
with newer South releases.

To ease the upgrading process, all the migrations for the `cms` application
have been consolidated into a single migration file, `0001_initial.py`.

*   migration 0001 is a *real* migration, that gets you to the same point migrations 0001-0036 used to
*   the migrations 0002 to 0036 inclusive still exist, but are now all *dummy*
    migrations
*   migrations 0037 and later are *new* migrations

How this affects you
--------------------

If you're starting with *a new installation*, you don't need to worry about
this. Don't even bother reading this section; it's for upgraders.

If you're using version *2.3.2 or newer*, you don't need to worry about this
either.

If you're using version *2.3.1 or older*, you will need to run a two-step
process.

First, you'll need to upgrade to 2.3.3, to bring your migration history
up-to-date with the new scheme. Then you'll need to perform the migrations for
2.4.

For the two-step upgrade process do the following in your project main directory::

    pip install django-cms==2.3.3
    python manage.py syncdb
    python manage.py migrate
    pip install django-cms==2.4
    python manage.py migrate

Added delete orphaned plugins command
=====================================

Added a management command for deleting orphaned plugins from the database.

The command can be run with::

    manage.py cms delete_orphaned_plugins

Please read :ref:`cms-delete-orphaned-plugins-command` before using.

.. _cms-moderator-upgrade:

Added a check command
=====================

Added a management command to check your configuration and environment.

To use this command, simply run:

    manage.py cms check

This replaces the old at-runtime checks.

CMS_MODERATOR
=============
Has been removed since it is no longer in use. From 2.4 onward, all pages
exist in a public and draft version. Users with the ``publish_page`` permission
can publish changes to the public site.

.. admonition:: Management command required

    To bring a previous version of your site's database up-to-date, you'll
    need to run ``manage.py cms moderator on``. **Never run this command
    without first checking for orphaned plugins**, using the ``cms list
    plugins`` command. If it reports problems, run ``manage.py cms
    delete_orphaned_plugins``. Running ``cms moderator`` with orphaned plugins
    will fail and leave bad data in your database. See :ref:`cms-list-command`
    and :ref:`cms-delete-orphaned-plugins-command`.

    Also, check that all your plugins define a
    :meth:`~cms.models.pluginmodel.CMSPlugin.copy_relations()` method if required. You can do
    this by running ``manage.py cms check`` and read the *Presence of
    "copy_relations"* section. See :ref:`handling-relations` for guidance on
    this topic.


Added Fix MPTT Management command
=================================

Added a management command for fixing MPTT tree data.

The command can be run with::

    manage.py cms fix-mptt


Removed the MultilingualMiddleware
==================================

We removed the MultilingualMiddleware. This removed rather some unattractive
monkey-patching of the ``reverse()`` function as well. As a benefit we now
support localisation of URLs and apphook URLs with standard Django helpers.


For django 1.4 more information can be found here:

    https://docs.djangoproject.com/en/dev/topics/i18n/translation/#internationalization-in-url-patterns

If you are still running django 1.3 you are able to achieve the same functionality with django-i18nurl. It is a backport
of the new functionality in django 1.4 and can be found here:

   https://github.com/brocaar/django-i18nurls


What you need to do:

- Remove ``cms.middleware.multilingual.MultilingualURLMiddleware`` from your
  settings.
- Be sure ``django.middleware.locale.LocaleMiddleware`` is in your settings,
  and that it comes after the SessionMiddleware.
- Be sure that the ``cms.urls`` is included in a ``i18n_patterns``::

        from django.conf.urls.i18n import i18n_patterns
        from django.contrib import admin
        from django.conf import settings
        from django.urls import *

        admin.autodiscover()

        urlpatterns = i18n_patterns('',
            re_path(r'^admin/', include(admin.site.urls)),
            re_path(r'^', include('cms.urls')),
        )

        if settings.DEBUG:
            urlpatterns = patterns('',
            re_path(r'^media/(?P<path>.*)$', 'django.views.static.serve',
                    {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
            re_path(r'', include('django.contrib.staticfiles.urls')),
        ) + urlpatterns

- Change your url and reverse calls to language namespaces. We now support the django way of
  calling other language urls either via ``{% language %}`` template tag or via ``activate("de")`` function call in views.

  Before::

        {% url "de:myview" %}

  After::

        {% load i18n %}{% language "de" %}
        {% url "myview_name" %}
        {% endlanguage %}

- reverse urls now return the language prefix as well. So maybe there is some code that adds language prefixes. Remove
  this code.

Added LanguageCookieMiddleware
==============================

To fix the behaviour of django to determine the language every time from new, when you visit `/` on a page, this
middleware saves the current language in a cookie with every response.

To enable this middleware add the following to your `MIDDLEWARE_CLASSES` setting:

    `cms.middleware.language.LanguageCookieMiddleware`


CMS_LANGUAGES
=============

:setting:`CMS_LANGUAGES` has be overhauled. It is no longer a list of tuples like the ``LANGUAGES`` settings.

An example explains more than thousand words::

    CMS_LANGUAGES = {
            1: [
                {
                    'code': 'en',
                    'name': gettext('English'),
                    'fallbacks': ['de', 'fr'],
                    'public': True,
                    'hide_untranslated': True,
                    'redirect_on_fallback':False,
                },
                {
                    'code': 'de',
                    'name': gettext('Deutsch'),
                    'fallbacks': ['en', 'fr'],
                    'public': True,
                },
                {
                    'code': 'fr',
                    'name': gettext('French'),
                    'public': False,
                },
            ],
            2: [
                {
                    'code': 'nl',
                    'name': gettext('Dutch'),
                    'public': True,
                    'fallbacks': ['en'],
                },
            ],
            'default': {
                'fallbacks': ['en', 'de', 'fr'],
                'redirect_on_fallback':True,
                'public': False,
                'hide_untranslated': False,
            }
        }


For more details on what all the parameters mean please refer to the :setting:`CMS_LANGUAGES` docs.

The following settings are not needed any more and have been removed:

- `CMS_HIDE_UNTRANSLATED`
- `CMS_LANGUAGE_FALLBACK`
- `CMS_LANGUAGE_CONF`
- `CMS_SITE_LANGUAGES`
- `CMS_FRONTEND_LANGUAGES`

Please remove them from your ``settings.py``.

CMS_FLAT_URLS
=============

Was marked deprecated in 2.3 and has now been removed.



Plugins in Plugins
==================

We added the ability to have plugins in plugins. Until now only the TextPlugin supported this.
For demonstration purposes we created a MultiColumn Plugin. The possibilities for this are endless.
Imagine: StylePlugin, TablePlugin, GalleryPlugin etc.

The column plugin can be found here:

   https://github.com/divio/djangocms-column

At the moment the limitation is that plugins in plugins is only editable in the frontend.

Here is the MultiColumn Plugin as an example::

    class MultiColumnPlugin(CMSPluginBase):
        model = MultiColumns
        name = _("Multi Columns")
        render_template = "cms/plugins/multi_column.html"
        allow_children = True
        child_classes = ["ColumnPlugin"]

There are 2 new properties for plugins:

**allow_children**

Boolean
If set to True it allows adding Plugins.

**child_classes**

List
A List of Plugin Classes that can be added to this plugin.
If not provided you can add all plugins that are available in this placeholder.

How to render your child plugins in the template
------------------------------------------------

We introduce a new template tag in the cms_tags called ``{% render_plugin %}``
Here is an example of how the MultiColumn plugin uses it::

    {% load cms_tags %}
    <div class="multicolumn">
    {% for plugin in instance.child_plugins %}
        {% render_plugin plugin %}
    {% endfor %}
    </div>

As you can see the children are accessible via the plugins children attribute.


New way to handle django CMS settings
=====================================

If you have code that needs to access django CMS settings (settings prefixed
with ``CMS_`` or ``PLACEHOLDER_``) you would have used for example
``from django.conf import settings; settings.CMS_TEMPLATES``. This will no
longer guarantee to return sane values, instead you should use
``cms.utils.conf.get_cms_setting`` which takes the name of the setting
**without** the ``CMS_`` prefix as argument and returns the setting.

Example of old, now deprecated style::

    from django.conf import settings

    settings.CMS_TEMPLATES
    settings.PLACEHOLDER_FRONTEND_EDITING

Should be replaced with the new API::

    from cms.utils.conf import get_cms_setting

    get_cms_setting('TEMPLATES')
    get_cms_setting('PLACEHOLDER_FRONTEND_EDITING')


Added ``cms.constants`` module
==============================

This release adds the ``cms.constants`` module which will hold generic django
CMS constant values. Currently it only contains ``TEMPLATE_INHERITANCE_MAGIC``
which used to live in ``cms.conf.global_settings`` but was moved to the new
``cms.constants`` module in the settings overhaul mentioned above.


django-reversion integration changes
====================================

`django-reversion`_ integration has changed. Because of huge databases after some time we introduce some changes
to the way revisions are handled for pages.

     1. Only publish revisions are saved. All other revisions are deleted when you publish a page.
     2. By default only the latest 25 publish revisions are kept. You can change this behaviour with the new
        :setting:`CMS_MAX_PAGE_PUBLISH_REVERSIONS` setting.


Changes to the show_sub_menu template tag
=========================================

The :ttag:`show_sub_menu` has received two new parameters.
The first stays the same and is still: how many levels of menu should be displayed.

The second: ``root_level`` (default=None), specifies at what level, if any, the menu should root at.
For example, if root_level is 0 the menu will start at that level regardless of what level the current page is on.

The third argument: ``nephews`` (default=100), specifies how many levels of nephews (children of siblings) are shown.


PlaceholderAdmin support i18n
=============================

If you use placeholders in other apps or models we now support more than one language out of the box.
If you just use ``PlaceholderAdmin`` it will display language tabs like the cms. If you
use `django-hvad`_ it uses the hvad language tabs.

If you want to disable this behaviour you can set ``render_placeholder_language_tabs = False`` on your Admin
class that extends PlaceholderAdmin. If you use a custom ``change_form_template`` be sure to have a look at
``cms/templates/admin/placeholders/placeholder/change_form.html`` for how to incorporate language tabs.


Added CMS_RAW_ID_USERS
======================

If you have a lot of users (500+) you can set this setting to a number after which admin User fields are displayed in
a raw Id field. This improves performance a lot in the admin as it has not to load all the users into the html.


******************************
Backwards incompatible changes
******************************

New minimum requirements for dependencies
=========================================

* Django 1.3 and Python 2.5 are no longer supported.


********************
Pending deprecations
********************

* ``simple_language_changer`` will be removed in version 3.0. A bug-fix makes
  this redundant as every non-managed URL will behave like this.

.. _django-reversion: https://github.com/etianen/django-reversion
.. _django-hvad: https://github.com/kristianoellegaard/django-hvad
