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