Unreleased
---
local:
depth: 1
---
This release adds support for Django 5.0. The support has also been backported to Wagtail 5.2 LTS.
A new developer tutorial series has been added to the documentation. This series builds upon the pre-existing [](/getting_started/tutorial), going through the creation and deployment of a portfolio website.
This tutorial series was created by Damilola Oladele as part of the Google Season of Docs program, with support from Meagen Voss, and Thibaud Colas. We also thank Storm Heg, Kalob Taulien, Kátia Nakamura, Mariusz Felisiak, and Rachel Smith for their support and feedback as part of the project.
Following design improvements to the page listing view, Wagtail now provides a unified search and filtering interface for all listings. This will improve navigation capabilities, particularly for sites with a large number of pages or where content tends to use a flat structure.
In this release, the universal listing interface is available for Pages, Snippets, and Forms.
This feature was developed by Ben Enright, Matt Westcott, Nick Lee, Thibaud Colas, and Sage Abdullah.
The admin interface now supports right-to-left languages, such as Persian, Arabic, Hebrew. Though there are still some areas that need improvement, all admin views will now be displayed in the correct direction. Review our UI guidelines for guidance on supporting right-to-left languages in admin interface customizations.
Thank you to Thibaud Colas, Badr Fourane, and Sage Abdullah for their work on this long-requested improvement.
The built-in accessibility checker now displays as a side panel within page and snippet editors supporting preview. The new "Checks" side panel only shows accessibility-related issues for pages with the userbar enabled in this release, but will be updated to support any content checks in the future.
This feature was implemented by Nick Lee, Thibaud Colas, and Sage Abdullah.
search_index
option to StreamField blocks to control whether the block is indexed for searching (Vedant Pandey)UniqueConstraint
in place of unique_together
for {class}~wagtail.models.TranslatableMixin
's system check (Temidayo Azeez, Sage Abdullah)IndexView.get_add_url()
in snippets index view template (Christer Jensen, Sage Abdullah)Page.permissions_for_user()
to be overridden by specific page types (Sébastien Corbin)extra_actions
blocks to Snippets and generic index templates (Bhuvnesh Sharma)panels
/ edit_handler
on ModelViewSet
(Sage Abdullah)PagePermissionPolicy
in wagtail.permissions
module (Sage Abdullah)max_length
(Elhussein Almasri)TypedTableBlock
(Tommaso Amici, Cynthia Kiser)TableBlock
header controls to a field that requires user input (Bhuvnesh Sharma, Aman Pandey, Cynthia Kiser)WAGTAILADMIN_LOGIN_URL
setting to allow customising the login URL (Neeraj Yetheendran)DrilldownController
and w-drilldown
component to support drilldown menus (Thibaud Colas)caption
on admin UI Table component (Aman Pandey)SnippetViewSet
& ModelViewSet
to support being copied, this can be disabled by copy_view_enabled = False
(Shlomo Markowitz)STORAGES
setting introduced in Django 4.2 (phijma-leukeleu)index_results.html
or index_results_template_name
override on initial load (Stefan Hammer)last_published_by_user
(Chiemezuo Akujobi)alias
and specific
(Tomasz Knapik)ActionController
explicitly checks for elements that allow select functionality (Nandini Arora)FormSubmissionsPanel
on Django 5.0 when creating a new form page (Matt Westcott)MultipleChooserPanel
modal works correctly when USE_THOUSAND_SEPARATOR
is True
for pages with ids over 1,000 (Sankalp, Rohit Sharma)th
) for visual spacing, ensure this is ignored by accessibility tooling (V Rohitansh)SiteSetting.DoesNotExist
error when retrieving settings for an unrecognised site (Nick Smith)exclude_fields_in_copy
are correctly excluded in new copies, resolving to the default value (Elhussein Almasri)default_ordering
set on IndexView is preserved if ModelViewSet does not specify an explicit ordering (Cynthia Kiser)_()
within templates (Chiemezuo Akujobi)MultipleChooserPanel
may require a chooser viewset and how the functionality is expected to work (Andy Chosak)Page
model reference get_children
documentation (Salvo Polizzi)body.ready
) from multiple JavaScript implementations to one Stimulus controller w-init
(Chiemezuo Akujobi)arg=_('...')
in all wagtailadmin
module templates (Chiemezuo Akujobi)ruff
and replace black
with ruff format
(John-Scott Atlakson)laces
library (Tibor Leupold){% formattedfield %}
tag to replace direct use of wagtailadmin/shared/field.html
(Matt Westcott)ActionController
to have a noop
method to more easily leverage standalone Stimulus action options (Nandini Arora)skipLibCheck
for TypeScript (LB (Ben) Johnston)CloneController
to auto clear the added content after a set duration (LB (Ben) Johnston)BaseListingView
(Matt Westcott)c-
, o-
, u-
, t-
, is-
prefixes (Thibaud Colas)initTooltips
in favour of Stimulus controller (LB (Ben) Johnston)InitController
to allow for custom event dispatching when ready (Aditya, LB (Ben) Johnston)UnsavedController
(Sai Srikar Dumpeti, LB (Ben) Johnston)OrderableController
with a more accessible solution (Aman Pandey, LB (Ben) Johnston)FileResponse
when serving files such as Images or Documents (Jake Howard)WidgetWithScript
base widget class (LB (Ben) Johnston)Features previously deprecated in Wagtail 4.2, 5.0 and 5.1 have been fully removed. For additional details on these changes, see:
The most significant changes are highlighted below.
The wagtail.contrib.modeladmin
app has been removed. If you wish to continue using it, it is available as the external package wagtail-modeladmin
.
The Elasticsearch 5 and 6 backends have been removed. If you are using one of these backends, you will need to upgrade to Elasticsearch 7 or 8 before upgrading to Wagtail 6.0.
use_json_field=True
The use_json_field
argument to StreamField
is no longer required, and can be removed. StreamField now consistently uses JSONField for its database representation, and Wagtail 5.0 required older TextField-based streams to be migrated. As such, use_json_field
no longer has any effect.
WAGTAILADMIN_GLOBAL_PAGE_EDIT_LOCK
setting is no longer recognised and should be replaced with WAGTAILADMIN_GLOBAL_EDIT_LOCK
.Query
model is no longer part of the wagtail.search
module; it can now be found in the optional wagtail.contrib.search_promotions
app.wagtail.models.UserPagePermissionsProxy
class and get_pages_with_direct_explore_permission
, get_explorable_root_page
and users_with_page_permission
functions have been removed; equivalent functionality exists in the wagtail.permission_policies.pages.PagePermissionPolicy
class.permission_type
field of the GroupPagePermission
model has been removed; the permission
field (a foreign key to Django's Permission
model) should be used instead.partial_match
argument on SearchField
and on search
methods has been removed. AutocompleteField
and the autocomplete
method should be used instead.insert_editor_css
hook has been removed; the insert_global_admin_css
hook should be used instead.wagtail.contrib.frontend_cache
module now supports azure-mgmt-cdn
version 10 and azure-mgmt-frontdoor
version 1 as its minimum supported versions.Task.page_locked_for_user
method has been removed; Task.locked_for_user
should be used instead.{% icon %}
template tag no longer accepts class_name
as an argument; classname
should be used instead.wagtail.tests.utils
module has been removed and can now be found at wagtail.test.utils
.wagtailadmin/shared/field_as_li.html
has been removed, and should be replaced with wagtailadmin/shared/field.html
enclosed in an <li>
tag.wagtail:show
and wagtail:hide
on showing and hiding dialogs have been removed; w-dialog:show
and w-dialog:hide
should be used instead.headerSearch
, initTagField
, cancelSpinner
and unicodeSlugsEnabled
have been removed; these should be replaced with Stimulus controllers.SnippetViewSet
& ModelViewSet
copy view enabled by defaultThe newly introduced copy view will be enabled by default for all ModelViewSet
and SnippetViewSet
classes.
This can be disabled by setting copy_view_enabled = False
, for example.
class PersonViewSet(SnippetViewSet):
model = Person
#...
copy_view_enabled = False
class PersonViewSet(ModelViewSet):
model = Person
#...
copy_view_enabled = False
See [](modelviewset_copy) for additional details about this feature.
Django versions prior to 4.2 are no longer supported as of this release; please upgrade to Django 4.2 or above before upgrading Wagtail.
SlugInput
widget is now the default for SlugField
fieldsIn Wagtail 5.0 a new SlugInput
admin widget was added to support slug behavior in Page and Page copy forms. This widget was included by default if the promote_panels
fields layout was customised, causing confusion.
As of this release, any forms that inherit from WagtailAdminModelForm
(includes page and snippet model editing) will now use the SlugInput
by default on all models with SlugField
fields.
Previously, the widget had to be explicitly added.
from wagtail.admin.widgets.slug import SlugInput
# ... other imports
class MyPage(Page):
promote_panels = [
FieldPanel("slug", widget=SlugInput),
# ... other panels
]
Keeping the widget as above is fine, but will no longer be required. The JavaScript field behavior will be included by default.
# ... imports
class MyPage(Page):
promote_panels = [
FieldPanel("slug"),
# ... other panels
]
If you do not want this for some reason, you will now need to declare a different widget.
from django.forms.widgets import TextInput
# ... other imports
class MyPage(Page):
promote_panels = [
FieldPanel("slug", widget=TextInput), # use a plain text field
# ... other panels
]
Page
objects or subclasses of DraftStateMixin
Prior to this release, the database record of a Page
or any subclass of DraftStateMixin
either contained the live data (if published), the state of the last published version (if unpublished), or the state of the first revision (if never published). Subsequent draft edits would create new Revision
records, but the main database record would not be updated. As a result, the database record could lag substantially behind the current state of the object, causing unexpected behaviour particularly when unique constraints are in use.
As of this release, the database record of a non-live object will be updated to reflect the draft state of the object. This is unlikely to have a visible effect on existing sites, since the admin backend works with the Revision
records while the site front-end typically filters out non-live objects. However, any code that relies on the database record being untouched by draft edits (for example, using it to store a specific approved / archived state of the page) may need to be updated.
filter_queryset
and get_filtered_queryset
methods no longer return filtersThe undocumented internal methods filter_queryset(queryset)
on wagtail.admin.views.generic.IndexView
, and get_filtered_queryset()
on wagtail.admin.views.reports.ReportView
, now return just the filtered queryset; previously they returned a tuple of (filters, queryset)
. The filterset instance is always available as the cached property self.filters
.
window.enableDirtyFormCheck
functionThe admin frontend window.enableDirtyFormCheck
will be removed in a future release and as of this release only supports the basic initialization.
The previous approach was to call a window global function as follows.
window.enableDirtyFormCheck('.my-form', { alwaysDirty: true, confirmationMessage: 'You have unsaved changes'});
The new approach will be data attribute driven as follows.
<form
method="POST"
data-controller="w-unsaved"
data-action="w-unsaved#submit beforeunload@window->w-unsaved#confirm change->w-unsaved#check keyup->w-unsaved#check"
data-w-unsaved-confirm-value="This page has unsaved changes." // equivalent to `confirmationMessage`.
data-w-unsaved-force-value="true" // equivalent to `alwaysDirty`.
data-w-unsaved-watch-value="edits comments" // can add 'comments' if comments is enabled, defaults to only 'edits'.
>
... form contents
</form>
data-tippy-content
attribute support will be removedThe implementation of the JS tooltips have been fully migrated to the Stimulus w-tooltip
/TooltipController
implementation.
Dynamic support for any data-tippy-content="..."
usage will be removed this release, for example, within chooser modals or dynamic html response data.
Some minimal backwards compatibility support for data-tippy-content
will work until a future release, but only in the initial HTML response on a page.
These HTML data attributes were not documented, but if any custom code implemented custom tooltips, these will need to be changed.
Old | New | Notes |
---|---|---|
data-controller="w-tooltip" |
Required, new addition for any usage | |
data-tippy-content="{% trans 'History' %}" |
data-w-tooltip-content-value="{% trans 'History' %}" |
Required |
data-tippy-offset="[12, 24]" |
data-w-tooltip-offset-value="[12, 24]" |
Optional, default is no offset |
data-tippy-placement="top" |
data-w-tooltip-placement-value="top" |
Optional, default is 'bottom' |
WidgetWithScript
base widget classThe undocumented WidgetWithScript
class that used inline scripts to attach JavaScript to widgets will be removed in a future release.
This approach creates security risks and will not be compliant with CSP support, instead it's recommended that all similar requirements migrate to use the recommended Stimulus JS integration approach.
A full example of how to build this has been documented on (extending client-side behavior)[extending_client_side_stimulus_widget], a basic example is below.
from django.forms import Media, widgets
class CustomRichTextArea(WidgetWithScript, widgets.Textarea):
def render_js_init(self, id_, name, value):
return f"window.customEditorInitScript({json.dumps(id_)});"
@property
def media(self):
return Media(js=["vendor/custom-editor.js"])
from django.forms import Media, widgets
class CustomRichTextArea(widgets.Textarea):
def build_attrs(self, *args, **kwargs):
attrs = super().build_attrs(*args, **kwargs)
attrs['data-controller'] = 'cusom-editor'
@property
def media(self):
return Media(js=["vendor/custom-editor.js","js/custom-editor-controller.js"])
// myapp/static/js/custom-editor-controller.js
class CustomEditorController extends window.StimulusModule.Controller {
connect() {
window.customEditorInitScript(this.element.id);
}
}
window.wagtail.app.register('color', CustomEditorController);