1.. _upgrade-to-3.4:
2
3#################
43.4 release notes
5#################
6
7The most significant change in this release is the removal of revision support
8(i.e. undo/redo/recover functionality on pages) from the core django CMS. This
9functionality will be reinstated as an optional addon in due course, but in the
10meantime, that functionality is not available.
11
12.. _whats_new_3.4:
13
14*****************
15What's new in 3.4
16*****************
17
18* Changed the way CMS plugins are rendered. The HTML ``div`` with
19  ``cms-plugin`` class is no longer rendered around every CMS plugin. Instead a
20  combination of ``template`` tags and JavaScript is used to add event handlers
21  and plugin data directly to the plugin markup. This fixes most of the
22  rendering issues caused by the extra markup.
23* Changed asset cache-busting implementation, which is now handled by a path change,
24  rather than the ``GET`` parameter.
25* Added the option to copy pages in the page tree using the drag and drop
26  interface.
27* Made it possible to use multi-table inheritance for Page/Title extensions.
28* Refactored plugin rendering functionality to speed up loading time in both
29  structure and content modes.
30* Added a new ``Shift`` + ``Space`` shortcut to switch between structure and
31  content mode while highlighting the current plugin, revealing its position.
32* Improved keyboard navigation
33* Added help modal about available short-cuts
34* Added fuzzy matching to the plugin picker.
35* Changed the ``downcast_plugins`` utility to return a generator instead of a
36  list.
37* Fixed a bug that caused an aliased placeholder to show in structure mode.
38* Fixed a bug that prevented aliased content from showing correctly without
39  publishing the page first.
40* Added help text to an ``Alias`` plugin change form when attached to a page
41  to show the content editor where the content is aliased from.
42* Removed revision support from django CMS core.
43  As a result both ``CMS_MAX_PAGE_HISTORY_REVERSIONS`` and ``CMS_MAX_PAGE_PUBLISH_REVERSIONS``
44  settings are no longer supported, as well as the ``with_revision`` parameter
45  in ``cms.api.create_page`` and ``cms.api.create_title``.
46* In ``cms.plugin_base.CMSPluginBase`` methods ``get_child_classes`` and ``get_parent_classes`` now
47  are implemented as a ``@classmethod``.
48
49.. _backward_incompatible_3.4:
50
51****************
52Upgrading to 3.4
53****************
54
55A database migration is required because the default value of CMSPlugin.position was set to 0 instead of null.
56
57Please make sure that your current database is consistent and in a healthy
58state, and **make a copy of the database before proceeding further.**
59
60Then run::
61
62    python manage.py migrate
63    python manage.py cms fix-tree
64
65
66*****************************
67Backward incompatible changes
68*****************************
69
70Apphooks & Toolbars
71===================
72
73As per our deprecation policy we've now removed the backwards compatible shim
74for ``cms_app.py`` and ``cms_toolbar.py``.
75If you have not done so already, please rename these to ``cms_apps.py`` and ``cms_toolbars.py``.
76
77
78Permissions
79===========
80
81The permissions system was heavily refactored. As a result, several internal
82functions and methods have been removed or changed.
83
84Functions removed:
85
86 * ``user_has_page_add_perm``
87 * ``has_page_add_permission``
88 * ``has_page_add_permission_from_request``
89 * ``has_any_page_change_permissions``
90 * ``has_auth_page_permission``
91 * ``has_page_change_permission``
92 * ``has_global_page_permission``
93 * ``has_global_change_permissions_permission``
94 * ``has_generic_permission``
95 * ``load_view_restrictions``
96 * ``get_any_page_view_permissions``
97
98
99The following methods were changed to require a user parameter instead of a request:
100
101 * ``Page.has_view_permission``
102 * ``Page.has_add_permission``
103 * ``Page.has_change_permission``
104 * ``Page.has_delete_permission``
105 * ``Page.has_delete_translation_permission``
106 * ``Page.has_publish_permission``
107 * ``Page.has_advanced_settings_permission``
108 * ``Page.has_change_permissions_permission``
109 * ``Page.has_move_page_permission``
110
111These are also deprecated in favour of their counterparts in ``cms.utils.page_permissions``.
112
113To keep consistency with both django CMS permissions and Django permissions,
114we've modified the vanilla permissions system (``CMS_PERMISSIONS = False``)
115to require users to have certain Django permissions to perform an action.
116
117Here's an overview:
118
119============ ==================================
120Action       Permission required
121============ ==================================
122Add Page     Can Add Page & Can Change Page
123Change Page  Can Change Page
124Delete Page  Can Change Page & Can Delete Page
125Move Page    Can Change Page
126Publish Page Can Change Page & Can Publish Page
127============ ==================================
128
129This change will only affect non-superuser staff members.
130
131.. warning::
132
133    If you have a custom ``Page`` extension with a configured toolbar,
134    please see the updated :ref:`example <complete_toolbar_api>`.
135    It uses the new permission internals.
136
137
138Manual plugin rendering
139=======================
140
141We've rewritten the way plugins and placeholders are rendered.
142As a result, if you're manually rendering plugins and placeholders
143you'll have to adapt your code to match the new rendering mechanism.
144
145To render a plugin programmatically, you will need a context and request object.
146
147.. warning:: Manual plugin rendering is not a public API, and as such it's subject to change without notice.
148
149         ::
150
151             from django.template import RequestContext
152             from cms.plugin_rendering import ContentRenderer
153
154             def render_plugin(request, plugin):
155                 renderer = ContentRenderer(request)
156                 context = RequestContext(request)
157                 # Avoid errors if plugin require a request object
158                 # when rendering.
159                 context['request'] = request
160                 return renderer.render_plugin(plugin, context)
161
162Like a plugin, to render a placeholder programmatically, you will need a context and request object.
163
164
165.. warning:: Manual placeholder rendering is not a public API, and as such it's subject to change without notice.
166
167             ::
168
169                 from django.template import RequestContext
170                 from cms.plugin_rendering import ContentRenderer
171
172                 def render_placeholder(request, placeholder):
173                     renderer = ContentRenderer(request)
174                     context = RequestContext(request)
175                     # Avoid errors if plugin require a request object
176                     # when rendering.
177                     context['request'] = request
178                     content = renderer.render_placeholder(
179                        placeholder,
180                        context=context,
181                     )
182                     return content
183