docs/releases/7.0.md
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.