NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #5051 most downloaded on PyPI
A Django content management system.
Last release 1 months ago
25 Aug 2026
Release timing varies
gaps range from 9 days to 2 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
13 years old
300 releases · first in 2014
Security fix: Improper restriction handling on Pages admin API (xuliang@QAX, Dan Braghis)
PageViewSet (Sage Abdullah)FieldPanel(required_on_save=True) for AbstractFormField's field_type field (Alex Tomkins)Button component render a <button> element when no URL is supplied (Nayeli De Jesus, LB (Ben Johnston), Sage Abdullah)submenu_hook attribute to ViewSetGroup for collecting submenu items registered via a hook (Hunzlah Malik, MariyaOT, Sage Abdullah)ViewSet.menu_order when used in a ViewSetGroup (Sage Abdullah)ChoiceBlock (Sage Abdullah)id as a template context variable when rendering children of StreamBlock and ListBlock (Sage Abdullah)SnippetChooserViewSet.widget_class a class instead of an instance (Amrinder Singh, Sage Abdullah)WAGTAILSIMPLETRANSLATION_SYNC_PAGE_TREE = True (Sahil Kumar)SnippetChooserViewSet (Sage Abdullah)format_html in construct_homepage_panels example (Andreas Nüßlein)request.in_preview_panel to explain its use (Raghad Dahi)get_api_representation (Pranith Beeram)USE_L10N setting from internationalization and project setup documentation (Piyush Bhakuni)request argument to cache_object in Page._get_site_root_paths() for correctness (Kailesh)EMAIL_BACKEND setting deprecation on Django 6.1 when running project template tests (Sage Abdullah)one and not match support to RulesController (LB (Ben Johnston))One column per quarter.
5.2, 6.0, 6.1
3.10, 3.11, 3.12, 3.13, 3.14
7.4 LTS
5.2, 6.0
3.10, 3.11, 3.12, 3.13, 3.14
August 25, 2026
---
local:
depth: 1
---
Wagtail 8.0 introduces a preview of a new v3 API, built on Django Ninja and type hints. The v2 API was designed for headless site and other data publication needs. v3 serves similar use cases, and adds support for CMS operations on top: authenticated clients can create, edit, publish and unpublish, move, copy, and revert content, and manage revisions, across pages, sites, locales, redirects, images, documents, and API-enabled snippets. You can create new pages with writable StreamField content, rich text as HTML or Markdown. The API auto-generates precise OpenAPI 3.1 schemas based on your project’s models, and uses API token authentication tied to user accounts. See the v3 API documentation for full details.
The v3 API is released as a preview to signify we want to adapt it based on feedback: it may change in backwards-incompatible ways in any release until stabilised. We welcome feedback via discussions, feature requests and bug reports. This feature was developed by Thibaud Colas and Sage Abdullah.
This release introduces the ability to swap out the base Page model with a custom project-specific model. Any fields and methods defined on this model will be shared by all page types. This feature is only supported for newly-created projects, and certain add-on packages may not yet be compatible with it (see ). This feature was developed by Matt Westcott.
A permission policy for every model managed by Wagtail is now registered to a global permission policy registry. The registry allows you to retrieve the permission policy of a model from anywhere in the code, which can be useful for performing permission checks outside of a view's request-response cycle, such as in a background task. It can also be used to implement custom permission logic, including for Wagtail's built-in models.
For more details, refer to the reference documentation. This feature was developed by Sage Abdullah.
This release introduces formal support for Django 6.1.
The Wagtail user guide has been updated to use a new versioning scheme, better search and navigation, and better support for Right-to-Left (RTL) languages.
Thank you to Raghad Dahi for leading this work. For more information, read her project report: Streamlining content ops with LLMs: Wagtail user guide.
We now provide SBOM exports of our dependency graph in SPDX JSON format. This complements a number of improvements to dependency management, implemented by Sage Abdullah, Dan Braghis, and Thibaud Colas:
The internal Pages admin API incorrectly returned page fields without access control when they were declared in api_fields. A user with access to the Wagtail admin could use this API to fetch draft and live page fields’ contents that are part of api_fields on the base page model (title, slug, seo_title, search_description), as well as all custom fields declared in api_fields.
Many thanks to xuliang@QAX for reporting this issue. For further details, please see security advisory GHSA-3vrh-m9w7-v94f.
By passing specific HTTP headers to the document serve URL endpoint, an attacker was able to determine whether a document with a given ID matched a specified SHA1 hash, regardless of any permission restrictions on the document or knowing its filename. This could allow an attacker to determine whether a document with a specific known hash is present in the Wagtail document library.
Many thanks to Anand Himanshu for reporting this issue. For further details, please see security advisory GHSA-92hv-j533-69wc.
The Documents and Images API incorrectly listed items in descendants of private collections, which should inherit the view restrictions defined on their ancestors. A user with access to the API could see the filename and name of documents and images in these descendant collections.
Many thanks to Ta Duc Thien for reporting this issue. For further details, please see security advisory GHSA-c2xx-cjmh-9q8f.
A CMS user with "add" permission over a snippet model, but not "change" or "view" permission, could copy an existing snippet that they do not have access to, allowing them to view its contents.
Many thanks to tinyb0y for reporting this issue. For further details, please see security advisory GHSA-x5cx-w6p2-mxf2.
A CMS user with the "submit translations" permission, could use the Admin API's "copy for translation" endpoint to copy an existing page that they do not have edit access to, allowing them to view its contents.
Many thanks to tinyb0y for reporting this issue. For further details, please see security advisory GHSA-jm5p-837g-rv8g.
PageViewSet (Sage Abdullah)FieldPanel(required_on_save=True) for AbstractFormField's field_type field (Alex Tomkins)Button component render a <button> element when no URL is supplied (Nayeli De Jesus, LB (Ben Johnston), Sage Abdullah)submenu_hook attribute to ViewSetGroup for collecting submenu items registered via a hook (Hunzlah Malik, MariyaOT, Sage Abdullah)ViewSet.menu_order when used in a ViewSetGroup (Sage Abdullah)ChoiceBlock (Sage Abdullah)id as a template context variable when rendering children of StreamBlock and ListBlock (Sage Abdullah)SnippetChooserViewSet.widget_class a class instead of an instance (Amrinder Singh, Sage Abdullah)WAGTAILSIMPLETRANSLATION_SYNC_PAGE_TREE = True (Sahil Kumar)SnippetChooserViewSet (Sage Abdullah)format_html in construct_homepage_panels example (Andreas Nüßlein)request.in_preview_panel to explain its use (Raghad Dahi)get_api_representation (Pranith Beeram)USE_L10N setting from internationalization and project setup documentation (Piyush Bhakuni)request argument to cache_object in Page._get_site_root_paths() for correctness (Kailesh)EMAIL_BACKEND setting deprecation on Django 6.1 when running project template tests (Sage Abdullah)one and not match support to RulesController (LB (Ben Johnston))Features previously deprecated in Wagtail 6.4, 7.0, 7.1, 7.2, and 7.3 have been fully removed:
construct_wagtail_userbar hook now receives a third argument page in addition to request and items; hook functions that only accept two arguments will now fail.buildExpandingFormset and initPrefillTitleFromFilename are removed.TAG_LIMIT and TAG_SPACES_ALLOWED are replaced by WAGTAIL_TAG_LIMIT and WAGTAIL_TAG_SPACES_ALLOWED.wagtailadmin/generic/index.html must now provide a breadcrumbs_items context variable.wagtailadmin/pages/_editor_js.html is removed.PageListingButton, SnippetListingButton and UserListingButton classes are removed in favour of ListingButton and Button.wagtail.admin.signals.init_new_page is moved to wagtail.signals.init_new_page.wagtail.telepath is moved to wagtail.admin.telepath.wagtail.widget_adapters is moved to wagtail.admin.telepath.widgets.wagtailadmin/js/telepath/telepath.js is removed.INDEX option on WAGTAILSEARCH_BACKENDS is replaced by INDEX_PREFIX (for example, "INDEX": "mysite" now becomes "INDEX_PREFIX": "mysite_").render method.resetValue property is removed from TeleportController.For additional details on these changes, see:
Browser support for AVIF and WebP is now solid enough that Wagtail no longer converts images in these formats to PNG when no output format is specified. Rather than relying on this setting, we recommend controlling output formats explicitly with the format-* filter or picture template tag. See for more details.
If you need to retain the previous behavior as-is, add the following to your settings:
WAGTAILIMAGES_FORMAT_CONVERSIONS = {
"bmp": "png",
"heic": "jpeg",
"avif": "png",
"webp": "png",
}
azure-mgmt-cdn, azure-mgmt-frontdoor, and azure-mgmt-resource packages will be droppedIf you are using the front-end cache invalidator module (wagtail.contrib.frontend_cache) with Azure CDN or Azure Front Door, the following packages need to be updated:
azure-mgmt-cdn to version 13 or aboveazure-mgmt-frontdoor to version 1.1 or aboveIn addition, if you do not set SUBCRIPTION_ID and thus rely on azure-mgmt-resource to retrieve the default subscription, you should install the azure-mgmt-subscription package instead of (or in addition to) azure-mgmt-resource.
Support for older versions will be dropped in a future release.
Reusable apps that work with the Page model are likely to require updating in order to be usable on projects that use the new custom base page model feature. This process is detailed at .
If you use the and have a {class}~wagtail.admin.viewsets.model.ModelViewSet, {class}~wagtail.snippets.views.snippets.SnippetViewSet, or {class}~wagtail.admin.viewsets.chooser.ChooserViewSet that defines a custom value for the (previously-undocumented) {attr}~wagtail.admin.viewsets.model.ModelViewSet.permission_policy, you must now register the permission policy separately.
Registering a permission policy can be done by calling
register_permission_policy(Model, <policy_instance>)
at the top of the model app's wagtail_hooks.py.
# wagtail_hooks.py
from wagtail.permissions import register_permission_policy
from .models import MyModel
register_permission_policy(MyModel, my_custom_policy_instance)
... # More customizations
Alternatively, you can also put the registration in the app's
AppConfig.ready().
# apps.py
class MyAppConfig(AppConfig):
...
def ready(self):
from wagtail.permissions import register_permission_policy
from .models import MyModel
register_permission_policy(MyModel, my_custom_policy_instance)
If you do not register the permission policy explicitly, Wagtail will automatically register the viewset's permission_policy, and a deprecation warning will be raised. This support will be removed in a future release.
This change does not affect viewsets that do not have a custom permission_policy.
SnippetChooserViewSet.widget_class is now a classThe SnippetChooserViewSet.widget_class attribute now correctly returns a widget class instead of an instance, consistent with ChooserViewSet.widget_class. This change may require updates to any customizations that relied on the previous behavior, such as an override in a SnippetChooserViewSet subclass that uses super().widget_class.
ViewSet.menu_order is now respected when used in a ViewSetGroup{class}~wagtail.admin.viewsets.base.ViewSets that are registered as part of a {class}~wagtail.admin.viewsets.base.ViewSetGroup now have their {attr}~wagtail.admin.viewsets.base.ViewSet.menu_order respected instead of always using its position in ViewSetGroup.items.
If you rely on the previous behavior that used the items ordering, remove {attr}~wagtail.admin.viewsets.base.ViewSet.menu_order in your ViewSet definition.
submissions_list_view_class on form page models no longer worksThe submissions_list_view_class attribute on the form builder's AbstractForm model, previously documented at , is no longer directly usable. This is because the wagtail.contrib.forms.views module can no longer be imported at model load time without introducing a circular import, and so there is no way to refer to a subclass of SubmissionsListView within a model definition. Instead, the get_submissions_list_view_class method can be overridden to achieve the same result. First, the definition of the SubmissionsListView subclass, and the import of SubmissionsListView, should be moved to a separate views module within the app. Then, the attribute assignment:
class FormPage(AbstractEmailForm):
# ...
submissions_list_view_class = CustomSubmissionsListView
can be replaced with:
class FormPage(AbstractEmailForm):
# ...
def get_submissions_list_view_class(self):
from myapp.views import CustomSubmissionsListView
return CustomSubmissionsListView
request argument to Page._get_site_root_paths is now cache_objectThe request argument to the undocumented method Page._get_site_root_paths() is renamed to cache_object to reflect the fact that it is not always a request object, but may be any object that can be used for caching purposes.
If you pass request as a positional argument, no changes are needed. If you pass request as a keyword argument to this method, you will need to update the argument name to cache_object in your code or turn it into a positional argument.
Passing a request keyword argument will continue to work for now and raise a deprecation warning, but support for this will be removed in a future release.
Security fix: Improper restriction handling on Pages admin API (xuliang@QAX, Dan Braghis)
PageViewSet (Sage Abdullah)FieldPanel(required_on_save=True) for AbstractFormField's field_type field (Alex Tomkins)Button component render a <button> element when no URL is supplied (Nayeli De Jesus, LB (Ben Johnston), Sage Abdullah)submenu_hook attribute to ViewSetGroup for collecting submenu items registered via a hook (Hunzlah Malik, MariyaOT, Sage Abdullah)ViewSet.menu_order when used in a ViewSetGroup (Sage Abdullah)ChoiceBlock (Sage Abdullah)id as a template context variable when rendering children of StreamBlock and ListBlock (Sage Abdullah)SnippetChooserViewSet.widget_class a class instead of an instance (Amrinder Singh, Sage Abdullah)WAGTAILSIMPLETRANSLATION_SYNC_PAGE_TREE = True (Sahil Kumar)SnippetChooserViewSet (Sage Abdullah)format_html in construct_homepage_panels example (Andreas Nüßlein)request.in_preview_panel to explain its use (Raghad Dahi)request argument to cache_object in Page._get_site_root_paths() for correctness (Kailesh)EMAIL_BACKEND setting deprecation on Django 6.1 when running project template tests (Sage Abdullah)one and not match support to RulesController (LB (Ben Johnston))Docs: Fix panel classname and deprecated usage of format_html in construct_homepage_panels example (Andreas Nüßlein)
PageViewSet (Sage Abdullah)FieldPanel(required_on_save=True) for AbstractFormField's field_type field (Alex Tomkins)Button component render a <button> element when no URL is supplied (Nayeli De Jesus, LB (Ben Johnston), Sage Abdullah)submenu_hook attribute to ViewSetGroup for collecting submenu items registered via a hook (Hunzlah Malik, MariyaOT, Sage Abdullah)ViewSet.menu_order when used in a ViewSetGroup (Sage Abdullah)ChoiceBlock (Sage Abdullah)id as a template context variable when rendering children of StreamBlock and ListBlock (Sage Abdullah)SnippetChooserViewSet.widget_class a class instead of an instance (Amrinder Singh, Sage Abdullah)WAGTAILSIMPLETRANSLATION_SYNC_PAGE_TREE = True (Sahil Kumar)SnippetChooserViewSet (Sage Abdullah)format_html in construct_homepage_panels example (Andreas Nüßlein)request.in_preview_panel to explain its use (Raghad Dahi)request argument to cache_object in Page._get_site_root_paths() for correctness (Kailesh)EMAIL_BACKEND setting deprecation on Django 6.1 when running project template tests (Sage Abdullah)one and not match support to RulesController (LB (Ben Johnston))Security fix: Improper restriction handling on Pages admin API (xuliang@QAX, Dan Braghis)
ContentCheckerItem subclasses (Robert Rollins)last_published_at noon alias pages on first publish (Kevin Howbrook)August 20,2026
---
local:
depth: 1
---
The internal Pages admin API incorrectly returned page fields without access control when they were declared in api_fields. A user with access to the Wagtail admin could use this API to fetch draft and live page fields’ contents that are part of api_fields on the base page model (title, slug, seo_title, search_description), as well as all custom fields declared in api_fields.
Many thanks to xuliang@QAX for reporting this issue. For further details, please see security advisory GHSA-3vrh-m9w7-v94f.
By passing specific HTTP headers to the document serve URL endpoint, an attacker was able to determine whether a document with a given ID matched a specified SHA1 hash, regardless of any permission restrictions on the document or knowing its filename. This could allow an attacker to determine whether a document with a specific known hash is present in the Wagtail document library.
Many thanks to Anand Himanshu for reporting this issue. For further details, please see security advisory GHSA-92hv-j533-69wc.
The Documents and Images API incorrectly listed items in descendants of private collections, which should inherit the view restrictions defined on their ancestors. A user with access to the API could see the filename and name of documents and images in these descendant collections.
Many thanks to Ta Duc Thien for reporting this issue. For further details, please see security advisory GHSA-c2xx-cjmh-9q8f.
A CMS user with "add" permission over a snippet model, but not "change" or "view" permission, could copy an existing snippet that they do not have access to, allowing them to view its contents.
Many thanks to tinyb0y for reporting this issue. For further details, please see security advisory GHSA-x5cx-w6p2-mxf2.
A CMS user with the "submit translations" permission, could use the Admin API's "copy for translation" endpoint to copy an existing page that they do not have edit access to, allowing them to view its contents.
Many thanks to tinyb0y for reporting this issue. For further details, please see security advisory GHSA-jm5p-837g-rv8g.
ContentCheckerItem subclasses (Robert Rollins)last_published_at noon alias pages on first publish (Kevin Howbrook)CVE-2026-54259 : Improper restriction handling on Documents and Images chosen endpoints
StructBlock.Meta.form_layout (Matthias Brück, Sage Abdullah)gettext_lazy for a model's verbose_name (James Biggs)return in example views for template components (Tibor Leupold)June 15, 2026
---
local:
depth: 1
---
This release addresses a faulty permission check in the document and image choosers. The Documents and Images chooser's chosen endpoint incorrectly listed items for which the user has not been granted choose permission. A user with access to the Wagtail admin could see the filename and name and URLs of documents and images in those collections.
Many thanks to Harsh Akshit for reporting this issue. For further details, please see the CVE-2026-54259 security advisory.
This release addresses a potential denial-of-service attack on the image preview endpoint. An authenticated admin user could trigger expensive rendition processing with purposefully crafted filter specs resulting in potentially service degradation.
Many thanks to 0x1saac for reporting this issue. For further details, please see the CVE-2026-54260 security advisory.
This release addresses a faulty permission check in the image preview endpoint. A user with access to the Wagtail admin could preview any image. The existing data of the image object itself is not exposed. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to 0x1saac and Harsh Akshit for reporting this issue. For further details, please see the CVE-2026-54261 security advisory.
This release addresses a faulty permission check in the simple_translation app. A low-level user with the "Can submit translation" permission could create translations for any page, including those they do not have permissions for.
Many thanks to Devansh Bordia and alanturing881 for reporting this issue. For further details, please see the CVE-2026-54262 security advisory.
This release addresses a reflected cross-site scripting (XSS) vulnerability on the dynamic image URL generator view within the Wagtail admin interface. A user with a limited-permission editor account for the Wagtail admin could craft a URL that, when viewed by a user with higher privileges, could perform actions with that user's credentials.
Many thanks to Thibaud Colas for reporting this issue. For further details, please see the CVE-2026-54263 security advisory.
StructBlock.Meta.form_layout (Matthias Brück, Sage Abdullah)gettext_lazy for a model's verbose_name (James Biggs)return in example views for template components (Tibor Leupold)Fix: Reinstate missing file jquery.fileupload-validate.js (Rob Brackett)
jquery.fileupload-validate.js (Rob Brackett)May 19, 2026
---
local:
depth: 1
---
jquery.fileupload-validate.js (Rob Brackett)Fix: CVE-2026-44197 : Improper permission handling when comparing revisions (Seoyoung Kang, Jake Howard)
is_deferred_validation flag to support skipping custom validation when saving drafts (Daniel Kirkham)include_root parameter to admin pages API endpoint (Divyansh Mishra)creation_form_class on ChooserViewSet as a dotted path string (K Adithya)WAGTAILDOCS_MAX_UPLOAD_SIZE setting for specifying maximum document file size (Om Harsh)WAGTAILDOCS_MAX_UPLOAD_SIZE to 10MB (Thibaud Colas)format-* operations on SVG images (Ankit Kumar)FormState model to improve compatibility with cookie-based sessions (Sage Abdullah)WAGTAILADMIN_PAGE_SEARCH_FILTER_BY_PERMISSIONS setting to disable permission filtering on page searches (Matt Westcott)SnippetViewSet/ModelViewSet's list_display (Srishti Jaiswal)empty-meta-description to validate meta description tags are not empty (Thibaud Colas)extractMetrics method to PreviewController to retrieve content metrics from the preview panel (Thibaud Colas)routablefullpageurl template tag (Pravin Kamble)PageViewSet (Sage Abdullah)get_object() DB query in API detail view (Siddheshwar Kadam)ImageBlock alt text populates on choosing a new image after unchecking decorative state (Pratham Jaiswal)verbose_name_plural for Query model in search promotions app (Saptami)max_count or max_count_per_parent (Lasse Schmieding)max_count_per_parent being moved under one parent (James Biggs)ChoiceBlock choices in block values (Devarshi Mani Tripathi)filter_spec parameter of ImageRenditionField (Soumya-codr)nested_default_fields attribute on API viewsets (Deepanshu Tevathiya)http with https in example URLs (Kunal Gupta)pathlib.Path for settings in "Integrating into Django" documentation (Kunal Gupta)ReferenceIndex API (Saptami)format_html in insert_global_admin_js example (Lasse Schmieding)published and unpublished signals (Kunal Hemnani)list_export in reports accepts a dotted path for nested attribute resolution (mikko2577)WAGTAILDOCS_SERVE_METHOD (Thibaud Colas)wagtail.admin.ui.tables (Sage Abdullah)hash_filelike test case to account for line break differences on Windows (Mustansir Dabhiya)PermissionError on document serve tests under Windows (Matt Westcott)if syntax (Sage Abdullah)timeout-minutes to GitHub Actions workflow jobs (Ashutosh)SwapController (LB (Ben Johnston))w-block- prefixes for block type class names (Kalash Kumari Thakur)May 5, 2026
---
local:
depth: 1
---
Wagtail 7.4 is designated a Long Term Support (LTS) release. Long Term Support releases will continue to receive maintenance updates as necessary to address security and data-loss related issues, up until the next LTS release (typically a period of 12 months).
The autosave and concurrent editing notifications features have been improved based on user feedback. The improvements include: better handling of race conditions and network failures, refined messaging and alignment of indicator elements, as well as clearer display of idle users editing the same page.
These improvements were developed by Sage Abdullah, with support from the Wagtail UI team.
StreamField blocks now support deferred validation of required fields when saving drafts of pages (or snippets using DraftStateMixin). Users can now add a StreamField block and save work-in-progress versions without filling in all fields of the block. Validation is applied as normal when the page or snippet is published, scheduled, or submitted to a workflow.
The new behavior is enabled by default, but individual field blocks can opt out by setting the required_on_save option to True. All blocks now also have an {attr}~wagtail.blocks.Block.is_deferred_validation attribute that can be used in custom validation logic to conditionally skip validation when saving drafts. For more details, refer to .
This feature was developed by Sage Abdullah.
The preview feature has been improved to be more compatible with projects that use signed cookies as the sessions backend for Django. Previewing large pages in Wagtail no longer causes the session cookie to exceed the cookie size limit enforced by browsers.
This feature was developed by Sage Abdullah. We would like to thank Personalkollen for their sponsorship of this feature.
The page explorer can now be customized for each page type using the {class}~wagtail.admin.viewsets.pages.PageViewSet. This allows you to add custom columns, filters, and more based on the parent page. The same customizations can also be applied to the flat per-page-type listings. For more details, refer to .
This feature was developed by Sage Abdullah.
The Django Modelsearch library has been upgraded to version 1.3, bringing enhancements including support for fuzzy search on PostgreSQL, searching and filtering across related fields to any level of nesting, and ranking of results on SQLite.
is a new advanced how-to guide explaining how to meet common content personalization requirements with built-in features, such as combining BlockGroup in StreamField and preview modes to create segmented page sections. This guide was written by Thibaud Colas.
The Wagtail documentation now contains a new version of our official package maintenance guidelines, which we recommend for Wagtail and Django projects. Those guidelines are meant as an opinionated starting point to help with creation and long-term maintenance of packages in our ecosystem. They support our official package template, cookiecutter-wagtail-package. This new version of the guide was written by Thibaud Colas.
This release includes three enhancements to Wagtail’s content quality checker:
empty-meta-description check is enabled by default, to validate meta description tags are not empty.extractMetrics of PreviewController to retrieve content metrics.Those enhancements were developed by Thibaud Colas.
This release includes a number of improvements around the User Experience in the page editor, delivered with support from the Wagtail UI team.
Wagtail recently underwent an independent code security audit commissioned by the Interministerial Digital Directorate (DINUM) of France. Check out the audit findings and our action plan. Here are specific changes in this release made in accordance to those findings:
WAGTAILDOCS_MAX_UPLOAD_SIZE to 10MB (Thibaud Colas)WAGTAILDOCS_SERVE_METHOD (Thibaud Colas)Thank you to the Sites Conformes team at DINUM for supporting the project by commissioning this audit!
A CMS user without the ability to edit a page could access revisions of the page through the revision compare view if they knew the primary key of two revisions. This could potentially result in disclosure of sensitive information.
Many thanks to Seoyoung Kang from AhnLab and an independent security researcher for reporting this issue. For further details, please see security advisory GHSA-c6wj-9vcj-75pj.
A CMS user without the ability to edit a page could still access the history report for the page, potentially resulting in disclosure of sensitive information.
Many thanks to Seoyoung Kang from AhnLab and an independent security researcher for reporting this issue. For further details, please see security advisory GHSA-c4mr-889m-vgf6.
A CMS user with limited access to form pages could delete submissions to form pages they don't have access to by crafting a form submission to delete submissions on a page they do have access to for submissions they don't. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to Vishal Shukla for reporting this issue. For further details, please see security advisory GHSA-pwm3-7fv4-g6xx.
A CMS user with limited access to pages could copy a page they don't have access to to an area of the site they do. Once coped, they'd be able to view its contents, and potentially publish it. Permissions were correctly checked for the copy destination, but not for the source page.
Many thanks to Sanjok Karki and an independent security researcher for reporting this issue. For further details, please see security advisory GHSA-67rv-mg8q-5pf3.
The Documents and Images API incorrectly listed items in private collections. A user with access to the API could see the filename and name of documents and images in private collections.
Many thanks to Sanjok Karki and an independent security researcher for reporting this issue. For further details, please see security advisory GHSA-p5gm-92h4-6pv6.
is_deferred_validation flag to support skipping custom validation when saving drafts (Daniel Kirkham)include_root parameter to admin pages API endpoint (Divyansh Mishra)creation_form_class on ChooserViewSet as a dotted path string (K Adithya)format-* operations on SVG images (Ankit Kumar)SnippetViewSet/ModelViewSet's list_display (Srishti Jaiswal)routablefullpageurl template tag, supporting full page URLs for routable pages (Pravin Kamble)get_object() DB query in API detail view (Siddheshwar Kadam)ImageBlock alt text populates on choosing a new image after unchecking decorative state (Pratham Jaiswal)verbose_name_plural for Query model in search promotions app (Saptami)max_count or max_count_per_parent (Lasse Schmieding)max_count_per_parent being moved under one parent (James Biggs)ChoiceBlock choices in block values (Devarshi Mani Tripathi)filter_spec parameter of ImageRenditionField (Soumya-codr)nested_default_fields attribute on API viewsets (Deepanshu Tevathiya)http with https in example URLs (Kunal Gupta)pathlib.Path for settings in "Integrating into Django" documentation (Kunal Gupta)ReferenceIndex API (Saptami)format_html in insert_global_admin_js example (Lasse Schmieding)published and unpublished signals (Kunal Hemnani)list_export in reports accepts a dotted path for nested attribute resolution (mikko2577)wagtail.admin.ui.tables (Sage Abdullah)hash_filelike test case to account for line break differences on Windows (Mustansir Dabhiya)PermissionError on document serve tests under Windows (Matt Westcott)if syntax (Sage Abdullah)timeout-minutes to GitHub Actions workflow jobs (Ashutosh)SwapController (LB (Ben Johnston))w-block- prefixes for block type class names (Kalash Kumari Thakur)StreamField blocks template rendering with include_block now a new w- prefix for CSS class names, such as w-block-my_block_name. For backwards compatibility, this is in addition to the pre-existing block-my_block_name classes. Those legacy classes without the w- prefix will be removed in a future release.
Django 4.2 is no longer supported as of this release; please upgrade to Django 5.2 or above before upgrading Wagtail.
The userbar AccessibilityItem has been renamed to {class}~wagtail.admin.userbar.ContentCheckerItem, to better signify its use for all types of content checks. The public API is identical aside from the renaming. Internals have also been renamed to use more appropriate terminology.
{% page_header_buttons %} template tagThe undocumented {% page_header_buttons %} template tag and its corresponding wagtailadmin/pages/listing/_page_header_buttons.html template have been deprecated and will be removed in a future release. If you made use of them in your templates, consider using the documented register_page_header_buttons hook, or overriding header_more_buttons and/or header_buttons in your custom page view instead. Alternatively, use the wagtail.admin.ui.menus.pages.get_page_header_buttons function to get the buttons, and render them as template components inside a dropdown menu instead.
Using the {% page_header_buttons %} template tag and its template will continue to work for now, but will raise a deprecation warning.
Maintenance: Upgrade to latest Sass with changes for deprecated if syntax (Sage Abdullah)
is_deferred_validation flag to support skipping custom validation when saving drafts (Daniel Kirkham)include_root parameter to admin pages API endpoint (Divyansh Mishra)creation_form_class on ChooserViewSet as a dotted path string (K Adithya)WAGTAILDOCS_MAX_UPLOAD_SIZE setting for specifying maximum document file size (Om Harsh)format-* operations on SVG images (Ankit Kumar)FormState model to improve compatibility with cookie-based sessions (Sage Abdullah)WAGTAILADMIN_PAGE_SEARCH_FILTER_BY_PERMISSIONS setting to disable permission filtering on page searches (Matt Westcott)SnippetViewSet/ModelViewSet's list_display (Srishti Jaiswal)empty-meta-description to validate meta description tags are not empty (Thibaud Colas)extractMetrics method to PreviewController to retrieve content metrics from the preview panel (Thibaud Colas)routablefullpageurl template tag (Pravin Kamble)PageViewSet (Sage Abdullah)get_object() DB query in API detail view (Siddheshwar Kadam)ImageBlock alt text populates on choosing a new image after unchecking decorative state (Pratham Jaiswal)verbose_name_plural for Query model in search promotions app (Saptami)max_count or max_count_per_parent (Lasse Schmieding)max_count_per_parent being moved under one parent (James Biggs)ChoiceBlock choices in block values (Devarshi Mani Tripathi)filter_spec parameter of ImageRenditionField (Soumya-codr)nested_default_fields attribute on API viewsets (Deepanshu Tevathiya)http with https in example URLs (Kunal Gupta)pathlib.Path for settings in "Integrating into Django" documentation (Kunal Gupta)ReferenceIndex API (Saptami)format_html in insert_global_admin_js example (Lasse Schmieding)published and unpublished signals (Kunal Hemnani)hash_filelike test case to account for line break differences on Windows (Mustansir Dabhiya)PermissionError on document serve tests under Windows (Matt Westcott)if syntax (Sage Abdullah)timeout-minutes to GitHub Actions workflow jobs (Ashutosh)SwapController (LB (Ben Johnston))w-block- prefixes for block type class names (Kalash Kumari Thakur)Security fix: Improper restriction handling on Pages admin API (xuliang@QAX, Dan Braghis)
August 20,2026
---
local:
depth: 1
---
The internal Pages admin API incorrectly returned page fields without access control when they were declared in api_fields. A user with access to the Wagtail admin could use this API to fetch draft and live page fields’ contents that are part of api_fields on the base page model (title, slug, seo_title, search_description), as well as all custom fields declared in api_fields.
Many thanks to xuliang@QAX for reporting this issue. For further details, please see security advisory GHSA-3vrh-m9w7-v94f.
By passing specific HTTP headers to the document serve URL endpoint, an attacker was able to determine whether a document with a given ID matched a specified SHA1 hash, regardless of any permission restrictions on the document or knowing its filename. This could allow an attacker to determine whether a document with a specific known hash is present in the Wagtail document library.
Many thanks to Anand Himanshu for reporting this issue. For further details, please see security advisory GHSA-92hv-j533-69wc.
The Documents and Images API incorrectly listed items in descendants of private collections, which should inherit the view restrictions defined on their ancestors. A user with access to the API could see the filename and name of documents and images in these descendant collections.
Many thanks to Ta Duc Thien for reporting this issue. For further details, please see security advisory GHSA-c2xx-cjmh-9q8f.
A CMS user with "add" permission over a snippet model, but not "change" or "view" permission, could copy an existing snippet that they do not have access to, allowing them to view its contents.
Many thanks to tinyb0y for reporting this issue. For further details, please see security advisory GHSA-x5cx-w6p2-mxf2.
A CMS user with the "submit translations" permission, could use the Admin API's "copy for translation" endpoint to copy an existing page that they do not have edit access to, allowing them to view its contents.
Many thanks to tinyb0y for reporting this issue. For further details, please see security advisory GHSA-jm5p-837g-rv8g.
CVE-2026-54259 : Improper restriction handling on Documents and Images chosen endpoints
June 15, 2026
---
local:
depth: 1
---
This release addresses a faulty permission check in the document and image choosers. The Documents and Images chooser's chosen endpoint incorrectly listed items for which the user has not been granted choose permission. A user with access to the Wagtail admin could see the filename and name and URLs of documents and images in those collections.
Many thanks to Harsh Akshit for reporting this issue. For further details, please see the CVE-2026-54259 security advisory.
This release addresses a potential denial-of-service attack on the image preview endpoint. An authenticated admin user could trigger expensive rendition processing with purposefully crafted filter specs resulting in potentially service degradation.
Many thanks to 0x1saac for reporting this issue. For further details, please see the CVE-2026-54260 security advisory.
This release addresses a faulty permission check in the image preview endpoint. A user with access to the Wagtail admin could preview any image. The existing data of the image object itself is not exposed. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to 0x1saac and Harsh Akshit for reporting this issue. For further details, please see the CVE-2026-54261 security advisory.
This release addresses a faulty permission check in the simple_translation app. A low-level user with the "Can submit translation" permission could create translations for any page, including those they do not have permissions for.
Many thanks to Devansh Bordia and alanturing881 for reporting this issue. For further details, please see the CVE-2026-54262 security advisory.
This release addresses a reflected cross-site scripting (XSS) vulnerability on the dynamic image URL generator view within the Wagtail admin interface. A user with a limited-permission editor account for the Wagtail admin could craft a URL that, when viewed by a user with higher privileges, could perform actions with that user's credentials.
Many thanks to Thibaud Colas for reporting this issue. For further details, please see the CVE-2026-54263 security advisory.
Security fix: Improper permission handling when comparing revisions (Seoyoung Kang, Jake Howard)
sizes attribute in responsive image template tags (Jake Howard)May 5, 2026
---
local:
depth: 1
---
A CMS user without the ability to edit a page could access revisions of the page through the revision compare view if they knew the primary key of two revisions. This could potentially result in disclosure of sensitive information.
Many thanks to Seoyoung Kang from AhnLab for reporting this issue. For further details, please see security advisory GHSA-c6wj-9vcj-75pj.
A CMS user without the ability to edit a page could still access the history report for the page, potentially resulting in disclosure of sensitive information.
Many thanks to Seoyoung Kang from AhnLab for reporting this issue. For further details, please see security advisory GHSA-c4mr-889m-vgf6.
A CMS user with limited access to form pages could delete submissions to form pages they don't have access to by crafting a form submission to delete submissions on a page they do have access to for submissions they don't. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to Vishal Shukla for reporting this issue. For further details, please see security advisory GHSA-pwm3-7fv4-g6xx.
A CMS user with limited access to pages could copy a page they don't have access to to an area of the site they do. Once coped, they'd be able to view its contents, and potentially publish it. Permissions were correctly checked for the copy destination, but not for the source page.
Many thanks to Sanjok Karki for reporting this issue. For further details, please see security advisory GHSA-67rv-mg8q-5pf3.
The Documents and Images API incorrectly listed items in private collections. A user with access to the API could see the filename and name of documents and images in private collections.
Many thanks to Sanjok Karki for reporting this issue. For further details, please see security advisory GHSA-p5gm-92h4-6pv6.
When a page is autosaved, the audit log entries created throughout the editing session are now grouped together as a single entry in the page's history view. This makes the page's history view more manageable to navigate when a large number of edits have been made via autosave. The site history report still shows granular entries for each autosave, to allow for more detailed analysis of editing activity across the site.
sizes attribute in responsive image template tags (Jake Howard)PageLogEntry and ModelLogEntry tablesThis release includes a migration to add composite indexes to the wagtailcore_pagelogentry and wagtailcore_modellogentry tables on the fields uuid, action, and -timestamp. Running this migration may take a few minutes on large sites with millions of existing log entries. If you have already created these indexes manually on your database, you should skip this migration by passing the option --fake to the migrate management command, for example: python manage.py migrate --fake wagtailcore 0097.
If you have custom audit log models in your project, you should also run python manage.py makemigrations to generate a migration that adds the same composite indexes to your custom log entry models, and then apply that migration.
Fix: CVE-2026-28222: Improper escaping of HTML (Cross-site Scripting) on TableBlock class attributes (Guan Chenxian, Matt Westcott)
March 3, 2026
---
local:
depth: 1
---
This release addresses a stored cross-site scripting (XSS) vulnerability on rendering TableBlock blocks within a StreamField. A user with access to create or edit pages containing TableBlock StreamField blocks is able to set specially-crafted class attributes on the block which run arbitrary JavaScript code when the page is viewed. When viewed by a user with higher privileges, this could lead to performing actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin, and only affects sites using TableBlock.
Many thanks to Guan Chenxian for reporting this issue. For further details, please see the CVE-2026-28222 security advisory.
This release addresses a stored cross-site scripting (XSS) vulnerability on confirmation messages within the wagtail.contrib.simple_translation module. A user with access to the Wagtail admin area may create a page with a specially-crafted title which, when another user performs the "Translate" action, causes arbitrary JavaScript code to run. This could lead to performing actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to Guan Chenxian for reporting this issue. For further details, please see the CVE-2026-28223 security advisory.
django.contrib.messages notification messagesNotification messages created through the django.contrib.messages module are now escaped according to Django's automatic HTML escaping mechanism when displayed within the Wagtail admin area. In most cases this is desirable to prevent cross-site scripting attacks; however, if your project makes intentional use of HTML markup within notification messages, this must now be passed as a safe string, through the use of a function such as format_html.
Fix: CVE-2026-25517: Improper permission handling on admin preview endpoints (thxtech, Matt Westcott, Jake Howard)
Page and Collection models (Samya Aggarwal)ModelViewSet.pk_path_converter with defaults for IntegerField and UUIDField primary keys (Seb Corbin)before_edit_setting / after_edit_setting hooks (Baptiste Mispelon)StreamBlock in comparison view (Taras Panasiuk)register_icons hook (Joey Jurjens, Sage Abdullah)TypedTableBlock are counted in the reference index (Aman Bora)request.is_preview and request.preview_mode are set for password-required responses (Ishtpreet Singh)StructBlocks with blocks named content (Sage Abdullah, Serkan Korkusuz)purge_embeds after an embed provider changes policies (Paul Souders)WAGTAILIMAGES_FORMAT_CONVERSIONS in the settings docs (David Buxton)before_delete_page and similar hooks only trigger on the individual page view, not bulk actions (Shivam Kumar)PageQuerySet.prefetch_related performance note (Lasse Schmieding)search.html in tutorial (Lee Hart)RoutablePageMixin (Tibor Leupold)_WAGTAILSEARCH_FORCE_AUTO_UPDATE in search tests (Matt Westcott)SubmitController error handling (LB (Ben) Johnston)latest.whl nightly build for ease of use with package managers (Sage Abdullah)no-jquery ESLint plugin to start final deprecation of jQuery (LB (Ben) Johnston)mode value to w-teleport to allow different DOM update strategies (Sage Abdullah)February 3, 2026
---
local:
depth: 1
---
The editor now automatically saves pages and snippets as you make changes to the content. Conflicting changes made in other editing sessions are detected using the existing concurrent editing notifications system. In the case of conflicts, validation errors, or other issues, autosave is paused and the user is notified. Autosave resumes once the issue has been resolved.
The autosave feature is enabled by default for all pages and snippets that use the RevisionMixin. The autosave interval can be configured or disabled via the WAGTAIL_AUTOSAVE_INTERVAL setting.
This feature was developed by Matt Westcott and Sage Abdullah, with review and support from Thibaud Colas and the Wagtail UI team, as well as designs by Ben Enright. We would like to thank Wharton Research Data Services for their sponsorship of this feature.
The StructBlock.Meta class now supports a form_layout attribute that allows you to customize the order and grouping of child blocks in the editing interface. You can provide a list of block names to specify the order, or use the new BlockGroup class to create collapsible groups of blocks, including a special "settings" group that is hidden by default. Refer to for more details.
This feature was developed by Sage Abdullah, with support from the Wagtail UI team and reference to previous work by Andy Babic.
The developer documentation and the Wagtail user guide now publish their contents in the llms.txt format. Those files can be used to provide context to Large Language Models on Wagtail projects. For both sites, this includes llms.txt files with an index of the site contents, large llms-full.txt files with full documentation contents, and Markdown variants of every page (with full docstrings contents):
.md at the end of any documentation page URL to view the Markdown output of that page. Examples: 7.3 release notes in Markdown{.external}, StreamField block reference in Markdown{.external}This feature was developed by Thibaud Colas.
Wagtail’s default image quality settings are now optimized for the needs of a wider number of sites, and consistent between image formats. The default settings are now lower for JPEG and AVIF. This will reduce image file sizes, loading times, and energy use of loading images.
Those changes in default settings won’t affect existing images, but it is possible to re-generate them if desired. View our image quality documentation for more information, and recommended quality settings for common use cases.
This feature was developed by Thibaud Colas.
The built-in accessibility checker now supports custom content checks. Those checks can provide live feedback to CMS users when content doesn’t meet accessibility best practices. They also support opinionated rules about other aspects of content quality - for example SEO, readability, tone of voice, page weight.
This feature was developed by Thibaud Colas.
New before_edit_setting and after_edit_setting hooks provide extension points for customizing the settings editing workflow. These hooks allow developers to extend settings management with custom validation, logging, notifications, or other actions. This matches capabilities available for pages and snippets.
This feature was developed by Baptiste Mispelon.
This release addresses a permission vulnerability in the Wagtail admin interface. Due to a missing permission check on the preview endpoints, a user with access to the Wagtail admin and knowledge of a model's fields can craft a form submission to obtain a preview rendering of any page, snippet or site setting object for which previews are enabled, consisting of any data of the user's choosing. The existing data of the object itself is not exposed, but depending on the nature of the template being rendered, this may expose other database contents that would otherwise only be accessible to users with edit access over the model. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Page and Collection models (Samya Aggarwal)ModelViewSet.pk_path_converter with defaults for IntegerField and UUIDField primary keys (Seb Corbin)StreamBlock in comparison view (Taras Panasiuk)register_icons hook (Joey Jurjens, Sage Abdullah)TypedTableBlock are counted in the reference index (Aman Bora)request.is_preview and request.preview_mode are set for password-required responses (Ishtpreet Singh)StructBlocks with blocks named content (Sage Abdullah, Serkan Korkusuz)purge_embeds after an embed provider changes policies (Paul Souders)WAGTAILIMAGES_FORMAT_CONVERSIONS in the settings docs (David Buxton)before_delete_page and similar hooks only trigger on the individual page view, not bulk actions (Shivam Kumar)PageQuerySet.prefetch_related performance note (Lasse Schmieding)search.html in tutorial (Lee Hart)RoutablePageMixin (Tibor Leupold)_WAGTAILSEARCH_FORCE_AUTO_UPDATE in search tests (Matt Westcott)SubmitController error handling (LB (Ben) Johnston)latest.whl nightly build for ease of use with package managers (Sage Abdullah)raise ... from err within an except clause) (Vivek Subramani, Matt Westcott)no-jquery ESLint plugin to start final deprecation of jQuery (LB (Ben) Johnston)mode value to w-teleport to allow different DOM update strategies (Sage Abdullah)LocalePreviously, when loading fixtures of Page models or other models extending TranslatableMixin, missing locale_id values would be automatically filled with the default Locale. This could break the setup of TransactionTestCase, and so this functionality has now been removed. Fixtures must now specify an explicit locale_id value.
Image quality settings for JPEG and AVIF now use lower default values, set to provide consistent perceptual quality between formats. This will take effect for newly-generated images only.
WAGTAILIMAGES_JPEG_QUALITY changed from 85 to 76.WAGTAILIMAGES_AVIF_QUALITY changed from 80 to 61.The new values match the default (unchanged) WAGTAILIMAGES_WEBP_QUALITY of 80. For sites considering custom values for those settings, refer to our recommended image quality table to make sure perceptual quality is consistent between different formats.
PageLogEntry and ModelLogEntry tablesAs of Wagtail 7.3.2, a migration has been included to add composite indexes to the wagtailcore_pagelogentry and wagtailcore_modellogentry tables on the fields uuid, action, and -timestamp. Running this migration may take a few minutes on large sites with millions of existing log entries. If you have already created these indexes manually on your database, you should skip this migration by passing the option --fake to the migrate management command, for example: python manage.py migrate --fake wagtailcore 0097.
If you have custom audit log models in your project, you should also run python manage.py makemigrations to generate a migration that adds the same composite indexes to your custom log entry models, and then apply that migration.
The items in the Wagtail userbar have been refactored to Template components. This changes the internal API for custom userbar items, with a render_html(parent_context) method. The pre-existing render(request) method has been deprecated and will be removed in a future release.
As part of refactoring userbar items to Template components, the following undocumented internals have changed:
BaseItem and its subclasses now inherit from Component.template attribute has been renamed to template_name.get_context_data method now receives a parent_context parameter, instead of a request parameter.The URL wagtailimages:generate_url and its associated view class GenerateURLView have been replaced. The new dynamic image URL generator UI uses Stimulus, with the URL wagtailimages:url_generator_output and the same URLGeneratorView as the page itself with async requests now returning HTML partials. Any overrides to those views or their template wagtailimages/url_generator.html will need to be adapted.
CreateView and EditViewThe form validation logic in wagtail.admin.views.generic.models.CreateView (aliased as wagtail.admin.views.generic.CreateView, and also subclassed as wagtail.snippets.views.snippets.CreateView) and wagtail.admin.views.generic.models.EditView (aliased as wagtail.admin.views.generic.EditView, and also subclassed as wagtail.snippets.views.snippets.EditView) has been refactored to better support validation conditions not handled by the form object (such as formsets displayed alongside the form, or a 'locked' status on the model). Any user code that overrides the post, form_valid, form_invalid and/or get_error_message methods to implement additional validation will need to be updated. These views now implement a new method is_valid(form), which by default delegates to form.is_valid(). To signal a validation error, this method should set the attribute self.produced_error_message to the desired error message string, and return False. For a generic validation error, this error message string can be obtained from self.get_error_message().
Maintenance: Add no-jquery ESLint plugin to start final deprecation of jQuery (LB (Ben) Johnston)
Page and Collection models (Samya Aggarwal)ModelViewSet.pk_path_converter with defaults for IntegerField and UUIDField primary keys (Seb Corbin)before_edit_setting / after_edit_setting hooks (Baptiste Mispelon)StreamBlock in comparison view (Taras Panasiuk)register_icons hook (Joey Jurjens, Sage Abdullah)TypedTableBlock are counted in the reference index (Aman Bora)request.is_preview and request.preview_mode are set for password-required responses (Ishtpreet Singh)purge_embeds after an embed provider changes policies (Paul Souders)WAGTAILIMAGES_FORMAT_CONVERSIONS in the settings docs (David Buxton)before_delete_page and similar hooks only trigger on the individual page view, not bulk actions (Shivam Kumar)PageQuerySet.prefetch_related performance note (Lasse Schmieding)search.html in tutorial (Lee Hart)RoutablePageMixin (Tibor Leupold)_WAGTAILSEARCH_FORCE_AUTO_UPDATE in search tests (Matt Westcott)SubmitController error handling (LB (Ben) Johnston)latest.whl nightly build for ease of use with package managers (Sage Abdullah)no-jquery ESLint plugin to start final deprecation of jQuery (LB (Ben) Johnston)mode value to w-teleport to allow different DOM update strategies (Sage Abdullah)Fix: CVE-2026-28222: Improper escaping of HTML (Cross-site Scripting) on TableBlock class attributes (Guan Chenxian, Matt Westcott)
March 3, 2026
---
local:
depth: 1
---
This release addresses a stored cross-site scripting (XSS) vulnerability on rendering TableBlock blocks within a StreamField. A user with access to create or edit pages containing TableBlock StreamField blocks is able to set specially-crafted class attributes on the block which run arbitrary JavaScript code when the page is viewed. When viewed by a user with higher privileges, this could lead to performing actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin, and only affects sites using TableBlock.
Many thanks to Guan Chenxian for reporting this issue. For further details, please see the CVE-2026-28222 security advisory.
This release addresses a stored cross-site scripting (XSS) vulnerability on confirmation messages within the wagtail.contrib.simple_translation module. A user with access to the Wagtail admin area may create a page with a specially-crafted title which, when another user performs the "Translate" action, causes arbitrary JavaScript code to run. This could lead to performing actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to Guan Chenxian for reporting this issue. For further details, please see the CVE-2026-28223 security advisory.
django.contrib.messages notification messagesNotification messages created through the django.contrib.messages module are now escaped according to Django's automatic HTML escaping mechanism when displayed within the Wagtail admin area. In most cases this is desirable to prevent cross-site scripting attacks; however, if your project makes intentional use of HTML markup within notification messages, this must now be passed as a safe string, through the use of a function such as format_html.
Fix: CVE-2026-25517: Improper permission handling on admin preview endpoints (thxtech, Matt Westcott, Jake Howard)
StructBlocks with blocks named content (Sage Abdullah, Serkan Korkusuz)February 3, 2026
---
local:
depth: 1
---
This release addresses a permission vulnerability in the Wagtail admin interface. Due to a missing permission check on the preview endpoints, a user with access to the Wagtail admin and knowledge of a model's fields can craft a form submission to obtain a preview rendering of any page, snippet or site setting object for which previews are enabled, consisting of any data of the user's choosing. The existing data of the object itself is not exposed, but depending on the nature of the template being rendered, this may expose other database contents that would otherwise only be accessible to users with edit access over the model. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
StructBlocks with blocks named content (Sage Abdullah, Serkan Korkusuz)Fix: Allow userbar in page previews to render without needing to configure site record (Sage Abdullah)
_WAGTAILSEARCH_FORCE_AUTO_UPDATE in search tests (Matt Westcott)November 26, 2025
---
local:
depth: 1
---
_WAGTAILSEARCH_FORCE_AUTO_UPDATE in search tests (Matt Westcott)ReferenceIndex tableThis release includes a migration to add composite indexes to the wagtailcore_referenceindex table on the fields base_content_type and object_id, and on to_content_type and to_object_id. If you have already created these indexes manually on your database, you should skip this migration by passing the option --fake to the migrate management command.
Running this migration may hang if there are existing long-running queries in progress on the table. If so, you are advised to stop and restart the database service before rerunning the migration.
Added support for Python 3.14 (Sage Abdullah)
?) to activate the keyboard shortcuts dialog (Dhruvi Patel)/) to activate and focus on the search input in the sidebar (Dhruvi Patel)max_value of 100 (%) for the closeness field in Image URL Generator form (LB (Ben) Johnston)WorkflowLock subclass via Task.lock_class in a custom task (Dan Braghis)update_fields parameter on Page.asave() (Tosinibikunle)CountController default findValue (Sage Abdullah)UserViewSet to User.USERNAME_FIELD to support default ordering with custom User models that may not have a name field (Lynwee)TableBlock header dropdown default option can be translated (arpitmak)construct_wagtail_userbar (Baptiste Mispelon)AGENTS.md (Andrew Selzer)RulesController (LB (Ben) Johnston)attrs in formattedfield tag & clean up other usages of the attrs template include (LB (Ben) Johnston)ImageNode within image template tags (minusf)November 5, 2025
---
local:
depth: 1
---
This release adds formal support for Python 3.14.
The listing view of {class}~.ModelViewSet and {class}~.SnippetViewSet now supports reordering of items using drag-and-drop. This feature can be enabled by setting the name of an integer field used for ordering as the {attr}~.ModelViewSet.sort_order_field attribute on the viewset or on the model. This can be a custom field, or set via inheriting Orderable.
Make sure to set default values for the sort order field on existing items before enabling this feature to avoid unexpected behavior. Here is an example: BreadType.objects.all().update(sort_order=F('pk') - 1).
This feature was developed by Joey Jurjens and Sage Abdullah.
Admin and document listings now support filtering by usage count. Image choosers now have both grid and list layouts, with a new toggle for users to switch between the two. The new toggle has also been added to standalone image listings for consistency.
Thank you to Joel William for implementing this as part of the Google Summer of Code program, with support from Coen van der Kamp, Sage Abdullah, Thibaud Colas, Ben Enright.
Built-in content checks now include a readability score, based on length of words and sentences in the page content. The content metrics also now provide an explainer panel detailing how they are calculated. This feature was developed by Thibaud Colas.
Error messages for form validation errors now contain a "Go to the first error" shortcut button. This speeds up navigating to address error messages, particularly for forms split between multiple tabs, where the errors can be hard to locate. This feature was developed by Srishti Jaiswal, Sage Abdullah and LB (Ben) Johnston.
Wagtail's search mechanism is now handled by the external Django Modelsearch library. This change will take effect automatically on upgrading to Wagtail 7.2, with no configuration changes required to most existing projects (but see the upgrade consideration notes below).
As part of this update, dedicated backends for OpenSearch and Elasticsearch 9 are now available; previously OpenSearch was only supported through a legacy version of the Elasticsearch 7 client library. For instructions on configuring these backends, see . Django Modelsearch is developed by Karl Hobley, with additional contributions and Wagtail compatibility developed by Matt Westcott.
We introduce two new shortcuts, ? to open the keyboard shortcuts dialog, and / to focus the search input in the sidebar. The keyboard shortcuts dialog has been reorganized into better categories. When keyboard shortcuts are disabled in user preferences, the "add comment" shortcut is also disabled, and messaging has been added to the keyboard shortcuts dialog to indicate the status of keyboard shortcuts and how to enable or disable them via user preferences. This feature was developed by Pravin Kamble.
Thank you to Dhruvi Patel for implementing this as part of the Google Summer of Code program, with support from LB (Ben) Johnston, Scott Cranfill, Thibaud Colas.
max_value of 100 (%) for the closeness field in Image URL Generator form (LB (Ben) Johnston)WorkflowLock subclass via Task.lock_class in a custom task (Dan Braghis)FileField usage in images & documents (Amir Mahmoodi)update_fields parameter on Page.asave() (Tosinibikunle)CountController default findValue (Sage Abdullah)UserViewSet to User.USERNAME_FIELD to support default ordering with custom User models that may not have a name field (Lynwee)TableBlock header dropdown default option can be translated (arpitmak)construct_wagtail_userbar (Baptiste Mispelon)AGENTS.md (Andrew Selzer)RulesController (LB (Ben) Johnston)attrs in formattedfield tag & clean up other usages of the attrs template include (LB (Ben) Johnston)ImageNode within image template tags (minusf)getattr & setattr uses constant) plus B033 (avoid duplicate values in set literals) (minusf)update_index after upgradingUsers of the Elasticsearch and OpenSearch backends are advised to run the command ./manage.py update_index after upgrading to Wagtail 7.2. If this is already set up to run on a regular schedule as recommended, no further action is required.
This is due to a change in the indexed document structure - specifically, the content_type field has been renamed to _django_content_type. Indexed documents will be upgraded to the new format on the next run of the update_index command. As of this release the old and new document format are handled equivalently, and searches will continue to work as before; however, support for the old format will be dropped in Wagtail 8.0. Consequently, upgrading to Wagtail 8.0 without first having run update_index on Wagtail 7.2 or later may result in incomplete search results.
ATOMIC_REBUILD now active by default on Elasticsearch and OpenSearchThe ATOMIC_REBUILD option, which rebuilds Elasticsearch and OpenSearch indexes as a fresh copy allowing searching to continue on the existing copy while rebuilding is in progress, is now enabled by default. If this is not appropriate for your configuration (for example, the user account used to connect to the server does not have permission to create indexes, or your service provider imposes a strict limit on the number of indexes), you can revert to the previous behavior by adding "ATOMIC_REBUILD": False to the backend's configuration options in WAGTAILSEARCH_BACKENDS.
INDEX configuration option on Elasticsearch and OpenSearch replaced with INDEX_PREFIXThe INDEX configuration option for Elasticsearch and OpenSearch backends has been deprecated. This option specifies a prefix to be used on all index names, allowing multiple Wagtail instances to share the same Elasticsearch server. This has now been replaced with the INDEX_PREFIX option. For example, the option "INDEX": "mysite" should now be replaced with "INDEX_PREFIX": "mysite_" (note the trailing _ character).
The INDEX option is still recognized in this release, but support for this will be dropped in Wagtail 8.0. For backends other than Elasticsearch and OpenSearch, the INDEX option is no longer used and can be removed.
Python 3.9 is no longer supported as of this release; please upgrade to Python 3.10 or above before upgrading Wagtail.
The JavaScript code previously used to generate the title from the file name when uploading images or documents has been replaced with a Stimulus SyncController implementation. This change improves compliance with Content Security Policy (CSP) by avoiding the need for inline scripts.
The events described in images title generation on upload and documents title generation on upload still continue to work as before. However, they may be deprecated in a future release in favor of the events dispatched by the SyncController with the w-sync prefix.
The use of creationFormFileFieldSelector, creationFormTitleFieldSelector, creationFormEventName options in ChooserModalOnloadHandlerFactory have been deprecated and will be removed in a future release.
refresh_index method on search backends renamed to refresh_indexesThe undocumented refresh_index method on search backend instances has been renamed to refresh_indexes, to reflect the fact that it acts on all indexes managed by the backend.
Removed support for Python 3.8 (Matt Westcott)
?) to activate the keyboard shortcuts dialog (Dhruvi Patel)/) to activate and focus on the search input in the sidebar (Dhruvi Patel)max_value of 100 (%) for the closeness field in Image URL Generator form (LB (Ben) Johnston)WorkflowLock subclass via Task.lock_class in a custom task (Dan Braghis)update_fields parameter on Page.asave() (Tosinibikunle)CountController default findValue (Sage Abdullah)UserViewSet to User.USERNAME_FIELD to support default ordering ordering with custom User models that may not have a name field (Lynwee)TableBlock header dropdown default option can be translated (arpitmak)construct_wagtail_userbar (Baptiste Mispelon)AGENTS.md (Andrew Selzer)RulesController (LB (Ben) Johnston)attrs in formattedfield tag & clean up other usages of the attrs template include (LB (Ben) Johnston)ImageNode within image template tags (minusf)Fix: CVE-2026-25517: Improper permission handling on admin preview endpoints (thxtech, Matt Westcott, Jake Howard)
StructBlocks with blocks named content (Sage Abdullah, Serkan Korkusuz)February 3, 2026
---
local:
depth: 1
---
This release addresses a permission vulnerability in the Wagtail admin interface. Due to a missing permission check on the preview endpoints, a user with access to the Wagtail admin and knowledge of a model's fields can craft a form submission to obtain a preview rendering of any page, snippet or site setting object for which previews are enabled, consisting of any data of the user's choosing. The existing data of the object itself is not exposed, but depending on the nature of the template being rendered, this may expose other database contents that would otherwise only be accessible to users with edit access over the model. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
StructBlocks with blocks named content (Sage Abdullah, Serkan Korkusuz)Fix: Allow label_format to be set to an empty string to hide the block summary label (Sage Abdullah)
label_format to be set to an empty string to hide the block summary label (Sage Abdullah)Node.move() in Page.move() documentation (Baptiste Mispelon)October 23, 2025
---
local:
depth: 1
---
label_format to be set to an empty string to hide the block summary label (Sage Abdullah)Node.move() in Page.move() documentation (Baptiste Mispelon)label_format behavior in StructBlockIn Wagtail 7.1, the label_format option for StructBlock has been changed to always show the block's original label when the block is collapsed, with the label_format string shown after it as a summary instead of replacing the label. This means that if you had previously set label_format to include (or be the same as) the label, you would likely want to remove the original label's text from the label_format string.
If you wish to hide the summary label entirely (similar to setting label_format = label in Wagtail < 7.1), you can set label_format to the empty string "". This was not possible in Wagtail 7.1, but is now supported as of this release.
Fix: Ensure the add comment keyboard shortcut is disabled when keyboard shortcuts are disabled in user preferences (Dhruvi Patel)
rest_framework installed (Vijay Raj)FieldPanel and TitleFieldPanel with read_only=True (Sage Abdullah)August 28, 2025
---
local:
depth: 1
---
rest_framework installed (Vijay Raj)FieldPanel and TitleFieldPanel with read_only=True (Sage Abdullah)Allow configuring permissions for site settings on a per-site basis (Matt Westcott)
NumberColumn to display numbers in universal listings (Baptiste Mispelon)GenericRelations for RevisionMixin and WorkflowMixin, to avoid issues with deletion cascades (Sage Abdullah)init_new_page signal (Maciek Baron)requests to access oEmbed endpoints, for more robust SSL certificate handling (Matt Westcott)RichTextBlock and RichTextField (Alec Baron)SnippetChooserBlock's icon to take precedence over SnippetViewSet.icon (Matt Westcott)preserve-svg in Jinja2 image tags (Vishesh Garg)preserve-svg as a filter when calling Image.get_rendition directly (Richard Allen)preserve-svg for Image.get_renditions, picture, and srcset_image tags (Matt Westcott)TypedTableBlock content when indexing for search (Charan T M)find view to the detail view (Andrew Hosgood)NoFutureDateValidator to validate against dates in the future (Talha Rizwan)background_position_x and background_position_y properties from AbstractRendition.background_position_style (Chiemezuo Akujobi)UsageCountColumn to document and image listings (Joel William, Sage Abdullah)StructBlocks collapsible when nested to support block settings (Sage Abdullah)label_format support for more widget types in StreamField (Sage Abdullah)form_attrs support to all StreamField blocks (Sage Abdullah)preview_value and default in Block meta options as callables for dynamic previews within StreamField (Ziyao Yan, Sage Abdullah)preview_value for RichTextBlock (Seb Corbin)WAGTAILADMIN_LOGIN_URL is respected when logging out of the admin (Antoine Rodriguez, Ramon de Jezus)ViewSet.inject_view_methods with multiple methods (Gorlik)exclude_fields_in_copy (Matt Westcott)import_redirects command (Matt Westcott)first_published_at field are preserved on reloading (Talha Rizwan)BooleanColumn icons so they can be distinguished without relying on color (Sage Abdullah)django.middleware.security.SecurityMiddleware first (Brylie Christopher Oxley)help_text kwarg in FloatBlock (Nick Smith)aria-invalid on StreamField widgets input when there is an error (Sage Abdullah)human_readable_date template tag (Seb Corbin)order_by expressions in database search backends (Seb Corbin)avif in WAGTAILIMAGES_EXTENSIONS example (Thibaud Colas)data-edit-form and interacting with the editor form and preview panel (Sage Abdullah)get_embed to remove finder argument which was only used for mocking in unit tests (Jigyasu Rajput)None values in TypedTableBlock (Jigyasu Rajput)utf8mb4 charset and collation for MySQL test database (Sage Abdullah)django.contrib.postgres to test settings INSTALLED_APPS (Sage Abdullah)SlugController with more generic and reusable CleanController (LB (Ben) Johnston)/etc (LB (Ben) Johnston)EventTarget instead of events.EventEmitter from Webpack (Sage Abdullah)telepath/widgets.js into separate files (Matt Westcott)4.2, 5.1, 5.2
3.9, 3.10, 3.11, 3.12, 3.13
7.0 LTS
4.2, 5.1, 5.2
3.9, 3.10, 3.11, 3.12, 3.13
August 4, 2025
---
local:
depth: 1
---
Check out our upcoming Wagtail Space 2025 event 🚀! Online, ✨ free ✨, October 8-10.
The app now allows permission over site settings to be granted on a per-site basis. This makes it possible to give non-superuser accounts full control over the configuration of an individual site. This feature was developed by Matt Westcott.
The app now allows previews to be enabled for generic and site setting models through PreviewableMixin. This makes it possible to preview your site while editing the settings. For more details, see . This feature was developed by Sébastien Corbin and Sage Abdullah.
Image listings now support both grid and list layouts, with a simple toggle for users to switch between the two. The list layout gives you more information about the images, such as the file name, collection, creation date, and usage count. This helps CMS users manage larger collections of images, and makes it possible to display more metadata about images in the future.
The documents listing now also display the usage count for each document, making it easier to see which documents are being used on your site.
Thank you to Joel William for implementing this as part of the Google Summer of Code program, with support from Coen van der Kamp, Sage Abdullah, Thibaud Colas, Ben Enright.
To make it easier to navigate complex structured content, blocks created with StructBlock can now be collapsed and expanded like other structured block types. A common need for this is block settings, where the block supports a lot of optional fields:
class BlockQuote(StructBlock):
text = TextBlock()
attribute_name = CharBlock(blank=True, required=False, label="e.g. Mary Berry")
# Fields within the settings block will be available but hidden by default.
settings = ThemeSettingsBlock(collapsed=True)
For more information, see and . This feature was implemented by Sage Abdullah, with support from the Wagtail UI team.
The live preview and user bar features have been refactored and improved to work better in headless setups. The preview panel can now load a cross-domain headless frontend (provided by the wagtail-headless-preview package). The Wagtail user bar has been refactored into a template component, allowing it to be rendered independently and loaded by the headless frontend. Incorporating the user bar into the frontend enables features in the page editor, such as:
For more details, see the documentation on enabling the user bar and accessibility checker in headless setups. This feature was developed by Sage Abdullah.
Wagtail’s developer documentation now includes experimental docs to reuse client-side code and UI components. This new documentation helps developers reuse existing components when creating customizations or extensions of the admin interface, so those customizations are simpler to build and maintain. The documentation is experimental, as well as reuse of those UI components. This means a component's API may change in a minor release without going through the deprecation process. If you use these components in your own code, please ensure that you have a testing process in place to catch any breaking changes with each Wagtail upgrade.
This feature was implemented by Sage Abdullah, with support from the Wagtail UI team.
The admin interface now supports more keyboard shortcuts to facilitate common actions: in this release, toggling the main navigation sidebar, and the minimap within the page editor. It’s also now possible for users to disable all of Wagtail’s custom shortcuts via a dedicated setting in their user profile.
Thank you to Dhruvi Patel for implementing this as part of the Google Summer of Code program, with support from Scott Cranfill, Thibaud Colas, LB (Ben) Johnston.
The panels mechanism used by the page and snippet editing forms now provides an API for client-side code to access the panel structure. This makes it possible to retrieve and manipulate the form contents without navigating the HTML structure of the page, which is not guaranteed to remain stable across releases of Wagtail. For further information, see . This feature was developed by Matt Westcott.
NumberColumn to display numbers in universal listings (Baptiste Mispelon)GenericRelations for RevisionMixin and WorkflowMixin, to avoid issues with deletion cascades (Sage Abdullah)init_new_page signal (Maciek Baron)requests to access oEmbed endpoints, for more robust SSL certificate handling (Matt Westcott)RichTextBlock and RichTextField (Alec Baron)SnippetChooserBlock's icon to take precedence over SnippetViewSet.icon (Matt Westcott)preserve-svg in Jinja2 image tags (Vishesh Garg)preserve-svg as a filter when calling Image.get_rendition directly (Richard Allen)preserve-svg for Image.get_renditions, picture, and srcset_image tags (Matt Westcott)TypedTableBlock content when indexing for search (Charan T M)find view to the detail view (Andrew Hosgood)NoFutureDateValidator to validate against dates in the future (Talha Rizwan)background_position_x and background_position_y properties from AbstractRendition.background_position_style (Chiemezuo Akujobi)form_attrs support to all StreamField blocks (Sage Abdullah)label_format support for more widget types in StreamField (Sage Abdullah)preview_value and default in Block meta options as callables for dynamic previews within StreamField (Ziyao Yan, Sage Abdullah)preview_value for RichTextBlock (Seb Corbin)WAGTAILADMIN_LOGIN_URL is respected when logging out of the admin (Antoine Rodriguez, Ramon de Jezus)ViewSet.inject_view_methods with multiple methods (Gorlik)exclude_fields_in_copy (Matt Westcott)import_redirects command (Matt Westcott)first_published_at field are preserved on reloading (Talha Rizwan)BooleanColumn icons so they can be distinguished without relying on color (Sage Abdullah)django.middleware.security.SecurityMiddleware first (Brylie Christopher Oxley)help_text kwarg in FloatBlock (Nick Smith)aria-invalid on StreamField widgets input when there is an error (Sage Abdullah)human_readable_date template tag (Seb Corbin)order_by expressions in database search backends (Seb Corbin)avif in WAGTAILIMAGES_EXTENSIONS example (Thibaud Colas)data-edit-form and interacting with the editor form and preview panel (Sage Abdullah)get_embed to remove finder argument which was only used for mocking in unit tests (Jigyasu Rajput)None values in TypedTableBlock (Jigyasu Rajput)utf8mb4 charset and collation for MySQL test database (Sage Abdullah)django.contrib.postgres to test settings INSTALLED_APPS (Sage Abdullah)SlugController with more generic and reusable CleanController (LB (Ben) Johnston)/etc (LB (Ben) Johnston)EventTarget instead of events.EventEmitter from Webpack (Sage Abdullah)telepath/widgets.js into separate files (Matt Westcott)label_format behavior in StructBlockThe label_format option for StructBlock has been changed to always show the block's original label when the block is collapsed, with the label_format string shown after it as a summary instead of replacing the label. This means that if you had previously set label_format to include (or be the same as) the label, you would likely want to remove the original label's text from the label_format string.
PageListingButton, SnippetListingButton, and UserListingButtonThe PageListingButton, SnippetListingButton, and UserListingButton classes have been deprecated in favour of the generic ListingButton and Button classes.
The PageListingButton class was previously documented as part of the register_page_listing_buttons hook. If you used this hook to add buttons to the page listing, you should now replace wagtail.admin.widgets.PageListingButton with wagtail.admin.widgets.ListingButton. Using the PageListingButton class will continue to work for now, but will raise a deprecation warning.
The SnippetListingButton and UserListingButton classes were previously documented as part of the register_snippet_listing_buttons and register_user_listing_buttons hooks, respectively. If you used these hooks to add buttons to the snippet or user listing, you should now replace wagtail.snippets.widgets.SnippetListingButton and wagtail.users.widgets.UserListingButton with one of the following:
wagtail.admin.widgets.Button if you want the button to appear as an item inside the "More" actions dropdown in the listing.wagtail.admin.widgets.ListingButton if you want the button to appear as a top-level button in the listing.Using the SnippetListingButton or UserListingButton classes will continue to work for now, but will raise a deprecation warning.
The PageListingButton, SnippetListingButton, and UserListingButton classes will be removed in a future release.
ListingButton in IndexView.get_list_more_buttons now renders the button as a top-level buttonIf you have overridden the undocumented get_list_more_buttons method on a generic IndexView subclass (e.g. for a ModelViewSet) and used the ListingButton class to add buttons to the "More" actions dropdown, these buttons will now be rendered as top-level buttons in the listing. If you want the buttons to appear inside the "More" actions dropdown, you should use the Button class instead.
init_new_page moved to wagtail.signalsThe signal, previously defined in wagtail.admin.signals, has now been moved to wagtail.signals. Any import lines referencing the old location need to be updated.
AccessibilityItem now accepts an in_editor argumentThe AccessibilityItem user bar item now accepts an {attr}~wagtail.admin.userbar.ContentCheckerItem.in_editor argument, which is set to True when it is instantiated within the page editor. If you customized the accessibility checker, you should update your code to pass this argument when creating an instance of your AccessibilityItem subclass.
@hooks.register('construct_wagtail_userbar')
def replace_userbar_accessibility_item(request, items, page):
items[:] = [
- CustomAccessibilityItem()
+ CustomAccessibilityItem(in_editor=item.in_editor)
if isinstance(item, AccessibilityItem) else item
for item in items
]
If you do not update your code, the AccessibilityItem will continue to work, but the in_editor argument will always be False. Wagtail does not currently use this argument, but it may do so in the future. It may also be utilized by users for cross-domain headless setups.
wagtail.telepath and wagtail.widget_adapters moved to wagtail.admin.telepathThe wagtail.telepath module has now been moved to wagtail.admin.telepath, and wagtail.widget_adapters has been moved to wagtail.admin.telepath.widgets. Any import lines referencing the old locations need to be updated.
The wagtailimages listing view templates have been adapted to support both list and grid layout. Those adaptations should be replicated for any overrides or reuse of those templates.
wagtailadmin/js/telepath/telepath.jsThe JavaScript file wagtailadmin/js/telepath/telepath.js is no longer required, as Telepath initialization is now handled within wagtailadmin/js/core.js. Any templates used within the Wagtail admin should remove imports of this file; any front-end code using Telepath outside of the Wagtail admin should use the telepath.js supplied with the telepath package or telepath-unpack.
The frontend implementation of the Tabs component (used in TabbedInterface and elsewhere) has been rewritten using Stimulus.
Any existing usage of the component via the data-tabs attribute will no longer work. Here is a summary of the new approach.
These are subject to change and are still not officially documented, please add a thumbs up or comment to the feature request if you would like a formalised Python or JavaScript API for the Tabs component.
| Item | Usage | Old | New |
|---|---|---|---|
| Attribute | Root tab container div | data-tabs |
data-controller="w-tabs" |
| Attribute | Tab trigger (tab) | role="tab" only |
role="tab" & data-w-tabs-target="trigger" data-action="w-tabs#select:prevent" |
| Attribute | Non-tab ad-hoc triggers (as a link) | href="#tab-label-id" data-trigger |
href="#the-tab-id" data-w-tabs-target="trigger" data-action="w-tabs#select:prevent" data-w-tabs-focus-param="true" (focus is optional, but recommended) |
| Attribute | Non-tab ad-hoc triggers (as a button) | N/A - was not supported | type="button" data-w-tabs-target="trigger" data-action="w-tabs#select" data-w-tabs-id-param="the-tab-id" data-w-tabs-focus-param="true" (focus is optional, but recommended) |
| Attribute | Opt in/out of URL sync, on tabs container | data-tabs-disable-url (opt out) |
data-action="popstate@window->w-tabs#select" data-w-tabs-use-location-value="true" (opt in) |
| Attribute | Add a class when a panel becomes active | data-tabs-animate (hard-coded 'animate-in' class) |
data-w-tabs-active-class="animate-in" |
| Attribute | Tab panel (content) | role="tabpanel" only |
role="tabpanel" & data-w-tabs-target="panel" |
| Attribute | Tablist container keyboard control | role="tablist" |
role="tablist" & data-action="keydown.right->w-tabs#selectNext keydown.left->w-tabs#selectPrevious keydown.home->w-tabs#selectFirst keydown.end->w-tabs#selectLast" |
| Event | A tab is selected | 'switch' (dispatched on the role=tablist, does not bubble) |
'w-tabs:selected' (dispatched on the triggers for the tab, does bubble) |
| Event | A change to the active panel | 'wagtail:tab-changed' (dispatched on document, does not bubble) |
'w-tabs:changed' (dispatched on the tabs container, does bubble) |
For a full HTML example, install the and see the tabs examples there.
Allow configuring permissions for site settings on a per-site basis (Matt Westcott)
NumberColumn to display numbers in universal listings (Baptiste Mispelon)GenericRelations for RevisionMixin and WorkflowMixin, to avoid issues with deletion cascades (Sage Abdullah)init_new_page signal (Maciek Baron)requests to access oEmbed endpoints, for more robust SSL certificate handling (Matt Westcott)RichTextBlock and RichTextField (Alec Baron)SnippetChooserBlock's icon to take precedence over SnippetViewSet.icon (Matt Westcott)preserve-svg in Jinja2 image tags (Vishesh Garg)preserve-svg as a filter when calling Image.get_rendition directly (Richard Allen)preserve-svg for Image.get_renditions, picture, and srcset_image tags (Matt Westcott)TypedTableBlock content when indexing for search (Charan T M)find view to the detail view (Andrew Hosgood)NoFutureDateValidator to validate against dates in the future (Talha Rizwan)background_position_x and background_position_y properties from AbstractRendition.background_position_style (Chiemezuo Akujobi)UsageCountColumn to document and image listings (Joel William, Sage Abdullah)StructBlocks collapsible when nested to support block settings (Sage Abdullah)label_format support for more widget types in StreamField (Sage Abdullah)form_attrs support to all StreamField blocks (Sage Abdullah)preview_value and default in Block meta options as callables for dynamic previews within StreamField (Ziyao Yan, Sage Abdullah)preview_value for RichTextBlock (Seb Corbin)WAGTAILADMIN_LOGIN_URL is respected when logging out of the admin (Antoine Rodriguez, Ramon de Jezus)ViewSet.inject_view_methods with multiple methods (Gorlik)exclude_fields_in_copy (Matt Westcott)import_redirects command (Matt Westcott)first_published_at field are preserved on reloading (Talha Rizwan)BooleanColumn icons so they can be distinguished without relying on color (Sage Abdullah)django.middleware.security.SecurityMiddleware first (Brylie Christopher Oxley)help_text kwarg in FloatBlock (Nick Smith)aria-invalid on StreamField widgets input when there is an error (Sage Abdullah)human_readable_date template tag (Seb Corbin)order_by expressions in database search backends (Seb Corbin)avif in WAGTAILIMAGES_EXTENSIONS example (Thibaud Colas)get_embed to remove finder argument which was only used for mocking in unit tests (Jigyasu Rajput)None values in TypedTableBlock (Jigyasu Rajput)utf8mb4 charset and collation for MySQL test database (Sage Abdullah)django.contrib.postgres to test settings INSTALLED_APPS (Sage Abdullah)SlugController with more generic and reusable CleanController (LB (Ben) Johnston)/etc (LB (Ben) Johnston)EventTarget instead of events.EventEmitter from Webpack (Sage Abdullah)telepath/widgets.js into separate files (Matt Westcott)Security fix: Improper restriction handling on Pages admin API (xuliang@QAX, Dan Braghis)
August 20,2026
---
local:
depth: 1
---
The internal Pages admin API incorrectly returned page fields without access control when they were declared in api_fields. A user with access to the Wagtail admin could use this API to fetch draft and live page fields’ contents that are part of api_fields on the base page model (title, slug, seo_title, search_description), as well as all custom fields declared in api_fields.
Many thanks to xuliang@QAX for reporting this issue. For further details, please see security advisory GHSA-3vrh-m9w7-v94f.
By passing specific HTTP headers to the document serve URL endpoint, an attacker was able to determine whether a document with a given ID matched a specified SHA1 hash, regardless of any permission restrictions on the document or knowing its filename. This could allow an attacker to determine whether a document with a specific known hash is present in the Wagtail document library.
Many thanks to Anand Himanshu for reporting this issue. For further details, please see security advisory GHSA-92hv-j533-69wc.
The Documents and Images API incorrectly listed items in descendants of private collections, which should inherit the view restrictions defined on their ancestors. A user with access to the API could see the filename and name of documents and images in these descendant collections.
Many thanks to Ta Duc Thien for reporting this issue. For further details, please see security advisory GHSA-c2xx-cjmh-9q8f.
A CMS user with "add" permission over a snippet model, but not "change" or "view" permission, could copy an existing snippet that they do not have access to, allowing them to view its contents.
Many thanks to tinyb0y for reporting this issue. For further details, please see security advisory GHSA-x5cx-w6p2-mxf2.
A CMS user with the "submit translations" permission, could use the Admin API's "copy for translation" endpoint to copy an existing page that they do not have edit access to, allowing them to view its contents.
Many thanks to tinyb0y for reporting this issue. For further details, please see security advisory GHSA-jm5p-837g-rv8g.
CVE-2026-54259 : Improper restriction handling on Documents and Images chosen endpoints (Harsh Akshit, Dan Braghis)
June 15, 2026
---
local:
depth: 1
---
This release addresses a faulty permission check in the document and image choosers. The Documents and Images chooser's chosen endpoint incorrectly listed items for which the user has not been granted choose permission. A user with access to the Wagtail admin could see the filename and name and URLs of documents and images in those collections.
Many thanks to Harsh Akshit for reporting this issue. For further details, please see the CVE-2026-54259 security advisory.
This release addresses a potential denial-of-service attack on the image preview endpoint. An authenticated admin user could trigger expensive rendition processing with purposefully crafted filter specs resulting in potentially service degradation.
Many thanks to 0x1saac for reporting this issue. For further details, please see the CVE-2026-54260 security advisory.
This release addresses a faulty permission check in the image preview endpoint. A user with access to the Wagtail admin could preview any image. The existing data of the image object itself is not exposed. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to 0x1saac and Harsh Akshit for reporting this issue. For further details, please see the CVE-2026-54261 security advisory.
This release addresses a faulty permission check in the simple_translation app. A low-level user with the "Can submit translation" permission could create translations for any page, including those they do not have permissions for.
Many thanks to Devansh Bordia and alanturing881 for reporting this issue. For further details, please see the CVE-2026-54262 security advisory.
Security fix: Improper permission handling when comparing revisions (Seoyoung Kang, Jake Howard)
sizes attribute in responsive image template tags (Jake Howard)sizes attribute in responsive image template tags (Jake Howard)May 5, 2026
---
local:
depth: 1
---
A CMS user without the ability to edit a page could access revisions of the page through the revision compare view if they knew the primary key of two revisions. This could potentially result in disclosure of sensitive information.
Many thanks to Seoyoung Kang from AhnLab for reporting this issue. For further details, please see security advisory GHSA-c6wj-9vcj-75pj.
A CMS user without the ability to edit a page could still access the history report for the page, potentially resulting in disclosure of sensitive information.
Many thanks to Seoyoung Kang from AhnLab for reporting this issue. For further details, please see security advisory GHSA-c4mr-889m-vgf6.
A CMS user with limited access to form pages could delete submissions to form pages they don't have access to by crafting a form submission to delete submissions on a page they do have access to for submissions they don't. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to Vishal Shukla for reporting this issue. For further details, please see security advisory GHSA-pwm3-7fv4-g6xx.
A CMS user with limited access to pages could copy a page they don't have access to to an area of the site they do. Once coped, they'd be able to view its contents, and potentially publish it. Permissions were correctly checked for the copy destination, but not for the source page.
Many thanks to Sanjok Karki for reporting this issue. For further details, please see security advisory GHSA-67rv-mg8q-5pf3.
The Documents and Images API incorrectly listed items in private collections. A user with access to the API could see the filename and name of documents and images in private collections.
Many thanks to Sanjok Karki for reporting this issue. For further details, please see security advisory GHSA-p5gm-92h4-6pv6.
sizes attribute in responsive image template tags (Jake Howard)Fix: CVE-2026-28222: Improper escaping of HTML (Cross-site Scripting) on TableBlock class attributes (Guan Chenxian, Matt Westcott)
March 3, 2026
---
local:
depth: 1
---
This release addresses a stored cross-site scripting (XSS) vulnerability on rendering TableBlock blocks within a StreamField. A user with access to create or edit pages containing TableBlock StreamField blocks is able to set specially-crafted class attributes on the block which run arbitrary JavaScript code when the page is viewed. When viewed by a user with higher privileges, this could lead to performing actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin, and only affects sites using TableBlock.
Many thanks to Guan Chenxian for reporting this issue. For further details, please see the CVE-2026-28222 security advisory.
This release addresses a stored cross-site scripting (XSS) vulnerability on confirmation messages within the wagtail.contrib.simple_translation module. A user with access to the Wagtail admin area may create a page with a specially-crafted title which, when another user performs the "Translate" action, causes arbitrary JavaScript code to run. This could lead to performing actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to Guan Chenxian for reporting this issue. For further details, please see the CVE-2026-28223 security advisory.
django.contrib.messages notification messagesNotification messages created through the django.contrib.messages module are now escaped according to Django's automatic HTML escaping mechanism when displayed within the Wagtail admin area. In most cases this is desirable to prevent cross-site scripting attacks; however, if your project makes intentional use of HTML markup within notification messages, this must now be passed as a safe string, through the use of a function such as format_html.
Remove upper bound on Pillow dependency (Kunal Hemnani)
February 12, 2026
---
local:
depth: 1
---
Fix: CVE-2026-25517: Improper permission handling on admin preview endpoints (thxtech, Matt Westcott, Jake Howard)
February 3, 2026
---
local:
depth: 1
---
This release addresses a permission vulnerability in the Wagtail admin interface. Due to a missing permission check on the preview endpoints, a user with access to the Wagtail admin and knowledge of a model's fields can craft a form submission to obtain a preview rendering of any page or snippet object for which previews are enabled, consisting of any data of the user's choosing. The existing data of the object itself is not exposed, but depending on the nature of the template being rendered, this may expose other database contents that would otherwise only be accessible to users with edit access over the model. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Fix: Prevent crash when previewing a form page with an empty field type (Sage Abdullah)
August 28, 2025
---
local:
depth: 1
---
Fix: Prevent error when restoring scroll position for cross-domain preview iframe (Sage Abdullah)
July 24, 2025
---
local:
depth: 1
---
Fix: Fix type hints for register_filter_adapter_class parameters (Sébastien Corbin)
register_filter_adapter_class parameters (Sébastien Corbin)child_block kwarg (Matt Westcott)UniqueConstraint examples for a custom rendition model to avoid spurious migrations (Alec Baron)utf8mb4 charset and collation for MySQL test database (Sage Abdullah)June 12, 2025
---
local:
depth: 1
---
register_filter_adapter_class parameters (Sébastien Corbin)child_block kwarg (Matt Westcott)UniqueConstraint examples for a custom rendition model to avoid spurious migrations (Alec Baron)utf8mb4 charset and collation for MySQL test database (Sage Abdullah)Fix: Avoid deprecation warnings about URLField assume_scheme on Django 5.x (Sage Abdullah)
WAGTAIL_ prefix to Wagtail-specific tag settings (Aayushman Singh)normalize on TypedTableBlock to assist with setting default and preview_value (Sage Abdullah)StreamBlock's value to assist with programmatic changes to StreamField (Matt Westcott)models.UniqueConstraint instead of unique_together (Oliver Parker, Cynthia Kiser, Sage Abdullah)standard tokenizer on Elasticsearch, to correctly handle numbers as tokens (Matt Westcott)get_default_privacy_setting (Shlomo Markowitz)get_template_for_action (Sage Abdullah)InspectView field display value via methods on the view (Dan Braghis)in and exact lookup on Elasticsearch (Sage Abdullah)InlinePanel will be correctly ordered after the first save when min_num is used (Elhussein Almasri, Joel William)assume_scheme on Django 5.x (Sage Abdullah)ImproperlyConfigured is thrown from db_field on unbound FieldPanels as intended (Matt Westcott)id (Sage Abdullah)WAGTAILADMIN_PERMITTED_LANGUAGES setting (Sébastien Corbin)django.contrib.admin to list of apps in "add to Django project" guide (Mohamed Rabiaa)insert_editor_js hook applies to all core editing/creation views (LB (Ben) Johnston)Page.get_url_parts will return a tuple, not None for NoReverseMatch errors (Arthur Tripp)expand_db_html utility function to create HTML ready for display (Thibaud Colas)expand_db_html usage for rich text in REST framework API (Thibaud Colas)?limit with WAGTAILAPI_LIMIT_MAX (Thibaud Colas)downshift, focus-trap-react, immer, redux, uuid (LB (Ben) Johnston)wagtail.models module into submodules (Matt Westcott)ruff to 0.9.6 (Sage Abdullah)stubs & adapter contents to better support Jest testing (LB (Ben) Johnston)SkipLinkController to FocusController with improved reusability, updated unit tests, and added story (LB (Ben) Johnston)LocaleController time zones & non-deterministic page ordering tests (Sage Abdullah).html files as Django templates (Jake Howard)insert_editor_js hook output, deprecate the wrapper template tag _editor_js.html (Sai Srikar Dumpeti, LB (Ben) Johnston)default_auto_field setting to home app in project template (Sylvain Boissel)setup.py and setup.cfg to pyproject.toml (Sage Abdullah)move_choose_destination to a class-based view (Chiemezuo Akujobi)wagtailadmin/shared/ajax_pagination_nav.html template (Sage Abdullah)django-tasks to 0.7.x (Jake Howard)May 6, 2025
---
local:
depth: 1
---
Wagtail 7.0 is designated a Long Term Support (LTS) release. Long Term Support releases will continue to receive maintenance updates as necessary to address security and data-loss related issues, up until the next LTS release (typically a period of 12 months).
This version adds formal support for Django 5.2.
This release introduces a change to the validation behavior when saving pages (or snippets using DraftStateMixin) as drafts. In most cases, required fields will not be enforced when saving as draft, allowing users to save work-in-progress versions without filling in all fields. Validation is applied as normal when the page or snippet is published, scheduled, or submitted to a workflow. The new behavior is enabled by default, but see the notes below on .
This feature was developed by Matt Westcott and Sage Abdullah.
We have a new pagination interface for all listing views and most choosers, including page numbers. This simplifies navigation for listings with tens or hundreds of pages, so users can jump directly to the last pages. Thank you to Jordan Teichmann for implementing the new designs, with guidance from Sage Abdullah.
This release adds a new "Locale" column to the listings and choosers of translatable models, making it easier to filter and sort by locale. The current content's locale is applied in choosers by default, with the ability to clear the locale filter. This feature was developed by Dan Braghis and Sage Abdullah.
While Wagtail provides a built-in API module based on the popular Django REST Framework, it is possible to use other approaches. This release adds a new guide, to demonstrate basic usage of Wagtail with Django Ninja, which leverages type hints and Pydantic for data validation. The guide covers common requirements beyond initial setup, like rich text, image renditions, and generation of API documentation.
This documentation was contributed by Thibaud Colas with support from Sage Abdullah.
WAGTAIL_ prefix to Wagtail-specific tag settings (Aayushman Singh)normalize on TypedTableBlock to assist with setting default and preview_value (Sage Abdullah)StreamBlock's value to assist with programmatic changes to StreamField (Matt Westcott)models.UniqueConstraint instead of unique_together (Oliver Parker, Cynthia Kiser, Sage Abdullah)standard tokenizer on Elasticsearch, to correctly handle numbers as tokens (Matt Westcott)get_default_privacy_setting (Shlomo Markowitz)get_template_for_action (Sage Abdullah)InspectView field display value via methods on the view (Dan Braghis)in and exact lookup on Elasticsearch (Sage Abdullah)InlinePanel will be correctly ordered after the first save when min_num is used (Elhussein Almasri, Joel William)assume_scheme on Django 5.x (Sage Abdullah)ImproperlyConfigured is thrown from db_field on unbound FieldPanels as intended (Matt Westcott)id (Sage Abdullah)WAGTAILADMIN_PERMITTED_LANGUAGES setting (Sébastien Corbin)django.contrib.admin to list of apps in "add to Django project" guide (Mohamed Rabiaa)request_or_site is optional on BaseGenericSetting.load (Matt Westcott)StreamField based form builder packages in the form builder documentation (Matt Westcott)insert_editor_js hook applies to all core editing/creation views (LB (Ben) Johnston)page.move method from django-treebeard (Shlomo Markowitz)Page.get_url_parts will return a tuple, not None for NoReverseMatch errors (Arthur Tripp)expand_db_html utility function to create HTML ready for display (Thibaud Colas)expand_db_html usage for rich text in REST framework API (Thibaud Colas)?limit with WAGTAILAPI_LIMIT_MAX (Thibaud Colas)downshift, focus-trap-react, immer, redux, uuid (LB (Ben) Johnston)wagtail.models module into submodules (Matt Westcott)ruff to 0.9.6 (Sage Abdullah)stubs & adapter contents to better support Jest testing (LB (Ben) Johnston)SkipLinkController to FocusController with improved reusability, updated unit tests, and added story (LB (Ben) Johnston)LocaleController time zones & non-deterministic page ordering tests (Sage Abdullah).html files as Django templates (Jake Howard)insert_editor_js hook output, deprecate the wrapper template tag _editor_js.html (Sai Srikar Dumpeti, LB (Ben) Johnston)default_auto_field setting to home app in project template (Sylvain Boissel)setup.py and setup.cfg to pyproject.toml (Sage Abdullah)move_choose_destination to a class-based view (Chiemezuo Akujobi)django-tasks to 0.7.x (Jake Howard)Features previously deprecated in Wagtail 5.2, 6.0, 6.1, 6.2 and 6.3 have been fully removed. For additional details on these changes, see:
The most significant changes are highlighted below.
classnames attribute on menu item and image format classesThe classnames keyword argument on the following classes is no longer supported and should be replaced with classname:
admin.menu.MenuItemadmin.ui.sidebar.ActionMenuItemadmin.ui.sidebar.LinkMenuItemadmin.ui.sidebar.PageExplorerMenuItemcontrib.settings.registry.SettingMenuItemwagtail.images.formats.FormatWAGTAIL_AUTO_UPDATE_PREVIEW setting is removed and should be replaced with WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL = 0 to disable auto-update.PASSWORD_REQUIRED_TEMPLATE setting is no longer recognized and should be replaced with WAGTAIL_PASSWORD_REQUIRED_TEMPLATE.DOCUMENT_PASSWORD_REQUIRED_TEMPLATE setting is no longer recognized and should be replaced with WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE.The settings WAGTAIL_USER_EDIT_FORM, WAGTAIL_USER_CREATION_FORM and WAGTAIL_USER_CUSTOM_FIELDS have been removed in favor of customizing the form classes via UserViewSet.get_form_class().
register_page_header_buttons, register_page_listing_buttons, construct_page_listing_buttons and register_page_listing_more_buttons now receive a user argument instead of page_perms.register_page_header_buttons receives a fourth argument view_name.construct_snippet_listing_buttons hook no longer accepts a context argument.register_user_listing_buttons hook now accepts a request_user argument instead of context.get_template method on StreamField blocks now accepts a value argument as its first argument.DISTRIBUTION_ID within the WAGTAILFRONTENDCACHE configuration setting is no longer supported, and should be replaced by multiple backends with a HOSTNAMES parameter.ModelViewSet no longer provides the URL patterns <int:pk>/ and <int:pk>/delete/ for editing and deleting; these have been replaced by edit/<str:pk>/ and delete/<str:pk>/.window.chooserUrls within Draftail choosers is removed.coreutils.escape_script function and escapescript template tag, and handling of <script type="text/django-form-template"> elements, are removed.js_translation_strings, locales and user_listing_buttons are removed.window.initBlockWidget, window.enableDirtyFormCheck, window.URLify, window.ActivateWorkflowActionsForDashboard, window.ActivateWorkflowActionsForEditView.window.wagtailConfig.BULK_ACTION_ITEM_TYPE is removed.data-tippy-content attribute is removed.DeleteMenuItem API is removed.(configuring_deferred_validation)=
For text-based fields (such as CharField, TextField, RichTextField and StreamField), the new behaviour of skipping required field validation on saving drafts is in place automatically, with no code changes required. For non-text-based fields (such as IntegerField and DateField) that are not defined with null=True, the database will not allow saving of blank values, and so the form will continue to enforce these as required fields even when saving as draft.
To allow a non-text-based field to be left blank on saving drafts, add null=True to its definition. The blank argument specifies whether the field is required on publish, and should be omitted (or set to blank=False) unless you intend the field to be fully optional. For example, the definition:
date_published = models.DateField("Date article published")
can be changed as follows to allow it to be left blank when saving as draft:
date_published = models.DateField("Date article published", null=True)
To strictly enforce requiredness on a field, including when saving as draft, you can set the attribute required_on_save = True on the model field, or pass required_on_save=True as an argument to FieldPanel. For example:
subtitle = models.CharField(max_length=255)
subtitle.required_on_save = True
or
content_panels = Page.content_panels + [FieldPanel("subtitle", required_on_save=True)]
This option is enabled as standard for the title field of page models. It is also recommended to use this option for any fields that are used in the __str__ representation of snippet models, so that these models always have a meaningful representation within listing views.
Page.save() no longer automatically calls full_clean for draft pagesIn previous releases, the save() method on page models called the full_clean method to apply model-level validation rules, regardless of whether the page was in a draft or live state, unless this was explicitly disabled by passing clean=False. As of this release, saving a page in a draft state (live=False) will only perform the minimum validation necessary to ensure data integrity: the title must be non-empty, and the slug must be unique within the parent page. Saving a page with live=True will apply full validation as before. If you have user code that creates draft pages and requires them to be validated, you must now call full_clean explicitly.
The "Snippets" sidebar menu item appears if there are snippet models without their own menu items. Previously, the "Snippets" menu item pointed to a snippets index view that listed all snippet models whether they'd been configured with their own menu items or not. This behaviour has been changed and the snippets index view will now only include snippet models that haven't been configured that way.
The new setting can be used to always show a top-level "Snippets" menu item in the sidebar pointing to an index view that includes all snippet models.
TAG_LIMIT and TAG_SPACES_ALLOWED settings renamed to WAGTAIL_TAG_LIMIT and WAGTAIL_TAG_SPACES_ALLOWEDThe TAG_LIMIT and TAG_SPACES_ALLOWED settings have been renamed to WAGTAIL_TAG_LIMIT and WAGTAIL_TAG_SPACES_ALLOWED respectively. The old settings will continue to work for now, but will be removed in a future release.
If your project has custom listing views in the admin that make use of the wagtailadmin/generic/index.html template but do not provide a breadcrumbs_items context variable, you will need to add this context variable to your view.
The breadcrumbs_items context variable is used to display the breadcrumbs in the admin interface as part of the Universal Listings project. This should be done automatically by the get_breadcrumbs_items method in the wagtail.admin.views.generic.base.BaseListingView class (or its subclasses, e.g. wagtail.admin.views.generic.IndexView).
If you have a custom listing view that does not inherit from the BaseListingView class, you will need to add the breadcrumbs_items context variable manually. Once added, the title header will be replaced by the breadcrumbs and the filters on the right sidebar will be replaced by the new AJAX-based filters pop-up in the header.
For now, listing views with no breadcrumbs will continue to have the title header and the legacy filters on the right sidebar, but the support will be removed in a future release.
insert_editor_js hook output in some non-editor viewsThe insert_editor_js was historically added to some non editing views, these have now been removed.
The confirm bulk move view and the chooser modal view for choosing the new location of bulk move pages will no longer use the hook output insert_editor_js. If custom JavaScript is needed in these views, migrate to the documented hook instead.
The insert_editor_js hook will continue to be output when editing pages, as documented.
wagtailadmin/pages/_editor_js.html templateThe undocumented template partial wagtailadmin/pages/_editor_js.html has been deprecated and will be removed in a future release.
If your project overrides the template to inject custom JavaScript into the Wagtail admin, you should follow the documented approaches to either use the hook or the hook instead.
wagtailadmin/shared/ajax_pagination_nav.html templateThe undocumented template partial wagtailadmin/shared/ajax_pagination_nav.html was marked for soft deprecation in Wagtail 2.16 and has now been removed.
If you use or override the template, you should use wagtailadmin/shared/pagination_nav.html with meaningful URLs as the linkurl value instead.
Fix: Avoid deprecation warnings about URLField assume_scheme on Django 5.x (Sage Abdullah)
WAGTAIL_ prefix to Wagtail-specific tag settings (Aayushman Singh)normalize on TypedTableBlock to assist with setting default and preview_value (Sage Abdullah)StreamBlock's value to assist with programmatic changes to StreamField (Matt Westcott)models.UniqueConstraint instead of unique_together (Oliver Parker, Cynthia Kiser, Sage Abdullah)standard tokenizer on Elasticsearch, to correctly handle numbers as tokens (Matt Westcott)get_default_privacy_setting (Shlomo Markowitz)get_template_for_action (Sage Abdullah)InspectView field display value via methods on the view (Dan Braghis)in and exact lookup on Elasticsearch (Sage Abdullah)InlinePanel will be correctly ordered after the first save when min_num is used (Elhussein Almasri, Joel William)assume_scheme on Django 5.x (Sage Abdullah)ImproperlyConfigured is thrown from db_field on unbound FieldPanels as intended (Matt Westcott)id (Sage Abdullah)WAGTAILADMIN_PERMITTED_LANGUAGES setting (Sébastien Corbin)django.contrib.admin to list of apps in "add to Django project" guide (Mohamed Rabiaa)insert_editor_js hook applies to all core editing/creation views (LB (Ben) Johnston)downshift, focus-trap-react, immer, redux, uuid (LB (Ben) Johnston)wagtail.models module into submodules (Matt Westcott)ruff to 0.9.6 (Sage Abdullah)stubs & adapter contents to better support Jest testing (LB (Ben) Johnston)SkipLinkController to FocusController with improved reusability, updated unit tests, and added story (LB (Ben) Johnston)LocaleController time zones & non-deterministic page ordering tests (Sage Abdullah).html files as Django templates (Jake Howard)insert_editor_js hook output, deprecate the wrapper template tag _editor_js.html (Sai Srikar Dumpeti, LB (Ben) Johnston)default_auto_field setting to home app in project template (Sylvain Boissel)setup.py and setup.cfg to pyproject.toml (Sage Abdullah)move_choose_destination to a class-based view (Chiemezuo Akujobi)wagtailadmin/shared/ajax_pagination_nav.html template (Sage Abdullah)Fix: Do not show upgrade notification if the installed version is the latest (Sage Abdullah)
child_block kwarg (Matt Westcott)utf8mb4 charset and collation for MySQL test database (Sage Abdullah)June 12, 2025
---
local:
depth: 1
---
child_block kwarg (Matt Westcott)utf8mb4 charset and collation for MySQL test database (Sage Abdullah)Fix: Prevent error when filtering by locale and searching with Elasticsearch (Sage Abdullah)
none() querysets (Matt Westcott)Page.get_route_paths docstring (Baptiste Mispelon)February 21, 2025
---
local:
depth: 1
---
none() querysets (Matt Westcott)Page.get_route_paths docstring (Baptiste Mispelon)Fix: Improve deprecation warning for WidgetWithScript by raising it with stacklevel=3 (Joren Hammudoglu)
django-tasks (Jake Howard)specific() sub-queries using select_related & prefetch_related (Andy Babic)DATA_UPLOAD_MAX_NUMBER_FIELDS in project template (Matt Westcott)allowed_http_methods (Andy Babic)FieldPanel / InlinePanel (Matt Westcott)on_serve_page hook to modify the serving chain of pages (Krystian Magdziarz, Dawid Bugajewski)WAGTAIL_GRAVATAR_PROVIDER_URL URLs with query string parameters (Ayaan Qadri, Guilhem Saurel)get_avatar_url hook to customise user avatars (James Harrington)page as a third parameter to the construct_wagtail_userbar hook (claudobahn)Fuzzy queries (Tom Usher)StreamField.get_default() to prevent creation forms from breaking (Matt Westcott)read_only Fieldpanels in use (Strapchay)th (table heading) elements that are not compliant with accessibility standards (Jai Vignesh J)MultipleChooserPanel using images or documents work when nested within an InlinePanel when no other choosers are in use within the model (Elhussein Almasri)MultipleChooserPanel works after doing a search in the page chooser modal (Matt Westcott)ListBlock instances get created with unique IDs in the admin client for accessibility and mini-map element references (Srishti Jaiswal)get_block_by_content_path on ImageBlock to prevent errors on commenting (Matt Westcott)aria-expanded attribute to new column button on TypedTableBlock to reflect menu state (Ayaan Qadri, Scott Cranfill)Page panel definitions without importing wagtail.admin (Matt Westcott)WidgetWithScript by raising it with stacklevel=3 (Joren Hammudoglu)Site.find_for_request() from Page.get_url_parts() (Andy Babic)StreamChildrenToListBlockOperation from duplicating data across multiple StreamField instances (Joshua Munn)wagtail start command to the management commands reference page (Damilola Oladele)DATA_UPLOAD_MAX_NUMBER_FIELDS when integrating Wagtail into Django (Matt Westcott)mark_safe to format_html for any script inclusions, to better avoid XSS issues from example code (Aayushman Singh)AbstractEmailForm or AbstractForm pages (John-Scott Atlakson, LB (Ben) Johnston)BlogTagIndexPage example for clarity (Clifford Gama)wagtailcache and wagtailpagecache examples to not use quotes for the fragment_name (Shiv)HTTPMethod in Page.handle_options_request() docs (Sage Abdullah)FieldPanel / InlinePanel where appropriate (Unyime Emmanuel Udoh)get_template method on StreamField blocks (Matt Westcott)RichTextBlock to a StreamField (Matt Westcott)ALLOWED_HOSTS check in Site.find_for_request (Jake Howard)CloneController to ensure that added/cleared events are not dispatched as cancelable (LB (Ben) Johnston)uuid UMD module as all code is now using the NPM module (LB (Ben) Johnston)eslint-disable no-undef linter directives with global comments (LB (Ben) Johnston)PreviewController usage to leverage Stimulus actions instead of calling preventDefault manually (Ayaan Qadri)ZoneController (w-zone) to support dynamic class name changes & event handling on container elements (Ayaan Qadri)ModalWorkflow (LB (Ben) Johnston)delay value in TagController to debounce async autocomplete tag fetch requests (Aayushman Singh)DrilldownController (Srishti Jaiswal)LinkController (w-link) (Sage Abdullah)EditView to make better use of generic EditView (Sage Abdullah)RulesController (w-rules) to support declarative conditional field enabling from other field values in a form (LB (Ben) Johnston)RulesController (w-rules) approach (LB (Ben) Johnston)ZoneController (w-zone) to support inactive class and a mechanism to switch the mode based on data within events (Ayaan Qadri)ZoneController (w-zone) to remove ad-hoc jQuery for the privacy switch when toggling visibility of private/public elements (Ayaan Qadri)is_active & active_menu_items from wagtail.admin.menu.MenuItem (Srishti Jaiswal)openpyxl at runtime to improve performance for projects that do not use ReportView, SpreadsheetExportMixin and wagtail.contrib.redirects (Sébastien Corbin)mp instead of mm for 'mystery person' as the default Gravatar if no avatar found (Harsh Dange)venv instead of pipenv in CircleCI (Sage Abdullah)FormsetController (w-formset) to support dynamic formset insertion/deletion behavior (LB (Ben) Johnston)revisions_revert view to be a subclass of EditView (Sage Abdullah)get_usage().count() call to view code (Sage Abdullah)4.2, 5.0, 5.1, 5.2
3.9, 3.10, 3.11, 3.12, 3.13
6.3 LTS
4.2, 5.0, 5.1, 5.2 [ 1 ]
3.9, 3.10, 3.11, 3.12, 3.13
February 3, 2025
---
local:
depth: 1
---
django-tasksWagtail now integrates with the django-tasks library to allow moving computationally-intensive tasks out of the request-response cycle, and improving the performance of the Wagtail admin interface. These tasks include:
In the default configuration, these tasks are executed immediately within the request-response cycle, as they were in previous versions of Wagtail. However, by configuring the TASKS setting with an appropriate backend as per the django-tasks documentation, these tasks can be deferred to a background worker process.
This feature was developed by Jake Howard.
You can now set up previews for StreamField blocks. The preview will be shown in the block picker, along with a description for the block. This feature can help users choose the right block when writing content inside a StreamField. To enable this feature, see .
This feature was developed by Sage Abdullah and Thibaud Colas.
The new documentation page curates important information about Wagtail’s headless capabilities, directly within the developer documentation. This is the foundation for a headless improvements roadmap for Wagtail.
Thank you to Sævar Öfjörð Magnússon and Alex Fulcher for creating this new page at the Wagtail Space NL 2024 sprint.
Building upon improvements in past versions, this release comes with further enhancements to alt text management:
ImageBlock alt text is now populated from the image’s default alt text when selecting a new image.ImageBlock alt text field is also populated from the image’s default alt text when converting from an ImageChooserBlock.alt-text-quality content check.Thank you to Matt Westcott, Thibaud Colas, and Cynthia Kiser for their work on these improvements.
FieldPanel and InlinePanelPlain strings can now be used in panel definitions as a substitute for FieldPanel and InlinePanel, avoiding the need to import these classes from wagtail.admin.panels:
class MyPage(Page):
body = RichTextField()
content_panels = [
"body",
]
This feature was developed by Matt Westcott.
The StreamField and InlinePanel interfaces now support drag-and-drop reordering of items within a field. This makes it faster to rearrange content within these fields, particularly when there is a lot of content.
This feature was developed by Thibaud Colas and Sage Abdullah, thanks to a sponsorship by Lyst.
For users of promoted search results, a new search terms report is available in the admin interface. This report shows terms that website users have searched for, and how many times they have been searched. This can help you understand what your users are looking for, and adjust your search promotions accordingly.
This feature was developed by Noah van der Meer and Sage Abdullah.
Following from a recent audit, this release comes with performance improvements focused on the user interface.
specific() sub-queries using select_related & prefetch_related, see (Andy Babic)DATA_UPLOAD_MAX_NUMBER_FIELDS in project template (Matt Westcott)allowed_http_methods (Andy Babic)on_serve_page hook to modify the serving chain of pages (Krystian Magdziarz, Dawid Bugajewski)WAGTAIL_GRAVATAR_PROVIDER_URL URLs with query string parameters (Ayaan Qadri, Guilhem Saurel)get_avatar_url hook to customise user avatars (James Harrington)page as a third parameter to the construct_wagtail_userbar hook (claudobahn)Fuzzy queries (Tom Usher)StreamField.get_default() to prevent creation forms from breaking (Matt Westcott)read_only FieldPanels in use (Strapchay)th (table heading) elements that are not compliant with accessibility standards (Jai Vignesh J)MultipleChooserPanel using images or documents work when nested within an InlinePanel when no other choosers are in use within the model (Elhussein Almasri)MultipleChooserPanel works after doing a search in the page chooser modal (Matt Westcott)ListBlock instances get created with unique IDs in the admin client for accessibility and mini-map element references (Srishti Jaiswal)get_block_by_content_path on ImageBlock to prevent errors on commenting (Matt Westcott)aria-expanded attribute to new column button on TypedTableBlock to reflect menu state (Ayaan Qadri, Scott Cranfill)Page panel definitions without importing wagtail.admin (Matt Westcott)WidgetWithScript by raising it with stacklevel=3 (Joren Hammudoglu)FilterField("created_at") to AbstractDocument to fix ordering by created_at after searching in the documents index view (Srishti Jaiswal)Site.find_for_request() from Page.get_url_parts() (Andy Babic)StreamChildrenToListBlockOperation from duplicating data across multiple StreamField instances (Joshua Munn)wagtail start command to the management commands reference page (Damilola Oladele)DATA_UPLOAD_MAX_NUMBER_FIELDS when integrating Wagtail into Django (Matt Westcott)mark_safe to format_html for any script inclusions, to better avoid XSS issues from example code (Aayushman Singh)AbstractEmailForm or AbstractForm pages (John-Scott Atlakson, LB (Ben) Johnston)BlogTagIndexPage example for clarity (Clifford Gama)wagtailcache and wagtailpagecache examples to not use quotes for the fragment_name (Shiv)HTTPMethod in Page.handle_options_request() docs (Sage Abdullah)FieldPanel / InlinePanel where appropriate (Unyime Emmanuel Udoh)get_template method on StreamField blocks (Matt Westcott)RichTextBlock to a StreamField (Matt Westcott)ALLOWED_HOSTS check in Site.find_for_request (Jake Howard)CloneController to ensure that added/cleared events are not dispatched as cancelable (LB (Ben) Johnston)uuid UMD module as all code is now using the NPM module (LB (Ben) Johnston)eslint-disable no-undef linter directives with global comments (LB (Ben) Johnston)PreviewController usage to leverage Stimulus actions instead of calling preventDefault manually (Ayaan Qadri)ZoneController (w-zone) to support dynamic class name changes & event handling on container elements (Ayaan Qadri)ZoneController usage (Ayaan Qadri)ModalWorkflow (LB (Ben) Johnston)delay value in TagController to debounce async autocomplete tag fetch requests (Aayushman Singh)DrilldownController (Srishti Jaiswal)LinkController (w-link) (Sage Abdullah)EditView to make better use of generic EditView (Sage Abdullah)RulesController (w-rules) to support declarative conditional field enabling from other field values in a form (LB (Ben) Johnston)RulesController (w-rules) approach (LB (Ben) Johnston)ZoneController (w-zone) to support inactive class and a mechanism to switch the mode based on data within events (Ayaan Qadri)ZoneController (w-zone) to remove ad-hoc jQuery for the privacy switch when toggling visibility of private/public elements (Ayaan Qadri)is_active & active_menu_items from wagtail.admin.menu.MenuItem (Srishti Jaiswal)openpyxl at runtime to improve performance for projects that do not use ReportView, SpreadsheetExportMixin and wagtail.contrib.redirects (Sébastien Corbin)mp instead of mm for 'mystery person' as the default Gravatar if no avatar found (Harsh Dange)venv instead of pipenv in CircleCI (Sage Abdullah)FormsetController (w-formset) to support dynamic formset insertion/deletion behavior (LB (Ben) Johnston)revisions_revert view to be a subclass of EditView (Sage Abdullah)get_usage().count() call to view code (Sage Abdullah)DATA_UPLOAD_MAX_NUMBER_FIELDS updateIt's recommended that all projects set the DATA_UPLOAD_MAX_NUMBER_FIELDS setting to 10000 or higher.
This specifies the maximum number of fields allowed in a form submission, and it is recommended to increase this from Django's default of 1000, as particularly complex page models can exceed this limit within Wagtail's page editor:
# settings.py
DATA_UPLOAD_MAX_NUMBER_FIELDS = 10_000
related_nameOn previous releases, form page models (defined through AbstractEmailForm, AbstractForm, FormMixin or EmailFormMixin) did not validate form fields where the related_name was different to the default value of form_fields. As a result, it was possible to create forms with duplicate field names - in this case, only a single field is displayed and captured in the resulting form.
In this new release, validation is now applied on these fields, existing forms will continue to behave as before and no data will be lost. However, editing them will now raise a validation error and users may need to delete any duplicated fields that they had previously missed.
The behaviour described here no longer applies as of `django-tasks` 0.10. Tasks are now enqueued immediately (and executed immediately if `ImmediateBackend` is in use), and the `ENQUEUE_ON_COMMIT` setting is no longer available.
In the default configuration, tasks managed by django-tasks (see above) run during the request-response cycle, as before. However, they are now deferred until the current transaction (if any) is committed. If ATOMIC_REQUESTS is set to True, this will be at the end of the request. This may lead to a change of behaviour on views that expect to see the results of these tasks immediately, such as a view that creates a page and then performs a search query to retrieve it. To restore the previous behaviour, set "ENQUEUE_ON_COMMIT": False in the TASKS setting:
# settings.py
TASKS = {
"default": {
"BACKEND": "django_tasks.backends.immediate.ImmediateBackend",
"ENQUEUE_ON_COMMIT": False,
}
}
Django's test framework typically runs tests inside transactions, and so this situation is also likely to arise in tests that perform database updates and then - within the same test - expect these changes to be immediately reflected in search queries, object usage counts, and other processes that are now handled with background tasks. This can be addressed by setting ENQUEUE_ON_COMMIT to False as above in the test settings, or by wrapping the database updates in with self.captureOnCommitCallbacks(execute=True) to ensure that these tasks are completed before the test continues:
def test_search(self):
home_page = Page.objects.get(slug="home")
with self.captureOnCommitCallbacks(execute=True): # Added
home_page.add_child(instance=EventPage(title="Christmas party"))
response = self.client.get("/search/?q=Christmas")
self.assertContains(response, "Christmas party")
page as a third parameter to the construct_wagtail_userbar hookIn previous releases, implementations of the construct_wagtail_userbar hook were expected to accept two arguments, whereas now page is passed in as a third argument.
Old
@hooks.register("construct_wagtail_userbar")
def construct_wagtail_userbar(request, items):
pass
New
@hooks.register("construct_wagtail_userbar")
def construct_wagtail_userbar(request, items, page):
pass
The old style will now produce a deprecation warning.
content_panels, promote_panels and settings_panels values on base Page modelPreviously, the content_panels, promote_panels and settings_panels attributes on the base Page model were defined as lists of Panel instances. These lists now contain instances of wagtail.models.PanelPlaceholder instead, which are resolved to Panel instances at runtime. Panel definitions that simply extend these lists (such as content_panels = Page.content_panels + [...]) are unaffected; however, any logic that inspects these lists (for example, finding a panel in the list to insert a new one immediately after it) will need to be updated to handle the new object types.
The unused JavaScript include wagtailadmin/js/vendor/rangy-core.js has been removed from the editor interface, and functions such as window.rangy.getSelection() are no longer available. Any code relying on this should now either supply its own copy of the Rangy library, or be migrated to the official Document.createRange() browser API.
window.buildExpandingFormset global functionThe undocumented global function window.buildExpandingFormset to attach JavaScript insertion / deletion behavior for Django formsets has been deprecated and will be removed in a future release.
Within the Wagtail admin this only impacts a small set of basic expanding formsets in use across Workflow and Group view editing. InlinePanel is not affected.
Previously these expanding formsets required a mix of specific id attribute structures and inline scripts to instantiate with callbacks for handling deletion. User code implementing this functionality through buildExpandingFormset should be updated - the following data attributes can be used to emulate the same behavior. These are likely to change and should not be considered official documentation.
| Element | Attribute(s) |
|---|---|
| Containing element | data-controller="w-formset" |
| Element to append new child forms | data-w-formset-target="forms" |
| Child form element | data-w-formset-target="child" |
| Deleted form element | data-w-formset-target="deleted" hidden |
template element for blank form |
data-w-formset-target="template" |
| Management field (total forms) | data-w-formset-target="totalFormsInput" |
| Management field (min forms) | data-w-formset-target="minFormsInput" |
| Management field (max forms) | data-w-formset-target="maxFormsInput" |
| Management field (Delete, within child form) | data-w-formset-target="deleteInput" |
Add child button |
data-action="w-formset#add" |
Delete child button (within child form) |
data-action="w-formset#delete" |
Usage of nested id structures are no longer required but can be left in place for easier debugging.
Fix: Improve deprecation warning for WidgetWithScript by raising it with stacklevel=3 (Joren Hammudoglu)
django-tasks (Jake Howard)specific() sub-queries using select_related & prefetch_related (Andy Babic)DATA_UPLOAD_MAX_NUMBER_FIELDS in project template (Matt Westcott)allowed_http_methods (Andy Babic)FieldPanel / InlinePanel (Matt Westcott)on_serve_page hook to modify the serving chain of pages (Krystian Magdziarz, Dawid Bugajewski)WAGTAIL_GRAVATAR_PROVIDER_URL URLs with query string parameters (Ayaan Qadri, Guilhem Saurel)get_avatar_url hook to customise user avatars (James Harrington)page as a third parameter to the construct_wagtail_userbar hook (claudobahn)Fuzzy queries (Tom Usher)StreamField values do not throw an error (Stefan Hammer)StreamField.get_default() to prevent creation forms from breaking (Matt Westcott)read_only Fieldpanels in use (Strapchay)th (table heading) elements that are not compliant with accessibility standards (Jai Vignesh J)MultipleChooserPanel using images or documents work when nested within an InlinePanel when no other choosers are in use within the model (Elhussein Almasri)MultipleChooserPanel works after doing a search in the page chooser modal (Matt Westcott)ListBlock instances get created with unique IDs in the admin client for accessibility and mini-map element references (Srishti Jaiswal)get_block_by_content_path on ImageBlock to prevent errors on commenting (Matt Westcott)aria-expanded attribute to new column button on TypedTableBlock to reflect menu state (Ayaan Qadri, Scott Cranfill)Page panel definitions without importing wagtail.admin (Matt Westcott)WidgetWithScript by raising it with stacklevel=3 (Joren Hammudoglu)Site.find_for_request() from Page.get_url_parts() (Andy Babic)wagtail start command to the management commands reference page (Damilola Oladele)DATA_UPLOAD_MAX_NUMBER_FIELDS when integrating Wagtail into Django (Matt Westcott)mark_safe to format_html for any script inclusions, to better avoid XSS issues from example code (Aayushman Singh)AbstractEmailForm or AbstractForm pages (John-Scott Atlakson, LB (Ben) Johnston)BlogTagIndexPage example for clarity (Clifford Gama)wagtailcache and wagtailpagecache examples to not use quotes for the fragment_name (Shiv)HTTPMethod in Page.handle_options_request() docs (Sage Abdullah)FieldPanel / InlinePanel where appropriate (Unyime Emmanuel Udoh)get_template method on StreamField blocks (Matt Westcott)ALLOWED_HOSTS check in Site.find_for_request (Jake Howard)CloneController to ensure that added/cleared events are not dispatched as cancelable (LB (Ben) Johnston)uuid UMD module as all code is now using the NPM module (LB (Ben) Johnston)eslint-disable no-undef linter directives with global comments (LB (Ben) Johnston)PreviewController usage to leverage Stimulus actions instead of calling preventDefault manually (Ayaan Qadri)ZoneController (w-zone) to support dynamic class name changes & event handling on container elements (Ayaan Qadri)ModalWorkflow (LB (Ben) Johnston)delay value in TagController to debounce async autocomplete tag fetch requests (Aayushman Singh)DrilldownController (Srishti Jaiswal)LinkController (w-link) (Sage Abdullah)EditView to make better use of generic EditView (Sage Abdullah)RulesController (w-rules) to support declarative conditional field enabling from other field values in a form (LB (Ben) Johnston)RulesController (w-rules) approach (LB (Ben) Johnston)ZoneController (w-zone) to support inactive class and a mechanism to switch the mode based on data within events (Ayaan Qadri)ZoneController (w-zone) to remove ad-hoc jQuery for the privacy switch when toggling visibility of private/public elements (Ayaan Qadri)is_active & active_menu_items from wagtail.admin.menu.MenuItem (Srishti Jaiswal)openpyxl at runtime to improve performance for projects that do not use ReportView, SpreadsheetExportMixin and wagtail.contrib.redirects (Sébastien Corbin)mp instead of mm for 'mystery person' as the default Gravatar if no avatar found (Harsh Dange)venv instead of pipenv in CircleCI (Sage Abdullah)FormsetController (w-formset) to support dynamic formset insertion/deletion behavior (LB (Ben) Johnston)revisions_revert view to be a subclass of EditView (Sage Abdullah)get_usage().count() call to view code (Sage Abdullah)Fix: CVE-2026-28222: Improper escaping of HTML (Cross-site Scripting) on TableBlock class attributes (Guan Chenxian, Matt Westcott)
March 3, 2026
---
local:
depth: 1
---
This release addresses a stored cross-site scripting (XSS) vulnerability on rendering TableBlock blocks within a StreamField. A user with access to create or edit pages containing TableBlock StreamField blocks is able to set specially-crafted class attributes on the block which run arbitrary JavaScript code when the page is viewed. When viewed by a user with higher privileges, this could lead to performing actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin, and only affects sites using TableBlock.
Many thanks to Guan Chenxian for reporting this issue. For further details, please see the CVE-2026-28222 security advisory.
This release addresses a stored cross-site scripting (XSS) vulnerability on confirmation messages within the wagtail.contrib.simple_translation module. A user with access to the Wagtail admin area may create a page with a specially-crafted title which, when another user performs the "Translate" action, causes arbitrary JavaScript code to run. This could lead to performing actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to Guan Chenxian for reporting this issue. For further details, please see the CVE-2026-28223 security advisory.
django.contrib.messages notification messagesNotification messages created through the django.contrib.messages module are now escaped according to Django's automatic HTML escaping mechanism when displayed within the Wagtail admin area. In most cases this is desirable to prevent cross-site scripting attacks; however, if your project makes intentional use of HTML markup within notification messages, this must now be passed as a safe string, through the use of a function such as format_html.
Remove upper bound on Pillow dependency
February 12, 2026
---
local:
depth: 1
---
Fix: CVE-2026-25517: Improper permission handling on admin preview endpoints (thxtech, Matt Westcott, Jake Howard)
February 3, 2026
---
local:
depth: 1
---
This release addresses a permission vulnerability in the Wagtail admin interface. Due to a missing permission check on the preview endpoints, a user with access to the Wagtail admin and knowledge of a model's fields can craft a form submission to obtain a preview rendering of any page or snippet object for which previews are enabled, consisting of any data of the user's choosing. The existing data of the object itself is not exposed, but depending on the nature of the template being rendered, this may expose other database contents that would otherwise only be accessible to users with edit access over the model. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Fix: Use correct URL when redirecting back to the listing after filtering and deleting form submissions (Sage Abdullah)
child_block kwarg (Matt Westcott)utf8mb4 charset and collation for MySQL test database (Sage Abdullah)June 12, 2025
---
local:
depth: 1
---
child_block kwarg (Matt Westcott)utf8mb4 charset and collation for MySQL test database (Sage Abdullah)Fix: Add missing “Close” label to the upgrade notification dismiss button (Sage Abdullah)
April 24, 2025
---
local:
depth: 1
---
This release adds support for Django 5.2.
Fix: Correctly place comment buttons next to date / datetime / time fields. (Srishti Jaiswal)
StreamChildrenToListBlockOperation from duplicating data across multiple StreamField instances (Joshua Munn)RichTextBlock to a StreamField (Matt Westcott)February 3, 2025
---
local:
depth: 1
---
StreamChildrenToListBlockOperation from duplicating data across multiple StreamField instances (Joshua Munn)RichTextBlock to a StreamField (Matt Westcott)Fix: Ensure Cloudfront cache invalidation is called with a list, for compatibility with current botocore versions (Jake Howard)
get_block_by_content_path on ImageBlock to prevent errors on commenting (Matt Westcott)January 2, 2025
---
local:
depth: 1
---
get_block_by_content_path on ImageBlock to prevent errors on commenting (Matt Westcott)Fix: Restore ability to upload profile picture through account settings (Sage Abdullah)
ImageChooserBlock to ImageBlock data conversions where all inputs to bulk_to_python are null (Storm Heg, Matt Westcott)BlogTagIndexPage example for clarity (Clifford Gama)wagtailcache and wagtailpagecache examples to not use quotes for the fragment_name (Shiv)November 19, 2024
---
local:
depth: 1
---
ImageChooserBlock to ImageBlock data conversions where all inputs to bulk_to_python are null (Storm Heg, Matt Westcott)BlogTagIndexPage example for clarity and several other tweaks (Clifford Gama)wagtailcache and wagtailpagecache examples to not use quotes for the fragment_name (Shiv)Deprecate the WAGTAIL_AUTO_UPDATE_PREVIEW setting, use WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL = 0 instead (Sage Abdullah)
ImageBlock with alt text support (Chiemezuo Akujobi for Google Summer of Code, mentored by Storm Heg, Saptak Sengupta, Thibaud Colas and Matt Westcott)getTextLabel method on date / time StreamField blocks (Vaughn Dickson)WAGTAIL_AUTO_UPDATE_PREVIEW setting, use WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL = 0 instead (Sage Abdullah)capfirst for title-casing model verbose names (Sébastien Corbin)copy_for_translation_done signal when copying translatable models as well as pages (Coen van der Kamp)description field across all images, to better support accessible image descriptions (Chiemezuo Akujobi)file_size field on document model to avoid artificial 2Gb limit (Gabriel Getzie)TypedTableBlock uses the correct API representations of child blocks (Matt Westcott)media definitions (Sage Abdullah)AbstractGroupApprovalTask to ensure can_handle checks for the abstract class correctly (Sumana Sree Angajala)WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT documentation to state that it defaults to False (Matt Westcott)TokenAuthentication in the Wagtail API v2 Configuration Guide (Krzysztof Jeziorny)zoneinfo.available_timezones (Sage Abdullah)get_prep_value for closer alignment with JSONField (Sage Abdullah)IndexView to BaseListingView (Sage Abdullah).in_bulk() on specific querysets under Django 5.2a0 (Sage Abdullah)test-media to .gitignore (Shlomo Markowitz)debounce util's return type for better TypeScript usage (Sage Abdullah)wagtailConfig values from inline scripts to the wagtail_config template tag (LB (Ben) Johnston, Sage Abdullah){% locales %} and {% js_translation_strings %} template tags (LB (Ben) Johnston, Sage Abdullah)window.wagtailConfig.BULK_ACTION_ITEM_TYPE usage in JavaScript to reduce reliance on inline scripts (LB (Ben) Johnston)window.fileupload_opts usage in JavaScript, use data attributes on fields instead to reduce reliance on inline scripts (LB (Ben) Johnston)image_format_name_to_content_type helper function that duplicates Willow functionality (Matt Westcott)DeleteMenuItem API for footer actions (Sage Abdullah)November 1, 2024
---
local:
depth: 1
---
Wagtail 6.3 is designated a Long Term Support (LTS) release. Long Term Support releases will continue to receive maintenance updates as necessary to address security and data-loss related issues, up until the next LTS release (typically a period of 12 months).
This release adds formal support for Python 3.13.
This release adds formal support for Django 5.1.
ImageBlock with alt text supportThis release introduces a new block type ImageBlock, which improves upon ImageChooserBlock by allowing editors to specify alt text tailored to the context in which the image is used. This is the new recommended block type for all images that are not purely decorative, and existing instances of ImageChooserBlock can be directly replaced with ImageBlock (with no data migration or template changes required) to benefit from contextual alt text. This feature was developed by Chiemezuo Akujobi as part of the Google Summer of Code program with mentoring support from Storm Heg, Saptak Sengupta, Thibaud Colas and Matt Westcott.
The Wagtail dashboard design evolves towards providing more information and navigation features. Mobile support is much improved. Upgrade banners are now dismissible.
This feature was developed by Albina Starykova and Sage Abdullah, based on designs by Ben Enright.
CMS users can now control the level of contrast of UI elements in the admin interface. This new customization is designed for partially sighted users, complementing existing support for a dark theme and Windows Contrast Themes. The new "More contrast" theming can be enabled in account preferences, or will otherwise be derived from operating system preferences.
This feature was designed thanks to feedback from our blind and partially sighted users, and was developed by Albina Starykova based on design input from Victoria Ottah.
This release follows through with "universal listings" user experience and design consistency improvements earlier in 2024, with the following features.
These features were developed by Sage Abdullah.
The WAGTAILIMAGES_EXTENSIONS setting now accepts the heic extension, which allows users to upload and use HEIC / HEIF images in Wagtail. These images are automatically converted to JPEG format when rendered. For more details, see .
This feature was developed by Matt Westcott.
You can now customize the preview device sizes available in the live preview panel by overriding {attr}~wagtail.models.PreviewableMixin.preview_sizes. The default size can also be set by overriding {attr}~wagtail.models.PreviewableMixin.default_preview_size.
This feature was developed by Bart Cieliński, alexkiro, and Sage Abdullah.
getTextLabel method on date / time StreamField blocks (Vaughn Dickson)WAGTAIL_AUTO_UPDATE_PREVIEW setting, use WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL = 0 instead (Sage Abdullah)capfirst for title-casing model verbose names (Sébastien Corbin)copy_for_translation_done signal when copying translatable models as well as pages (Coen van der Kamp)description field across all images, to better support accessible image descriptions (Chiemezuo Akujobi)StaticBlock now renders nothing by default when no template is specified (Sævar Öfjörð Magnússon)file_size field on document model to avoid artificial 2Gb limit (Gabriel Getzie)TypedTableBlock uses the correct API representations of child blocks (Matt Westcott)media definitions (Sage Abdullah)AbstractGroupApprovalTask to ensure can_handle checks for the abstract class correctly (Sumana Sree Angajala)fly.io deployment from the tutorial to this section (Vince Salvino)WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT documentation to state that it defaults to False (Matt Westcott)TokenAuthentication in the Wagtail API v2 Configuration Guide (Krzysztof Jeziorny)pytz dependency in favour of zoneinfo.available_timezones (Sage Abdullah)django-taggit dependency to allow 6.0 (Matt Westcott)SECRET_KEY in version and icon hashes (Jake Howard)get_prep_value for closer alignment with JSONField (Sage Abdullah)IndexView to BaseListingView (Sage Abdullah).in_bulk() on specific querysets under Django 5.2a0 (Sage Abdullah)test-media to .gitignore (Shlomo Markowitz)debounce util's return type for better TypeScript usage (Sage Abdullah)wagtailConfig values from inline scripts to the wagtail_config template tag (LB (Ben) Johnston, Sage Abdullah){% locales %} and {% js_translation_strings %} template tags (LB (Ben) Johnston, Sage Abdullah)beforeunload usage in UnsavedController to trigger a leave page warning when edits have been made (Shubham Mukati, Sage Abdullah)window.wagtailConfig.BULK_ACTION_ITEM_TYPE usage in JavaScript to reduce reliance on inline scripts (LB (Ben) Johnston)window.fileupload_opts usage in JavaScript, use data attributes on fields instead to reduce reliance on inline scripts (LB (Ben) Johnston)image_format_name_to_content_type helper function that duplicates Willow functionality (Matt Westcott)DeleteMenuItem API for footer actions (Sage Abdullah)Python 3.8 is no longer supported as of this release; please upgrade to Python 3.9 or above before upgrading Wagtail.
WAGTAIL_AUTO_UPDATE_PREVIEW settingThe WAGTAIL_AUTO_UPDATE_PREVIEW setting has been deprecated and will be removed in a future release.
To disable the automatic preview update feature, set WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL = 0 in your Django settings instead.
window.wagtailConfig.BULK_ACTION_ITEM_TYPEAs part of migrating away from inline scripts, the undocumented use of window.wagtailConfig.BULK_ACTION_ITEM_TYPE as a global has been deprecated and will be removed in a future release.
Old
{% block extra_js %}
{{ block.super }}
<script>
window.wagtailConfig.BULK_ACTION_ITEM_TYPE = 'SOME_ITEM';
</script>
{% endblock %}
New
Update usage of the wagtailadmin/bulk_actions/footer.html template include to declare the item_type.
{% block bulk_actions %}
{% include 'wagtailadmin/bulk_actions/footer.html' ... item_type="SOME_ITEM" %}
{% endblock %}
Custom item types for bulk actions are not officially supported yet and this approach is likely to get further changes in the future.
{% locales %} template tagThe undocumented locales template tag will be removed in a future release.
If access to JSON locales within JavaScript is needed, use window.wagtailConfig.LOCALES instead.
{% js_translation_strings %} template tagThe undocumented js_translation_strings template tag will be removed in a future release.
If access to JSON translation strings within JavaScript is needed, use window.wagtailConfig.STRINGS instead.
UpgradeNotificationPanel is no longer removable with construct_homepage_panels hookThe upgrade notification panel can still be removed with the WAGTAIL_ENABLE_UPDATE_CHECK = False setting.
SiteSummaryPanel is no longer removable with construct_homepage_panels hookThe summary items can still be removed with the construct_homepage_summary_items hook.
DeleteMenuItemThe undocumented DeleteMenuItem API will be removed in a future release.
The delete option is now provided via EditView.get_header_more_buttons(), though this is still an internal-only API.
Deprecate the WAGTAIL_AUTO_UPDATE_PREVIEW setting, use WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL = 0 instead (Sage Abdullah)
Note: 6.3rc1 has been retracted due to packaging issues
ImageBlock with alt text support (Chiemezuo Akujobi for Google Summer of Code, mentored by Storm Heg, Saptak Sengupta, Thibaud Colas and Matt Westcott)getTextLabel method on date / time StreamField blocks (Vaughn Dickson)WAGTAIL_AUTO_UPDATE_PREVIEW setting, use WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL = 0 instead (Sage Abdullah)capfirst for title-casing model verbose names (Sébastien Corbin)copy_for_translation_done signal when copying translatable models as well as pages (Coen van der Kamp)description field across all images, to better support accessible image descriptions (Chiemezuo Akujobi)file_size field on document model to avoid artificial 2Gb limit (Gabriel Getzie)TypedTableBlock uses the correct API representations of child blocks (Matt Westcott)media definitions (Sage Abdullah)WAGTAIL_WORKFLOW_REQUIRE_REAPPROVAL_ON_EDIT documentation to state that it defaults to False (Matt Westcott)TokenAuthentication in the Wagtail API v2 Configuration Guide (Krzysztof Jeziorny)zoneinfo.available_timezones (Sage Abdullah)get_prep_value for closer alignment with JSONField (Sage Abdullah)IndexView to BaseListingView (Sage Abdullah).in_bulk() on specific querysets under Django 5.2a0 (Sage Abdullah)test-media to .gitignore (Shlomo Markowitz)debounce util's return type for better TypeScript usage (Sage Abdullah)wagtailConfig values from inline scripts to the wagtail_config template tag (LB (Ben) Johnston, Sage Abdullah){% locales %} and {% js_translation_strings %} template tags (LB (Ben) Johnston, Sage Abdullah)window.wagtailConfig.BULK_ACTION_ITEM_TYPE usage in JavaScript to reduce reliance on inline scripts (LB (Ben) Johnston)window.fileupload_opts usage in JavaScript, use data attributes on fields instead to reduce reliance on inline scripts (LB (Ben) Johnston)image_format_name_to_content_type helper function that duplicates Willow functionality (Matt Westcott)DeleteMenuItem API for footer actions (Sage Abdullah)Nothing published for this version
Fix: Fix broken migration when ListBlock is defined with a child_block kwarg (Matt Westcott)
child_block kwarg (Matt Westcott)June 12, 2025
---
local:
depth: 1
---
child_block kwarg (Matt Westcott)Fix: Prevent multiple URLs from being combined into one when pasting links into a rich text input (Thibaud Colas)
November 1, 2024
---
local:
depth: 1
---
Fix: Fix various instances of USE_THOUSAND_SEPARATOR formatting numbers where formatting is invalid (Sébastien Corbin, Matt Westcott)
USE_THOUSAND_SEPARATOR formatting numbers where formatting is invalid (Sébastien Corbin, Matt Westcott)September 24, 2024
---
local:
depth: 1
---
USE_THOUSAND_SEPARATOR formatting numbers where formatting is invalid (Sébastien Corbin, Matt Westcott)Fix: Handle child_block being passed as a kwarg in ListBlock migrations (Matt Westcott)
child_block being passed as a kwarg in ListBlock migrations (Matt Westcott)wagtail.admin.models and custom user models (Matt Westcott)August 20, 2024
---
local:
depth: 1
---
child_block being passed as a kwarg in ListBlock migrations (Matt Westcott)wagtail.admin.models and custom user models (Matt Westcott)Optimize and consolidate redirects report view into the index view (Jake Howard, Dan Braghis)
HOSTNAMES parameter on WAGTAILFRONTENDCACHE to define which hostnames a backend should respond to (Jake Howard, sponsored by Oxfam America)EditView and breadcrumbs (Rohit Sharma)ChooseParentView if only one possible valid parent page is available (Matthias Brück)copy_for_translation_done signal when a page is copied for translation (Arnar Tumi Þorsteinsson)deactivate() method to ProgressController (Alex Morega)ModelViewSet (Sage Abdullah)routable_resolver_match attribute available on RoutablePageMixin responses (Andy Chosak)UserViewSet via the app config (Sage Abdullah)StreamBlock / ListBlock min_num / max_num (Matt Westcott)WAGTAILIMAGES_CHOOSER_PAGE_SIZE setting functional again (Rohit Sharma)richtext template tag to convert lazy translation values (Benjamin Bach).ico images (Julie Rymer)verbose_name on TranslatableMixin.locale so that it is translated when used as a label (Romein van Buren)wagtail_serve view is on a non-root path (Sage Abdullah)for_instance method to PageLogEntryManager (Matt Westcott)WAGTAIL_DATE_FORMAT, WAGTAIL_DATETIME_FORMAT and WAGTAIL_TIME_FORMAT take FORMAT_MODULE_PATH into account (Sébastien Corbin)restriction_type field on PageViewRestriction (Shlomo Markowitz)Orderable is not required for inline panels (Bojan Mihelac)prefers-reduced-motion to the accessibility documentation (Roel Koper)vary_fields property for custom image filters (Daniel Kirkham)DjangoJSONEncoder instead of custom LazyStringEncoder to serialize Draftail config (Sage Abdullah)WAGTAILIMAGES_CHOOSER_PAGE_SIZE at runtime (Matt Westcott)client/scss directory in Tailwind content config to speed up CSS compilation (Sage Abdullah)contrib.frontend_cache.backends into dedicated sub-modules (Andy Babic)docs/autobuild.sh script (Sævar Öfjörð Magnússon)urlparse with urlsplit to improve performance (Jake Howard)'BlockWidget' object has no attribute '_block_json' from masking errors during StreamField serialization (Matt Westcott)August 1, 2024
---
local:
depth: 1
---
The page editor’s Checks panel now displays two content metrics: word count, and reading time. They are calculated based on the contents of the page preview, with a new mechanism to extract content from the previewed page for processing within the page editor. The Checks panel has also been redesigned to accommodate a wider breadth of types of checks, and interactive checks, in future releases.
This feature was developed by Albina Starykova and sponsored by The Motley Fool.
When multiple users concurrently work on the same content, Wagtail now displays notifications to inform them of potential editing conflicts. When a user saves their work, other users are informed and presented with options: they can refresh the page to view the latest changes, or proceed with their own changes, overwriting the other user's work.
Concurrent editing notifications are available for pages, and snippets. Specific messaging about conflicting versions is only available for pages and snippets with support for saving revisions. To configure how often notifications are updated, use WAGTAIL_EDITING_SESSION_PING_INTERVAL.
This feature was implemented by Matt Westcott and Sage Abdullah.
The built-in accessibility checker now enforces a new alt-text-quality rule, which tests alt text for the presence of known bad patterns such as file extensions and underscores. This rule is enabled by default, but can be disabled if necessary.
This feature was implemented by Albina Starykova, with support from the Wagtail accessibility team.
All built-in and custom report views now use the Universal Listings visual design and filtering features introduced in all other listings in the admin interface over past releases. Thank you to Sage Abdullah for implementing this feature and continuing the rollout of the new designs.
StreamField definitions within migrations are now represented in a more compact form, where blocks that appear in multiple places within a StreamField structure are only defined once. For complex and deeply-nested StreamFields, this considerably reduces the size of migration files, and the memory consumption when loading them. This feature was developed by Matt Westcott.
HOSTNAMES parameter on WAGTAILFRONTENDCACHE to define which hostnames a backend should respond to (Jake Howard, sponsored by Oxfam America)EditView and breadcrumbs (Rohit Sharma)ChooseParentView if only one possible valid parent page is available (Matthias Brück)copy_for_translation_done signal when a page is copied for translation (Arnar Tumi Þorsteinsson)deactivate() method to ProgressController (Alex Morega)ModelViewSet (Sage Abdullah)routable_resolver_match attribute available on RoutablePageMixin responses (Andy Chosak)UserViewSet via the app config (Sage Abdullah)StreamBlock / ListBlock min_num / max_num (Matt Westcott)WAGTAILIMAGES_CHOOSER_PAGE_SIZE setting functional again (Rohit Sharma)richtext template tag to convert lazy translation values (Benjamin Bach).ico images (Julie Rymer)verbose_name on TranslatableMixin.locale so that it is translated when used as a label (Romein van Buren)wagtail_serve view is on a non-root path (Sage Abdullah)for_instance method to PageLogEntryManager (Matt Westcott)WAGTAIL_DATE_FORMAT, WAGTAIL_DATETIME_FORMAT and WAGTAIL_TIME_FORMAT take FORMAT_MODULE_PATH into account (Sébastien Corbin)restriction_type field on PageViewRestriction (Shlomo Markowitz)Orderable is not required for inline panels (Bojan Mihelac)prefers-reduced-motion to the accessibility documentation (Roel Koper)vary_fields property for custom image filters (Daniel Kirkham)DjangoJSONEncoder instead of custom LazyStringEncoder to serialize Draftail config (Sage Abdullah)WAGTAILIMAGES_CHOOSER_PAGE_SIZE at runtime (Matt Westcott)client/scss directory in Tailwind content config to speed up CSS compilation (Sage Abdullah)contrib.frontend_cache.backends into dedicated sub-modules (Andy Babic)docs/autobuild.sh script (Sævar Öfjörð Magnússon)urlparse with urlsplit to improve performance (Jake Howard)'BlockWidget' object has no attribute '_block_json' from masking errors during StreamField serialization (Matt Westcott)Previous versions allowed passing a dict for DISTRIBUTION_ID within the WAGTAILFRONTENDCACHE configuration for a CloudFront backend, to allow specifying different distribution IDs for different hostnames. This is now deprecated; instead, multiple distribution IDs should be defined as multiple backends, with a HOSTNAMES parameter to define the hostnames associated with each one. For example, a configuration such as:
WAGTAILFRONTENDCACHE = {
"cloudfront": {
"BACKEND": "wagtail.contrib.frontend_cache.backends.CloudfrontBackend",
"DISTRIBUTION_ID": {
"www.wagtail.org": "your-distribution-id",
"www.madewithwagtail.org": "other-distribution-id",
},
},
}
should now be rewritten as:
WAGTAILFRONTENDCACHE = {
"mainsite": {
"BACKEND": "wagtail.contrib.frontend_cache.backends.CloudfrontBackend",
"DISTRIBUTION_ID": "your-distribution-id",
"HOSTNAMES": ["www.wagtail.org"],
},
"madewithwagtail": {
"BACKEND": "wagtail.contrib.frontend_cache.backends.CloudfrontBackend",
"DISTRIBUTION_ID": "other-distribution-id",
"HOSTNAMES": ["www.madewithwagtail.org"],
},
}
ModelViewSet and SnippetViewSetModels registered with a ModelViewSet will now automatically have their {class}~django.contrib.auth.models.Permission objects registered in the Groups administration area. Previously, you need to use the register_permissions hook to register them.
If you have a model registered with a ModelViewSet and you registered the model's permissions using the register_permissions hook, you can now safely remove the hook.
If the viewset has {attr}~wagtail.admin.viewsets.model.ModelViewSet.inspect_view_enabled set to True, all permissions for the model are registered. Otherwise, the "view" permission is excluded from the registration.
To customize which permissions get registered for the model, you can override the {meth}~wagtail.admin.viewsets.model.ModelViewSet.get_permissions_to_register method.
This behavior now applies to snippets as well. Previously, the "view" permission for snippets is always registered regardless of inspect_view_enabled. If you wish to register the "view" permission, you can enable the inspect view:
class FooViewSet(SnippetViewSet):
...
inspect_view_enabled = True
Alternatively, if you wish to register the "view" permission without enabling the inspect view (i.e. the previous behavior), you can override get_permissions_to_register like the following:
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
class FooViewSet(SnippetViewSet):
def get_permissions_to_register(self):
content_type = ContentType.objects.get_for_model(self.model)
return Permission.objects.filter(content_type=content_type)
WAGTAIL_USER_EDIT_FORM, WAGTAIL_USER_CREATION_FORM, and WAGTAIL_USER_CUSTOM_FIELDS settingsThis release introduces a customizable UserViewSet class, which can be used to customize various aspects of Wagtail's admin views for managing users, including the form classes for creating and editing users. As a result, the WAGTAIL_USER_EDIT_FORM, WAGTAIL_USER_CREATION_FORM, and WAGTAIL_USER_CUSTOM_FIELDS settings have been deprecated in favor of customizing the form classes via UserViewSet.get_form_class().
If you use the aforementioned settings, you can migrate your code by making the following changes.
Given the following custom user model:
class User(AbstractUser):
country = models.CharField(verbose_name="country", max_length=255)
status = models.ForeignKey(
MembershipStatus, on_delete=models.SET_NULL, null=True, default=1
)
The following custom forms:
class CustomUserEditForm(UserEditForm):
status = forms.ModelChoiceField(
queryset=MembershipStatus.objects, required=True, label=_("Status")
)
class CustomUserCreationForm(UserCreationForm):
status = forms.ModelChoiceField(
queryset=MembershipStatus.objects, required=True, label=_("Status")
)
And the following settings:
WAGTAIL_USER_EDIT_FORM = "myapp.forms.CustomUserEditForm"
WAGTAIL_USER_CREATION_FORM = "myapp.forms.CustomUserCreationForm"
WAGTAIL_USER_CUSTOM_FIELDS = ["country", "status"]
Change the custom forms to the following:
class CustomUserEditForm(UserEditForm):
status = forms.ModelChoiceField(
queryset=MembershipStatus.objects, required=True, label=_("Status")
)
# Use ModelForm's automatic form fields generation for the model's `country` field,
# but use an explicit custom form field for `status`.
# This replaces the `WAGTAIL_USER_CUSTOM_FIELDS` setting.
class Meta(UserEditForm.Meta):
fields = UserEditForm.Meta.fields | {"country", "status"}
class CustomUserCreationForm(UserCreationForm):
status = forms.ModelChoiceField(
queryset=MembershipStatus.objects, required=True, label=_("Status")
)
# Use ModelForm's automatic form fields generation for the model's `country` field,
# but use an explicit custom form field for `status`.
# This replaces the `WAGTAIL_USER_CUSTOM_FIELDS` setting.
class Meta(UserCreationForm.Meta):
fields = UserEditForm.Meta.fields | {"country", "status"}
Create a custom UserViewSet subclass in e.g. myapp/viewsets.py:
# myapp/viewsets.py
from wagtail.users.views.users import UserViewSet as WagtailUserViewSet
from .forms import CustomUserCreationForm, CustomUserEditForm
class UserViewSet(WagtailUserViewSet):
# This replaces the WAGTAIL_USER_EDIT_FORM and WAGTAIL_USER_CREATION_FORM settings
def get_form_class(self, for_update=False):
if for_update:
return CustomUserEditForm
return CustomUserCreationForm
If you already have a custom GroupViewSet as described in , you can reuse the custom WagtailUsersAppConfig subclass. Otherwise, create an apps.py file within your project folder (the one containing the top-level settings and urls modules) e.g. myproject/apps.py. Then, create a custom WagtailUsersAppConfig subclass in that file, with a user_viewset attribute pointing to the custom UserViewSet subclass:
# myproject/apps.py
from wagtail.users.apps import WagtailUsersAppConfig
class CustomUsersAppConfig(WagtailUsersAppConfig):
user_viewset = "myapp.viewsets.UserViewSet"
# If you have customized the GroupViewSet before
group_viewset = "myapp.viewsets.GroupViewSet"
Replace wagtail.users in settings.INSTALLED_APPS with the path to CustomUsersAppConfig:
INSTALLED_APPS = [
...,
# Make sure you have two separate entries for the custom user model's app
# and the custom app config for the wagtail.users app
"myapp", # an app that contains the custom user model
"myproject.apps.CustomUsersAppConfig", # a custom app config for the wagtail.users app
# "wagtail.users", # this should be removed in favour of the custom app config
...,
]
You can also place the `WagtailUsersAppConfig` subclass inside the same `apps.py` file of your custom user model's app (instead of in a `myproject/apps.py` file), but you need to be careful. Make sure to use two separate config classes instead of turning your existing `AppConfig` subclass into a `WagtailUsersAppConfig` subclass, as that would cause Django to pick up your custom user model as being part of `wagtail.users`. You may also need to set {attr}`~django.apps.AppConfig.default` to `True` in your own app's `AppConfig`, unless you already use a dotted path to the app's `AppConfig` subclass in `INSTALLED_APPS`.
The report views have been reimplemented to use the new Universal Listings UI, which introduces AJAX-based filtering and support for the wagtail.admin.ui.tables framework.
As a result, a number of changes have been made to the ReportView and PageReportView classes, as well as their templates.
If you have custom report views as documented in , you will need to make the following changes.
title to page_titleThe title attribute on the view class should be renamed to page_title:
class UnpublishedChangesReportView(PageReportView):
- title = "Pages with unpublished changes"
+ page_title = "Pages with unpublished changes"
Set the index_url_name and index_results_url_name attributes on the view class:
class UnpublishedChangesReportView(PageReportView):
+ index_url_name = "unpublished_changes_report"
+ index_results_url_name = "unpublished_changes_report_results"
and register the results-only view:
@hooks.register("register_admin_urls")
def register_unpublished_changes_report_url():
return [
path("reports/unpublished-changes/", UnpublishedChangesReportView.as_view(), name="unpublished_changes_report"),
+ # Add a results-only view to add support for AJAX-based filtering
+ path("reports/unpublished-changes/results/", UnpublishedChangesReportView.as_view(results_only=True), name="unpublished_changes_report_results"),
]
If you are only extending the templates to add your own markup for the listing table (and not other parts of the view template), you need to change the template_name into results_template_name on the view class.
For a page report, the following changes are needed:
template_name to results_template_name, and optionally rename the template (e.g. reports/unpublished_changes_report.html to reports/unpublished_changes_report_results.html).wagtailadmin/reports/base_page_report_results.html.listing and no_results blocks should be renamed to results and no_results_message, respectively. class UnpublishedChangesReportView(PageReportView):
- template_name = "reports/unpublished_changes_report.html"
+ results_template_name = "reports/unpublished_changes_report_results.html"
{# <project>/templates/reports/unpublished_changes_report_results.html #}
-{% extends "wagtailadmin/reports/base_page_report.html" %}
+{% extends "wagtailadmin/reports/base_page_report_results.html" %}
-{% block listing %}
+{% block results %}
{% include "reports/include/_list_unpublished_changes.html" %}
{% endblock %}
-{% block no_results %}
+{% block no_results_message %}
<p>No pages with unpublished changes.</p>
{% endblock %}
For a non-page report, the following changes are needed:
template_name to results_template_name, and optionally rename the template (e.g. reports/custom_non_page_report.html to reports/custom_non_page_report_results.html).wagtailadmin/reports/base_report_results.html.results block containing both the results listing and the "no results" message; these should now become separate blocks named results and no_results_message.Before:
class CustomNonPageReportView(ReportView):
template_name = "reports/custom_non_page_report.html"
{# <project>/templates/reports/custom_non_page_report.html #}
{% extends "wagtailadmin/reports/base_report.html" %}
{% block results %}
{% if object_list %}
<table class="listing">
<!-- Table markup goes here -->
</table>
{% else %}
<p>No results found.</p>
{% endif %}
{% endblock %}
After:
class CustomNonPageReportView(ReportView):
results_template_name = "reports/custom_non_page_report_results.html"
{# <project>/templates/reports/custom_non_page_report_results.html #}
{% extends "wagtailadmin/reports/base_report_results.html" %}
{% block results %}
<table class="listing">
<!-- Table markup goes here -->
</table>
{% endblock %}
{% block no_results_message %}
<p>No results found.</p>
{% endblock %}
If you need to completely customize the view's template, you can still override the template_name attribute on the view class. Note that both ReportView and PageReportView now use the wagtailadmin/reports/base_report.html template, which now extends the wagtailadmin/generic/listing.html template. The wagtailadmin/reports/base_page_report.html template is now unused and should be replaced with wagtailadmin/reports/base_report.html.
If you override template_name, it is still necessary to set results_template_name to a template that extends wagtailadmin/reports/base_report_results.html (or wagtailadmin/reports/base_page_report_results.html for page reports), so the view can correctly update the listing and show the active filters as you apply or remove any filters.
window.ActivateWorkflowActionsForDashboard and window.ActivateWorkflowActionsForEditViewThe undocumented usage of the JavaScript window.ActivateWorkflowActionsForDashboard and window.ActivateWorkflowActionsForEditView functions will be removed in a future release.
These functions are only used by Wagtail to initialize event listeners to workflow action buttons via inline scripts and are never intended to be used in custom code. The inline scripts have been removed in favour of initializing the event listeners directly in the included workflow-action.js script. As a result, the functions no longer need to be globally-accessible.
Any custom workflow actions should be done using the documented approach for customizing the behavior of custom task types, such as by overriding Task.get_actions().
Optimize and consolidate redirects report view into the index view (Jake Howard, Dan Braghis)
HOSTNAMES parameter on WAGTAILFRONTENDCACHE to define which hostnames a backend should respond to (Jake Howard, sponsored by Oxfam America)EditView and breadcrumbs (Rohit Sharma)ChooseParentView if only one possible valid parent page availale (Matthias Brück)copy_for_translation_done signal when a page is copied for translation (Arnar Tumi Þorsteinsson)deactivate() method to ProgressController (Alex Morega)ModelViewSet (Sage Abdullah)routable_resolver_match attribute available on RoutablePageMixin responses (Andy Chosak)UserViewSet via the app config (Sage Abdullah)StreamBlock / ListBlock min_num / max_num (Matt Westcott)WAGTAILIMAGES_CHOOSER_PAGE_SIZE setting functional again (Rohit Sharma)richtext template tag to convert lazy translation values (Benjamin Bach).ico images (Julie Rymer)verbose_name on TranslatableMixin.locale so that it is translated when used as a label (Romein van Buren)wagtail_serve view is on a non-root path (Sage Abdullah)for_instance method to PageLogEntryManager (Matt Westcott)WAGTAIL_DATE_FORMAT, WAGTAIL_DATETIME_FORMAT and WAGTAIL_TIME_FORMAT take FORMAT_MODULE_PATH into account (Sébastien Corbin)restriction_type field on PageViewRestriction (Shlomo Markowitz)Orderable is not required for inline panels (Bojan Mihelac)prefers-reduced-motion to the accessibility documentation (Roel Koper)vary_fields property for custom image filters (Daniel Kirkham)DjangoJSONEncoder instead of custom LazyStringEncoder to serialize Draftail config (Sage Abdullah)WAGTAILIMAGES_CHOOSER_PAGE_SIZE at runtime (Matt Westcott)client/scss directory in Tailwind content config to speed up CSS compilation (Sage Abdullah)contrib.frontend_cache.backends into dedicated sub-modules (Andy Babic)docs/autobuild.sh script (Sævar Öfjörð Magnússon)urlparse with urlsplit to improve performance (Jake Howard)Fix: CVE-2024-39317: Regular expression denial-of-service via search query parsing (Jake Howard)
.ico images (Julie Rymer)July 11, 2024
---
local:
depth: 1
---
This release addresses a denial-of-service vulnerability in Wagtail. A bug in Wagtail's parse_query_string would result in it taking a long time to process suitably crafted inputs. When used to parse sufficiently long strings of characters without a space, parse_query_string would take an unexpectedly large amount of time to process, resulting in a denial of service.
In an initial Wagtail installation, the vulnerability can be exploited by any Wagtail admin user. It cannot be exploited by end users. If your Wagtail site has a custom search implementation which uses parse_query_string, it may be exploitable by other users (e.g. unauthenticated users).
Many thanks to Jake Howard for reporting and fixing this issue. For further details, please see the CVE-2024-39317 security advisory.
.ico images (Julie Rymer)Fix: CVE-2024-35228: Improper handling of insufficient permissions in wagtail.contrib.settings (Victor Miti, Matt Westcott, Jake Howard)
ChoiceBlock (Matt Westcott)wagtail.contrib.settings (Victor Miti, Matt Westcott, Jake Howard)May 30, 2024
---
local:
depth: 1
---
wagtail.contrib.settingsThis release addresses a permission vulnerability in the Wagtail admin interface. Due to an improperly applied permission check in the wagtail.contrib.settings module, a user with access to the Wagtail admin and knowledge of the URL of the edit view for a settings model can access and update that setting, even when they have not been granted permission over the model. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Many thanks to Victor Miti for reporting this issue, and Matt Westcott and Jake Howard for the fix. For further details, please see the CVE-2024-35228 security advisory.
ChoiceBlock (Matt Westcott)Fix: Fix form action URL in user edit and delete views for custom user models (Sage Abdullah)
May 21, 2024
---
local:
depth: 1
---
Fix: CVE-2024-32882: Permission check bypass when editing a model with per-field restrictions through wagtail.contrib.settings or ModelViewSet (Ben Mo…
WAGTAIL_DATE_FORMAT, WAGTAIL_DATETIME_FORMAT, WAGTAIL_TIME_FORMAT are correctly configured (Rohit Sharma, Coen van der Kamp)IndexView using the generic.IndexView (Rohit Sharma, Sage Abdullah, Storm Heg)IndexView using the generic.IndexView (Rohit Sharma, Sage Abdullah, Temidayo Azeez)PageListingViewSet for custom per-page-type page listings (Matt Westcott)ChooseParentView to PageListingViewSet to allow creating pages from custom page listings (Abdelrahman Hamada, Sage Abdullah)djangorestframework to 3.15.1 (Sage Abdullah)IndexView.list_display (Abdelrahman Hamada)STORAGES alias name for WAGTAILIMAGES_RENDITION_STORAGE (Alec Baron)PASSWORD_REQUIRED_TEMPLATE setting to WAGTAIL_PASSWORD_REQUIRED_TEMPLATE with deprecation of previous naming (Saksham Misra, LB (Ben) Johnston)DOCUMENT_PASSWORD_REQUIRED_TEMPLATE setting to WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE with deprecation of previous naming (Saksham Misra, LB (Ben) Johnston)get_parent (Nigel van Keulen)wagtail.contrib.settings or ModelViewSet (Ben Morse, Joshua Munn, Jake Howard, Sage Abdullah)__str__ for MySQL search index (Jake Howard)date objects on human_readable_date template tag (Jhonatan Lopes)verbose_name in group edit view when listing custom permissions (Sage Abdullah, Neeraj Yetheendran, Omkar Jadhav)make livehtml (Sage Abdullah)LANGUAGE_CODE (Mark Niehues)UnsavedController checks for nested removal/additions of inputs so that the unsaved warning shows in more valid cases when editing a page (Karthik Ayangar)get_add_url() is always used to re-render the add button when the listing is refreshed in viewsets (Sage Abdullah)objects manager (Jhonatan Lopes)get_dummy_request's resulting host name when running tests with ALLOWED_HOSTS = ["*"] (David Buxton)timesince_last_update template tag (Matt Westcott)w-kbd-scope-value with support for global so that specific keyboard shortcuts (e.g. ctrl+s/cmd+s) trigger consistently even when focused on fields (Neeraj Yetheendran)WAGTAIL_ALLOW_UNICODE_SLUGS setting when auto-generating slugs (LB (Ben) Johnston)convert_mariadb_uuids management command to assist with upgrading to Django 5.0+ on MariaDB (Matt Westcott)--purge-only in wagtail_update_image_renditions management command section (Pranith Beeram)6.3.0 with a fix for the missing favicon (Sage Abdullah)wagtail_update_image_renditions management command on the using images page (LB (Ben) Johnston)html.parser (Jake Howard)html.parser & remove html5lib dependency (Jake Howard)Button that only renders links (a element) to Link and remove unused prop & behavior that was non-compliant for aria role usage (Advik Kabra)wagtail.models.AbstractWorkflow model to support future customizations around workflows (Hossein)classnames template tag to handle nested lists of strings, use template tag for admin body element (LB (Ben) Johnston)UploadedDocument and UploadedImage into new UploadedFile model for easier shared code usage (Advik Kabra, Karl Hobley)window.chooserUrls globals, removing the need for inline scripts (Elhussein Almasri)w-init (InitController) to support a detail value to be dispatched on events (Chiemezuo Akujobi)page_breadcrumbs tag to use shared breadcrumbs.html template (Sage Abdullah)keyboard icon to admin icon set (Rohit Sharma)SwapController (LB (Ben) Johnston)w-block/BlockController) to instantiate StreamField blocks (Karthik Ayangar)w-kbd/KeyboardController) (Neeraj Yetheendran)xregexp (IE11 polyfill) along with window.XRegExp global util (LB (Ben) Johnston)urlify to use TypeScript, officially deprecate window.URLify global util (LB (Ben) Johnston)May 1, 2024
---
local:
depth: 1
---
Continuing work on the Universal Listings project, this release rolls out universal listing styles for the following views:
Universal listing components like header buttons have also been tweaked to improve usability, and the PageListingViewSet now includes ChooseParentView to allow creating pages from custom page listings.
Thank you to everyone who worked on these features: Ben Enright, Sage Abdullah, Rohit Sharma, Storm Heg, Temidayo Azeez, and Abdelrahman Hamada.
Wagtail now provides a way for CMS users to control the information density of the admin interface, via their user profile preferences. The new setting allows switching between the "default" density and a new "snug" mode, which reduces the spacing and size of UI elements.
It’s also possible for site implementers to customize this for the needs of their project – see .
This feature was developed by Ben Enright and Thibaud Colas.
A new viewset class PageListingViewSet has been introduced, allowing developers to create custom page listings for specific page types similar to those previously provided by the Modeladmin package - see . This feature was developed by Matt Westcott.
A new dialog is available from the help menu, providing an overview of keyboard shortcuts available in the Wagtail admin. This feature was developed by Karthik Ayangar and Rohit Sharma.
Wagtail now includes extra guidance in its private pages and private collections (documents) forms, to warn users about the pitfalls of the "shared password" option. For projects with higher security requirements, it's now possible to disable the shared password option entirely. Thank you to Rohit Sharma, Salvo Polizzi, and Jake Howard for implementing those changes.
For sites managing favicons via the CMS, Wagtail now supports .ico favicon generation, with format-ico:
<link rel="icon" href="{% image favicon_image format-ico %}" />
This feature was developed by Jake Howard.
wagtail.contrib.settings or ModelViewSetThis release addresses a permission vulnerability in the Wagtail admin interface. If a model has been made available for editing through the wagtail.contrib.settings module or ModelViewSet, and the permission argument on FieldPanel has been used to further restrict access to one or more fields of the model, a user with edit permission over the model but not the specific field can craft an HTTP POST request that bypasses the permission check on the individual field, allowing them to update its value.
The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin, or by a user who has not been granted edit access to the model in question. The editing interfaces for pages and snippets are also unaffected.
Many thanks to Ben Morse and Joshua Munn for reporting this issue, and Jake Howard and Sage Abdullah for the fix. For further details, please see the CVE-2024-32882 security advisory.
RelatedObjectsColumn to the table UI framework (Matt Westcott)WAGTAIL_DATE_FORMAT, WAGTAIL_DATETIME_FORMAT, WAGTAIL_TIME_FORMAT are correctly configured (Rohit Sharma, Coen van der Kamp)AbstractGroupApprovalTask to simplify customizing behavior of custom Task models (John-Scott Atlakson)djangorestframework to 3.15.1 (Sage Abdullah)IndexView.list_display (Abdelrahman Hamada)Page.route_for_request() to find the page route,
and Page.find_for_request() to find the page given a request object and a URL path, see . Results are cached on request._wagtail_route_for_request (Gordon Pendleton)STORAGES alias name for WAGTAILIMAGES_RENDITION_STORAGE (Alec Baron)PASSWORD_REQUIRED_TEMPLATE setting to WAGTAIL_PASSWORD_REQUIRED_TEMPLATE with deprecation of previous naming (Saksham Misra, LB (Ben) Johnston)DOCUMENT_PASSWORD_REQUIRED_TEMPLATE setting to WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE with deprecation of previous naming (Saksham Misra, LB (Ben) Johnston)get_parent (Nigel van Keulen)__str__ for MySQL search index (Jake Howard)date objects on human_readable_date template tag (Jhonatan Lopes)verbose_name in group edit view when listing custom permissions (Sage Abdullah, Neeraj Yetheendran, Omkar Jadhav)make livehtml (Sage Abdullah)LANGUAGE_CODE (Mark Niehues)UnsavedController checks for nested removal/additions of inputs so that the unsaved warning shows in more valid cases when editing a page (Karthik Ayangar)get_add_url() is always used to re-render the add button when the listing is refreshed in viewsets (Sage Abdullah)objects manager (Jhonatan Lopes)get_dummy_request's resulting host name when running tests with ALLOWED_HOSTS = ["*"] (David Buxton)timesince_last_update template tag (Matt Westcott)w-kbd-scope-value with support for global so that specific keyboard shortcuts (e.g. ctrl+s/cmd+s) trigger consistently even when focused on fields (Neeraj Yetheendran)WAGTAIL_ALLOW_UNICODE_SLUGS setting when auto-generating slugs (LB (Ben) Johnston)convert_mariadb_uuids management command to assist with upgrading to Django 5.0+ on MariaDB (Matt Westcott)--purge-only in wagtail_update_image_renditions management command section (Pranith Beeram)6.3.0 with a fix for the missing favicon (Sage Abdullah)wagtail_update_image_renditions management command on the using images page (LB (Ben) Johnston)html.parser rather than html5lib (Jake Howard)html.parser & remove html5lib dependency (Jake Howard)Button that only renders links (a element) to Link and remove unused prop & behaviors that was non-compliant for aria role usage (Advik Kabra)wagtail.models.AbstractWorkflow model to support future customizations around workflows (Hossein)classnames template tag to handle nested lists of strings, use template tag for admin body element (LB (Ben) Johnston)UploadedDocument and UploadedImage into new UploadedFile model for easier shared code usage (Advik Kabra, Karl Hobley)window.chooserUrls globals, removing the need for inline scripts (Elhussein Almasri)w-init (InitController) to support a detail value to be dispatched on events (Chiemezuo Akujobi)page_breadcrumbs tag to use shared breadcrumbs.html template (Sage Abdullah)keyboard icon to admin icon set (Rohit Sharma)SwapController (LB (Ben) Johnston)w-block/BlockController) to instantiate StreamField blocks (Karthik Ayangar)w-kbd/KeyboardController) (Neeraj Yetheendran)xregexp (IE11 polyfill) along with window.XRegExp global util (LB (Ben) Johnston)urlify to use TypeScript, officially deprecate window.URLify global util (LB (Ben) Johnston)SubmissionsListView classAs part of the Universal Listings project, the SubmissionsListView for listing form submissions in the wagtail.contrib.forms app has been refactored to become a subclass of wagtail.admin.views.generic.base.BaseListingView. As a result, the class has undergone a number of changes, including the following:
ordering attribute has been renamed to default_ordering.register_user_listing_buttons hook signature changedThe function signature for the register_user_listing_buttons hook was updated to accept a request_user argument instead of context. If you use this hook, make sure to update your function signature to match the new one. The old signature with context will continue to work for now, but the context only contains the request object. Support for the old signature will be removed in a future release.
PASSWORD_REQUIRED_TEMPLATE has changed to WAGTAIL_PASSWORD_REQUIRED_TEMPLATEThe setting PASSWORD_REQUIRED_TEMPLATE has been deprecated, it will continue to work until a future release but the new name for this same setting will be WAGTAIL_PASSWORD_REQUIRED_TEMPLATE to align with other settings naming conventions.
DOCUMENT_PASSWORD_REQUIRED_TEMPLATE has changed to WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATEThe setting DOCUMENT_PASSWORD_REQUIRED_TEMPLATE has been deprecated, it will continue to work until a future release but the new name for this same setting will be WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE to align with other settings naming conventions.
html5lib dependencyWagtail now uses html.parser for its rich text processing, and no longer depends on html5lib. If your project relies on html5lib, update rich text code to use Wagtail’s documented rich text APIs like rewrite handlers and format converters. Or update project dependencies to include html5lib.
user_listing_buttons template tagThe undocumented user_listing_buttons template tag has been deprecated and will be removed in a future release.
wagtailusers_groups:users URL patternThe undocumented wagtailusers_groups:users URL pattern has been deprecated and will be removed in a future release. If you are using reverse with this URL pattern name, you should update your code to use the wagtailusers_users:index URL pattern name and the group ID as the group query parameter. For example:
reverse("wagtailusers_groups:users", args=[group.id])
should be updated to:
reverse("wagtailusers_users:index") + f"?group={group.id}"
The corresponding wagtailusers_groups:users_results URL pattern has been removed as part of this change.
A redirect from the old URL pattern to the new one has been added to ensure that existing URLs continue to work. This redirect will be removed in a future release.
window.chooserUrls within Draftail choosersThe undocumented usage of the JavaScript window.chooserUrls within Draftail choosers will be removed in a future release.
The following chooserUrl object values will be impacted.
anchorLinkChooserdocumentChooseremailLinkChooserembedsChooserexternalLinkChooserimageChooserpageChooserOverriding these inner values on the global window.chooserUrls object will still override their usage in the Draftail choosers for now but this capability will be removed in a future release.
It's recommended that usage of this global is removed in any customizations or third party packages and instead a custom Draftail Entity be used instead. See example below.
# .../wagtail_hooks.py
@hooks.register("insert_editor_js")
def editor_js():
return format_html(
"""
<script>
window.chooserUrls.myCustomChooser = '{0}';
</script>
""",
reverse("myapp_chooser:choose"),
)
Remove the insert_editor_js hook usage and instead pass the data needed via the Entity's data.
# .../wagtail_hooks.py
from django.urls import reverse_lazy
@hooks.register("register_rich_text_features")
def register_my_custom_feature(features):
# features.register_link_type...
features.register_editor_plugin(
"draftail",
"custom-link",
draftail_features.EntityFeature(
{
"type": "CUSTOM_ITEM",
"icon": "doc-full-inverse",
"description": gettext_lazy("Item"),
"chooserUrls": {
# Important: `reverse_lazy` must be used unless the URL path is hard-coded
"myChooser": reverse_lazy("myapp_chooser:choose")
},
},
js=["..."],
),
)
chooserUrls valuesTo override existing chooser Entities' chooserUrls values, here is an example of an unsupported monkey patch can achieve a similar goal.
However, it's recommended that a custom Entity be created to be registered as a replacement feature for Draftail customizations as per the documentation.
# .../wagtail_hooks.py
from django.urls import reverse_lazy
from wagtail import hooks
@hooks.register("register_rich_text_features")
def override_embed_feature_url(features):
features.plugins_by_editor["draftail"]["embed"].data["chooserUrls"][
"embedsChooser"
] = reverse_lazy("my_embeds:chooser")
window.initBlockWidget to initialize a StreamField blockThe undocumented global function window.initBlockWidget has now been deprecated and will be removed in a future release.
Any complex customizations that have re-implemented parts of this functionality will need to be modified to adopt the new approach that uses Stimulus and avoids inline scripts.
The usage of this new approach is still unofficial and could change in the future, it's recommended that the documented BlockWidget and StreamField approaches be used instead.
However, for comparison, here is the old and new approach below.
Assuming we are using Django's format_html to prepare the HTML output with JSON.dumps strings for the block data values.
The old approach would call the window.initBlockWidget global function with an inline script as follows:
<div
id="{id}"
data-block="{block_json}"
data-value="{value_json}"
data-error="{error_json}"
></div>
<script>
initBlockWidget('{id}');
</script>
In the new approach, we no longer need to attach an inline script but instead use the Stimulus data attributes to attach the behavior with the w-block identifier as follows:
<div
id="{id}"
data-block
data-controller="w-block"
data-w-block-data-value="{block_json}"
data-w-block-arguments-value="[{value_json},{error_json}]"
></div>
The JavaScript base classes Widget and BoundWidget that provide client-side access to form widgets (see ) no longer use jQuery. The input property of BoundWidget (previously a jQuery collection) is now a native DOM element, and the element argument passed to the BoundWidget constructor (previously a jQuery collection) is now passed as a native DOM element if the HTML representation consists of a single element, and an iterable of elements (NodeList or array) otherwise. User code that extends these classes should be updated accordingly.
window.URLify deprecatedThe undocumented client-side global util window.URLify is now deprecated and will be removed in a future release.
If this was required for slug field behavior, it's recommended that the SlugInput widget be used instead. This will automatically convert values entered into a suitable slug in the browser while respecting the global configuration WAGTAIL_ALLOW_UNICODE_SLUGS.
from wagtail.admin.widgets.slug import SlugInput
# ... other imports
class MyPage(Page):
promote_panels = [
FieldPanel("slug", widget=SlugInput),
# ... other panels
]
If you require this for custom JavaScript functionality, it's recommended you either include your own implementation from the original Django URLify source. Alternatively, the slugify or parameterize (a Django URLify port) NPM packages might be suitable.
window.XRegExp polyfill removedThe legacy window.XRegExp global polyfill util has been removed and will throw an error if called.
Instead, any usage of this should be updated to the well supported browser native Regex implementation.
// old
const newStr = XRegExp.replace(originalStr, XRegExp('[ab+c]', 'g'), '')
// new (with RegExp)
const newStr = originalStr.replace(new RegExp('[ab+c]', 'g'), '')
// OR
const newStr = originalStr.replace(/[ab+c]/g, '')
Your coding agent can read these notes before it upgrades. Set up the MCP server →