May 2, 2023
---
local:
depth: 1
---
This release adds support for Django 4.2.
On deleting a page, image, document or snippet, the confirmation screen now provides a summary of where the object is used, allowing users to see the effect that deletion will have elsewhere on the site. This also prevents objects from being deleted in cases where deletion would be blocked by an on_delete=PROTECT
constraint. This feature was developed by Sage Abdullah.
The image library can now be configured to allow uploading SVG images. These are handled by the {% image %}
template tag as normal, with some limitations on image operations - for full details, see [](svg_images). This feature was developed by Joshua Munn, and sponsored by YouGov.
Support for adding custom validation logic to StreamField blocks has been formalised and simplified. For most purposes, raising a ValidationError
from the block's clean
method is now sufficient; more complex behaviours (such as attaching errors to a specific child block) are possible through block-specific subclasses of ValidationError
. For more details, see [](streamfield_validation). This feature was developed by Matt Westcott.
Wagtail’s icon set is now fully updated, customisable, and extendable. Built-in icons are now based on the latest FontAwesome visuals, with capabilities to both customise existing icons as well as add new ones. In particular, this includes:
{% icon %}
icon template tag to reuse icons in custom templates.register_icons
hook to register new icons and override existing ones.SnippetViewSet.icon
.For more details, see our new icons documentation.
This has been made possible thanks to a multi-year refactoring effort to migrate all icons to SVG. Thank you to all contributors who participated in this effort: Coen van der Kamp, LB (Ben) Johnston, Dan Braghis, Daniel Kirkham, Sage Abdullah, Thibaud Colas, Scott Cranfill, Storm Heg, Steve Steinwand, Jérôme Lebleu, Abayomi Victory.
The built-in accessibility checker has been updated with:
~wagtail.admin.userbar.AccessibilityItem
for simpler customisation of the checks performed.Those improvements were implemented by Albina Starykova as part of an Outreachy internship, with support from mentors Thibaud Colas, Sage Abdullah, and Joshua Munn.
Following its introduction in Wagtail 4.1, we have made a number of improvements to the page editor minimap:
Thank you to everyone who provided feedback on this new addition to the editor experience. Those changes were implemented by Thibaud Colas.
Wagtail’s admin interface now supports dark mode. The new dark theme can be enabled in account preferences, as well as configuring permanent usage of the light theme, or following system preferences.
We hope this new theme will bring accessibility improvements for users who prefer light text on dark backgrounds, and energy usage efficiency improvements for users of OLED monitors. This feature was developed by Thibaud Colas, with designs from Ben Enright.
Continuing on recent improvements to snippets, we have made the following additions to how snippets can be customised in the admin interface:
IndexView
.search_fields
and search backend via SnippetViewSet.list_filter
attribute.panels
/ edit_handler
to be specified via SnippetViewSet
.SnippetViewSet.icon
.For more details, see [](wagtailsnippets_custom_admin_views).
Developed by Sage Abdullah, these features were implemented as part of RFC 85: Snippets parity with ModelAdmin. We will start the deprecation process of the ModelAdmin contrib package in the next feature release and publish it as a separate package for users who wish to continue using it. The ModelAdmin package will be removed in Wagtail 6.0.
WAGTAILIMAGES_EXTENSIONS
setting to restrict image uploads to specific file types (Aman Pandey, Ananjan-R)Access level
to be easier to understand (Vallabh Tiwari).button-longrunning
behaviour to a Stimulus controller with support for custom label element & duration (Loveth Omokaro)change
event (George Sakkis)search_fields = []
(Daniel Kirkham)wagtail.search.utils.parse_query_string
to allow inner single quotes for key/value parsing (Aman Pandey)Locale
for more convenient usage within templates, see [](i18n_basic_example) (Andy Babic)MenuItem.name
for Snippets, Reports, and Settings menu items (Sage Abdullah)label_format
on StructBlock gracefully handles missing variables (Aadi jindal)Site.get_site_root_paths
works on cache backends that do not preserve Python objects (Jaap Roes)GroupApprovalTask
if it's locked by someone outside of the group (Sage Abdullah)WorkflowLock
is currently applied (Sage Abdullah)wagtail.schedule.cancel
(Stefan Hammer)require_admin_access()
(Stefan Hammer)radio
input fields (Mehul Aggarwal)TemplateResponse
s for users with a custom timezone (Stefan Hammer, Sage Abdullah)download_url
when WAGTAILDOCS_SERVE_METHOD
is direct
(Swojak-A)SettingsPanel
reference in the page editing TabbedInterface
example as SettingsPanel
no longer shows anything as of 4.1 (Kenny Wolf, Julian Bigler)ClusterableModel
requirements for using relations with RevisionMixin
-enabled models (Sage Abdullah)strictPropertyInitialization
in tsconfig (Thibaud Colas)Page.get_static_site_paths
method (Yosr Karoui)CollapseAll
and MinimapItem
components (Albina Starykova)AutoFieldController
to the less confusing SubmitController
(Loveth Omokaro)script
tags with template
tag for image/document bulk uploads (Rishabh Kumar Bahukhandi)SlugInput
widget (Loveth Omokaro)status
HTML usage to shared template tag (Aman Pandey, LB (Ben) Johnston, Himanshu Garg)ModelAdmin
and Snippets type index header (Aman Pandey)wagtailsearch.Query
to wagtail.contrib.search_promotions
(Karl Hobley)initErrorDetection
(tabs error counts) to a Stimulus Controller w-count
(Aman Pandey)window.addMessage
behaviour to a global event listener & Stimulus Controller approach with w-messages
(Aman Pandey)SnippetViewSet.on_register()
(Sage Abdullah)pageurl
template tag (Satvik Vashisht)window.initSlugAutoPopulate
behaviour to a Stimulus Controller w-sync
(Loveth Omokaro)status
classes to w-status
to align with preferred CSS class naming conventions (Mansi Gundre)wagtail.test.utils
to avoid cross-dependency issues (Matt Westcott)w-bulk
, remove inline script usage (Hanoon)SnippetViewSet
to extend ModelViewSet
(Sage Abdullah)w-disimissible
(Loveth Omokaro)w-autosize
controller using autosize npm package v6 (Suyash Srivastava)w-action
controller to support a click method (Suyash Srivastava)w-action
controller usage (Aadi jindal, LB (Ben) Johnston)The following features deprecated in Wagtail 3.0 have been fully removed. See Wagtail 3.0 release notes for details on these changes, including how to remove usage of these features:
wagtail.core
, wagtail.tests
, wagtail.admin.edit_handlers
and wagtail.contrib.forms.edit_handlers
are removed.StreamFieldPanel
, RichTextFieldPanel
, ImageChooserPanel
, DocumentChooserPanel
and SnippetChooserPanel
are removed.use_json_field=True
(with the exception of migrations created prior to Wagtail 5.0).BASE_URL
setting is no longer recognised.ModelAdmin.get_form_fields_exclude
method is no longer passed a request
argument.ModelAdmin.get_edit_handler
method is no longer passed a request
or instance
argument.widget_overrides
, required_fields
, required_formsets
, bind_to
, render_as_object
and render_as_field
methods on Panel
(previously EditHandler
) are removed.The following features deprecated in Wagtail 4.0 have been fully removed. See Wagtail 4.0 release notes for details on these changes, including how to remove usage of these features:
wagtail.contrib.settings.models.BaseSetting
class is removed.Page.get_latest_revision_as_page
method is removed.page
and page_id
properties and as_page_object
method on Revision
are removed.createPageChooser
, createSnippetChooser
, createDocumentChooser
and createImageChooser
are removed.wagtail.contrib.modeladmin.menus.SubMenu
class is removed.wagtail.contrib.modeladmin.helpers.AdminURLHelper
are now required to accept a base_url_path
keyword argument on the constructor.wagtail.admin.widgets.chooser.AdminChooser
class is removed.wagtail.snippets.views.snippets.get_snippet_edit_handler
function is removed.Django 4.0 reached end of life on 1st April 2023 and is no longer supported by Wagtail. Django 3.2 (LTS) is still supported until April 2024.
search
The search
method on pages, images and documents, and on the backend object returned by wagtail.search.backends.get_search_backend()
, no longer performs partial word matching when the Elasticsearch backend is in use. Previously, a search query such as Page.objects.search("cat")
would return results containing the word "caterpillar", while Page.objects.search("cat", partial_match=False)
would only return results for the exact word "cat". The search
method now always performs exact word matches, and the partial_match
argument has no effect. This change makes the Elasticsearch backend consistent with the database-backed full-text search backends.
To revert to the previous partial word matching behaviour, use the autocomplete
method instead - for example, Page.objects.autocomplete("cat")
. It may also be necessary to add an [](wagtailsearch_index_autocompletefield) entry for the relevant fields on the model's search_fields
definition, as the old SearchField("some_field", partial_match=True)
format is no longer supported.
The partial_match
argument on search
and SearchField
is now deprecated, and should be removed from your code; it will be dropped entirely in Wagtail 6.
When introduced in Wagtail 4.1, the ReferenceIndex
model recorded references across all of a project's models by default. The default set of models being indexed has now been changed to only those used within the Wagtail admin, specifically:
This change will remove the impact of the indexing on non-Wagtail apps and models.
If you have models that still require reference indexing, and which are not registered as snippets or with ModelAdmin, you will need to explicitly register them within your app's AppConfig.ready()
method. See Reference Index for further details.
The use of wagtail_reference_index_ignore
to prevent indexing of models is unchanged, but in many cases it may no longer be necessary.
It is recommended that the rebuild_references_index
management command is run after the upgrade to remove any unnecessary records.
Page.get_static_site_paths
method removedThe undocumented Page.get_static_site_paths
method (which returns a generator of URL paths for use by static site generator packages) has been removed. Packages relying on this functionality should provide their own fallback implementation.
wagtailsearch.Query
has moved to wagtail.contrib.search_promotions
The wagtailsearch.Query
model has been moved from the search
application to the contrib application wagtail.contrib.search_promotions
.
All imports will need to be updated and migrations will need to be run via a custom command, some imports will still work with a warning until a future version.
If you have daily hits records in the wagtailsearch.Query
you can run the management command to move these records to the new location.
./manage.py copy_daily_hits_from_wagtailsearch
Import | Old import | New import |
---|---|---|
Query Model |
from wagtail.search.models import Query |
from wagtail.contrib.search_promotions.models import Query |
QueryForm |
from wagtail.search.forms import QueryForm |
from wagtail.contrib.search_promotions.forms import QueryForm |
ModelAdmin
templatesIf there are custom styles in place for the ModelAdmin
's header content or more complex template overrides in us, there are a few changes for the following classes to be aware of.
Content | Old classes | New classes |
---|---|---|
Heading & search (contains h1 ) |
.left.header-left |
.left |
Action buttons (header_extra ) |
.right.header-right |
.right |
The slug field JavaScript behaviour was previously attached to any field with an ID of id_slug
, this has now changed to be any field with the appropriate Stimulus data attributes.
If using a custom edit handler or set of panels for page models, the correct widget will now need to be used for these data attributes to be included. This widget will use the WAGTAIL_ALLOW_UNICODE_SLUGS
Django setting.
from wagtail.admin.widgets.slug import SlugInput
# ... other imports
class MyPage(Page):
promote_panels = [
FieldPanel("slug", widget=SlugInput),
# ... other panels
]
Additionally, the slug behaviour can be attached to any field easily by including the following attributes in HTML or via Django's widget attrs
.
<input
type="text"
name="slug"
data-controller="w-slug"
data-action="blur->w-slug#slugify"
/>
To allow unicode values, add the data attribute value;
<input
type="text"
name="slug"
data-controller="w-slug"
data-action="blur->w-slug#slugify"
data-w-slug-allow-unicode-value="true"
/>
The mechanism for synchronising the slug field with the page title has changed, and is no longer hard-coded to activate on fields named 'title'. Notably, this change affects page panel definitions that use FieldPanel("title")
directly (rather than the convention of extending Page.content_panels
), as well as non-page models such as snippets.
To assist in upgrading these definitions, Wagtail 5.0.2 provides a new [](title_field_panel) class to be used in place of FieldPanel("title")
. For example:
from wagtail.admin.panels import FieldPanel, MultiFieldPanel
# ...
content_panels = [
MultiFieldPanel([
FieldPanel("title"),
FieldPanel("subtitle"),
]),
]
should become:
from wagtail.admin.panels import FieldPanel, MultiFieldPanel, TitleFieldPanel
# ...
content_panels = [
MultiFieldPanel([
TitleFieldPanel("title"),
FieldPanel("subtitle"),
]),
]
If you have made deeper customisations to this behaviour, or are unable to upgrade to Wagtail 5.0.2 or above, please read on as you may need to make some changes to adopt the new approach.
The title field will sync its value with the slug field on Pages if the Page is not published and the slug has not been manually changed. This JavaScript behaviour previously attached to any field with an ID of id_title
; this has now changed to be any field with the appropriate Stimulus data attributes.
There is a new Stimulus controller w-sync
which allows any field to change one or more other fields when its value changes, the other field in this case will be the slug field (w-slug
) with the id id_slug
.
If you need to hook into this behaviour, the new approach will now correctly dispatch change
events on the slug field. Alternatively, you can modify the data attributes on the fields to adjust this behaviour.
To adjust the target field (the one to be updated), you cam modify "data-w-sync-target-value"
, the default being "body:not(.page-is-live) [data-edit-form] #id_slug"
(find the field with id id_slug
when the page is not live).
To adjust what triggers the initial check (to see if the fields should be in sync), or the trigger the sync, you can use the Stimulus data-action
attributes.
<input
id="id_title"
type="text"
name="title"
data-controller="w-sync"
data-action="focus->w-sync#check blur->w-sync#apply change->w-sync#apply"
data-w-sync-target-value="body:not(.page-is-live) #some_other_slug"
/>
Above we have adjusted these attributes to add a 'change' event listener to trigger the sync and also adjusted to look for a field with some_other_slug
instead.
If you are using the wagtail.admin.widgets.AdminAutoHeightTextInput
only, this change will have no impact when upgrading. However, if you are relying on the global autosize
function at window.autosize
on the client, this will no longer work.
It is recommended that the AdminAutoHeightTextInput
widget be used instead. You can also adopt the data-controller
attribute and this will now function as before. Alternativey, you can simply add the required Stimulus data controller attribute as shown below.
Old syntax
<textarea id="story" name="story">It was a dark and stormy night...</textarea>
<script>window.autosize($('story'));</script>
New syntax
<textarea name="story" data-controller="w-autosize">It was a dark and stormy night...</textarea>
There are no additional data attributes supported at this time.
button-longrunning
) now relies on data attributesThe button-longrunning
class usage has been updated to use the newly adopted Stimulus approach, the previous data attributes will be deprecated in a future release.
If using the old approach, ensure any HTML templates are updated to the new approach before the next major release.
Old syntax
<button type="submit" class="button action-save button-longrunning" data-clicked-text="{% trans 'Creating…' %}">
{% icon name="spinner" %}
<em>{% trans 'Create' %}</em>
</button>
New syntax
Minimum required attributes are data-controller
and a data-action
.
<button type="submit" class="button action-save button-longrunning" data-controller="w-progress" data-action="w-progress#activate" data-w-progress-active-value="{% trans 'Creating…' %}">
{% icon name="spinner" %}
<em data-w-progress-target="label">{% trans 'Create' %}</em>
</button>
Stimulus targets and actions can be leveraged to revise the behaviour via data attributes.
<button ... data-w-progress-duration-value="500" ...>
- custom duration can be declared on the element<button ... class="custom-button" data-w-progress-active-class="custom-button--busy" ...>
- custom 'active' class to replace the default button-longrunning-active
(must be a single string without spaces)<button ... ><strong data-w-progress-target="label">{% trans 'Create' %}</strong></button>
- any element can be the button label (not just em
)<button ... data-action="w-progress#activate focus->w-progress#activate" ...>
- any event can be used to trigger the in progress behaviour<button ... data-action="w-progress#activate:once" ...>
- only trigger the progress behaviour once<button ... data-action="readystatechange@document->w-progress#activate:once" data-w-progress-duration-value="5000" disabled ...>
- disabled on load (once JS starts) and becomes enabled after 5s durationwindow.addMessages
replaced with event dispatchingThe undocumented window.addMessage
function is no longer available and will throw an error if called, if similar functionality is required use DOM Event dispatching instead as follows.
// old
window.addMessage('success', 'Content has updated');
// new
document.dispatchEvent(
new CustomEvent('w-messages:add', {
detail: { text: 'Content has updated', type: 'success' },
}),
);
// new (clearing existing messages before adding a new one)
document.dispatchEvent(
new CustomEvent('w-messages:add', {
detail: {
clear: true,
text: 'All content has updated',
type: 'success',
},
}),
);
// message types 'success', 'error', 'warning' are supported
Note that this event name may change in the future and this functionality is still not officially supported.
ValidationError
classesThe client-side handling of StreamField validation errors has been updated. The JavaScript classes StreamBlockValidationError
, ListBlockValidationError
, StructBlockValidationError
and TypedTableBlockValidationError
have been removed, and the corresponding Python classes can no longer be serialised using Telepath. Instead, the setError
methods on client-side block objects now accept a plain JSON representation of the error, obtained from the as_json_data
method on the Python class. Custom JavaScript code that works with these objects must be updated accordingly.
Additionally, the Python StreamBlockValidationError
, ListBlockValidationError
, StructBlockValidationError
and TypedTableBlockValidationError
classes no longer provide a params
dict with block_errors
and non_block_errors
items; these are now available as the attributes block_errors
and non_block_errors
on the exception itself (or cell_errors
and non_block_errors
in the case of TypedTableBlockValidationError
).
delete-multiple
view removedThe ability to remove multiple snippet instances from the DeleteView
and the undocumented wagtailsnippets_{app_label}_{model_name}:delete-multiple
URL pattern have been removed. The view's functionality has been replaced by the delete action of the bulk actions feature introduced in Wagtail 4.0.
The delete bulk action view now also calls the {before,after}_delete_snippet
hooks, in addition to the {before,after}_bulk_action
hooks.
If you have customised the IndexView
and/or DeleteView
views in a SnippetViewSet
subclass, make sure that the delete_multiple_url_name
attribute is renamed to delete_url_name
.
The template name for the index view of a snippet model has changed from wagtailsnippets/snippets/type_index.html
and wagtailsnippets/snippets/results.html
to wagtailsnippets/snippets/index.html
and wagtailsnippets/snippets/index_results.html
. In addition, the model index view that lists the snippet types now looks for the template wagtailsnippets/snippets/model_index.html
before resorting to the generic index template. If you have customised these templates, make sure to update them accordingly.
status
classes are now w-status
Please update any custom styling or usage within the admin when working with status tags to the following new classes.
Old | New |
---|---|
status-tag |
w-status |
primary |
w-status--primary |
disabled |
w-status--disabled |
status-tag--label |
w-status--label |
Note that a new template tag has been built for usage within the admin that may make it easier to generate status tags.
{% load wagtailadmin_tags %}
{% status "live" url="/test-url/" title=trans_title hidden_label=trans_hidden_label classname="w-status--primary" attrs='target="_blank" rel="noreferrer"' %}
{% status status_label classname="w-status--primary" %}
The Wagtail icon font has been deprecated and will be removed in a future release, as it is now unused in Wagtail itself. There are no changes to make for any icons usage via dedicated APIs such as icon
class properties. Any direct icon font usage needs to be converted to SVG icons instead, as documented in our icons overview.
To check whether your project uses the icon font, check for occurrences of:
wagtail.woff
font file.font-family: wagtail
in CSS.icon-<name>
CSS classes outside of SVG elements.The following icons are unused in Wagtail itself and will be removed in a future release. If you are using any of these icons, please replace them with an alternative (see our full list of icons), or re-add the icon to your own project.
Icon name | Alternative |
---|---|
angle-double-left |
arrow-left |
angle-double-right |
arrow-right |
arrow-down-big |
arrow-down |
arrow-up-big |
arrow-up |
arrows-up-down |
order |
chain-broken |
link |
chevron-down |
arrow-down (identical) |
dots-vertical |
dots-horizontal |
download-alt |
download (identical) |
duplicate |
copy (identical) |
ellipsis-v |
dots-horizontal |
horizontalrule |
minus |
repeat |
rotate |
reset |
rotate |
tick |
check (identical) |
undo |
rotate |
uni52 |
folder-inverse (identical) |
wagtail-inverse |
wagtail-icon |
get_admin_url_namespace()
and get_admin_base_path()
moved to SnippetViewSet
The undocumented get_admin_url_namespace()
and get_admin_base_path()
methods that were set on snippet models at runtime have been moved to the {class}~wagtail.snippets.views.snippets.SnippetViewSet
class. If you use these methods, you could access them via {meth}SnippetModel.snippet_viewset.get_admin_url_namespace() <wagtail.snippets.views.snippets.SnippetViewSet.get_admin_url_namespace>
and {meth}SnippetModel.snippet_viewset.get_admin_base_path() <wagtail.snippets.views.snippets.SnippetViewSet.get_admin_base_path>
, respectively.
get_usage()
and usage_url()
methods removedThe undocumented get_usage()
and usage_url()
methods that were set on snippet models at runtime have been removed. Calls to the get_usage()
method can be replaced with wagtail.models.ReferenceIndex.get_grouped_references_to(object)
. The usage_url()
method does not have a direct replacement, but the URL name can be retrieved via {meth}SnippetModel.snippet_viewset.get_url_name("usage") <wagtail.admin.viewsets.base.ViewSet.get_url_name>
, which can be used to construct the URL with {func}~django.urls.reverse
.