When using a queryset to render a list of images, you can now use the `prefetch_renditions()` queryset method to prefetch the renditions needed for rendering with a single extra query, similar to `prefetch_related`. If you have many renditions per image, you can also call it with filters as arguments - `prefetch_renditions("fill-700x586", "min-600x400")` - to fetch only the renditions you intend on using for a smaller query. For long lists of images, this can provide a significant boost to performance. See [](prefetching_image_renditions) for more examples. This feature was developed by Tidiane Dia and Karl Hobley.
Following from Wagtail 3.0, this release contains significant UI changes that affect all of Wagtail's admin, largely driven by the implementation of the new Page Editor. These include:
* Updating the side panels to prevent overlap with form fields unless necessary.
Further updates to the page editor are expected in the next release. Those changes were implemented by Thibaud Colas. Development on this feature was sponsored by Google.
* Character count: The character count is displayed underneath the editor, live-updating as you type. This counts the length of the text, not of any formatting.
* Paste to auto-create links: To add a link from your copy-paste clipboard, select text and paste the URL.
* Text shortcuts undo: The editor normally converts text starting with `1. ` to a list item. It’s now possible to un-do this change and keep the text as-is. This works for all Markdown-style shortcuts.
* RTL support: The editor’s UI now displays correctly in right-to-left languages.
* Focus-aware placeholder: The editor’s placeholder text will now follow the user’s focus, to make it easier to understand where to type in long fields.
* Empty heading highlight: The editor now highlights empty headings and list items by showing their type (“Heading 3”) as a placeholder, so content is less likely to be published with empty headings.
Wagtail’s page preview is now available in a side panel within the page editor. This preview auto-updates as users type, and can display the page in three different viewports: mobile, tablet, desktop. The existing preview functionality is still present, moved inside the preview panel rather than at the bottom of the page editor. The auto-update delay can be configured with the `WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL` setting. This feature was developed by Sage Abdullah.
In Wagtail 2.12, we introduced theming support for Wagtail’s primary brand colour. This has now been extended to almost all of Wagtail’s colour palette. View our [](custom_user_interface_colours) documentation for more information, an overview of Wagtail’s customisable colour palette, and a live demo of the supported customisations. This was implemented by Thibaud Colas, under the page editor redesign project sponsored by Google.
### Windows High Contrast mode support improvements
In Wagtail 2.16, we introduced support for Windows High Contrast mode (WHCM). This release sees a lot of improvements to our support, thanks to our new contributor Anuja Verma, who has been working on this as part of the [Contrast Themes](https://github.com/wagtail/wagtail/discussions/8193) Google Summer of Code project, with support from Jane Hughes, Scott Cranfill, and Thibaud Colas.
* Improve help block styles with less reliance on communication via colour alone in forced colors mode
* Add a bottom border to top messages so they stand out from the header in forced colors mode
* Make progress bars’ progress visible in forced colors mode
* Make checkboxes visible in forced colors mode
* Display the correct color for icons in forced colors mode
* Add a border around modal dialogs so they can be identified in forced colors mode
In Wagtail 3.0, a new Page Editor experience was introduced, this release brings many of the UX and UI improvements to other parts of Wagtail for a more consistent experience.
The bulk of these enhancements have been from Paarth Agarwal, who has been doing the [UX Unification](https://github.com/wagtail/wagtail/discussions/8158) internship project alongside other Google Summer of Code participants. This internship has been sponsored by Torchbox with mentoring support from LB (Ben Johnston), Thibaud Colas and Helen Chapman.
Snippets can now be given a previewable HTML representation, revision history, and draft / live states through the use of the mixins `PreviewableMixin`, `RevisionMixin`, and `DraftStateMixin`. For more details, see:
The documentation now has dark mode which will be turned on by default if set in your browser or OS preferences, it can also be toggled on and off manually. The colours and fonts of the documentation now align with the design updates introduced in Wagtail 3.0. These features were developed by Vince Salvino.
There are also many improvements to the documentation both under the hood and in the layout;
* Convert the rest of the documentation to Markdown, in place of RST, which will make it much easier for others to contribute to better documentation (Khanh Hoang, Vu Pham, Daniel Kirkham, LB (Ben) Johnston, Thiago Costa de Souza, Benedict Faw, Noble Mittal, Sævar Öfjörð Magnússon, Sandeep M A, Stefano Silvestri)
* Replace latin abbreviations (i.e. / e.g.) with common English phrases so that documentation is easier to understand (Dominik Lech)
* Improve organisation of the settings reference page with logical grouping and better internal linking (Akash Kumar Sen)
* Improve the accessibility of the documentation with higher contrast colours, consistent focus outline, better keyboard only navigation through the sidebar (LB (Ben) Johnston, Vince Salvino)
* Better sidebar scrolling behaviour, it is now sticky on larger devices and scrollable on its own (Paarth Agarwal, LB (Ben) Johnston)
* Fix links showing incorrectly in Safari (Tibor Leupold)
* See other features below for new feature specific documentation added.
* Use `FormData` instead of jQuery's `form.serialize` when editing documents or images just added so that additional fields can be better supported (Stefan Hammer)
* Add informational Codecov status checks for GitHub CI pipelines (Tom Hu)
* Introduce JavaScript chooser module, including a SearchController class which encapsulates the standard pattern of re-rendering the results panel in response to search queries and pagination (Matt Westcott)
* Upgrade notification, shown to admins on the dashboard if Wagtail is out of date, will now link to the release notes for the closest minor branch instead of the latest patch (Tibor Leupold)
* Upgrade notification can now be configured to only show updates when there is a new LTS available via `WAGTAIL_ENABLE_UPDATE_CHECK = 'lts'` (Tibor Leupold)
* Deprecate the usage and documentation of the `wagtail.contrib.modeladmin.menus.SubMenu` class, provide a warning if used directing developers to use `wagtail.admin.menu.Menu` instead (Matt Westcott)
* Add `menu_item_name` to modify `MenuItem`'s name for `ModelAdmin` (Alexander Rogovskyy, Vu Pham)
* Add an extra confirmation prompt when deleting pages with a large number of child pages, see [](wagtailadmin_unsafe_page_deletion_limit) (Jaspreet Singh)
* Add shortcut for accessing StreamField blocks by block name with new [`blocks_by_name` and `first_block_by_name` methods on `StreamValue`](streamfield_retrieving_blocks_by_name) (Tidiane Dia, Matt Westcott)
* Improve security of redirect imports by adding a file hash (signature) check for so that any tampering of file contents between requests will throw a `BadSignature` error (Jaap Roes)
* Added `path` and `re_path` decorators to the `RoutablePageMixin` module which emulate their Django URL utils equivalent, redirect `re_path` to the original `route` decorator (Tidiane Dia)
*`BaseChooser` widget now provides a Telepath adapter that's directly usable for any subclasses that use the chooser widget and modal JS as-is with no customisations (Matt Westcott)
* Ensure `aria-label` is not set on locale selection dropdown within page chooser modal as it was a duplicate of the button contents (LB (Ben Johnston))
* Revise the `ModelAdmin` title column behaviour to only link to 'edit' if the user has the correct permissions, fallback to the 'inspect' view or a non-clickable title if needed (Stefan Hammer)
* Resolve multiple form submissions index listing page layout issues including title not being visible on mobile and interaction with large tables (Paarth Agarwal)
* Ensure icons within help blocks have accessible contrasting colours, and links have a darker colour plus underline to indicate they are links (Paarth Agarwal)
* Resolve multiple header styling issues for modal, alignment on small devices, outside click handling target on medium devices, close button target size and hover styles (Paarth Agarwal)
### Changes to `Page.serve()` and `Page.serve_preview()` methods
As part of making previews available to non-page models, the `serve_preview()` method has been decoupled from the `serve()` method and extracted into the `PreviewableMixin` class. If you have overridden the `serve()` method in your page models, you will likely need to override `serve_preview()`, `get_preview_template()`, and/or `get_preview_context()` methods to handle previews accordingly. Alternatively, you can also override the `preview_modes` property to return an empty list to disable previews.
The live preview panel utilises an iframe to display the preview in the editor page, which requires the page in the iframe to have the `X-Frame-Options` header set to `SAMEORIGIN` (or unset). If you click a link within the preview panel, you may notice that the iframe stops working. This is because the link is loaded within the iframe and the linked page may have the `X-Frame-Options` header set to `DENY`. To work around this problem, add the following `<base>` tag within your `<head>` element in your `base.html` template, before any `<link>` elements:
```html+django
{% if request.in_preview_panel %}
<basetarget="_blank">
{% endif %}
```
This will make all links in the live preview panel open in a new tab.
As of Wagtail 4.0.1, new Wagtail projects created through the `wagtail start` command already include this change in the base template.
### `base_url_path` keyword argument added to AdminURLHelper
The `wagtail.contrib.modeladmin.helpers.AdminURLHelper` class now accepts a `base_url_path` keyword argument on its constructor. Custom subclasses of this class should be updated to accept this keyword argument.
Safari 13 will no longer be officially supported as of this release, this deviates the current support for the last 3 version of Safari by a few months and was required to add better support for RTL languages.
The `PageRevision` model has been replaced with a generic `Revision` model. If you use the `PageRevision` model in your code, make sure that:
* Creation of `PageRevision` objects should be updated to create `Revision` objects using the page's `id` as the `object_id`, the default `Page` model's content type as the `base_content_type`, and the page's specific content type as the `content_type`.
* Queries that use the `PageRevision.objects` manager should be updated to use the `Revision.page_revisions` manager.
*`Revision` queries that use `Page.id` should be updated to cast the `Page.id` to a string before using it in the query (e.g. by using `str()` or `Cast("page_id", output_field=CharField())`).
*`Page` queries that use `PageRevision.page_id` should be updated to cast the `Revision.object_id` to an integer before using it in the query (e.g. by using `int()` or `Cast("object_id", output_field=IntegerField())`).
* Access to `PageRevision.page` should be updated to `Revision.content_object`.
If you maintain a package across multiple Wagtail versions that includes a model with a `ForeignKey` to the `PageRevision` model, you can create a helper function to correctly resolve the model depending on the installed Wagtail version, for example:
### `Page.get_latest_revision_as_page` renamed to `Page.get_latest_revision_as_object`
The `Page.get_latest_revision_as_page` method has been renamed to `Page.get_latest_revision_as_object`. The old name still exists for backwards-compatibility, but calling it will raise a `RemovedInWagtail50Warning`.
Custom choosers should no longer use `wagtail.admin.widgets.chooser.AdminChooser` which has been replaced with `wagtail.admin.widgets.chooser.BaseChooser`.
### `explorer_breadcrumb` template tag has been renamed to `breadcrumbs`, `move_breadcrumb` has been removed
The `explorer_breadcrumb` template tag is not documented, however if used it will need to be renamed to `breadcrumbs` and the `url_name` is now a required arg.
The `move_breadcrumb` template tag is no longer used and has been removed.
### `wagtail.contrib.modeladmin.menus.SubMenu` is deprecated
The `wagtail.contrib.modeladmin.menus.SubMenu` class should no longer be used for constructing submenus of the admin sidebar menu. Instead, import `wagtail.admin.menu.Menu` and pass the list of menu items as the `items` keyword argument.
The internal JavaScript functions `createPageChooser`, `createSnippetChooser`, `createDocumentChooser` and `createImageChooser` used for initialising chooser widgets have been replaced by classes, and user code that calls them needs to be updated accordingly:
If your code contains references to URL route names within the `wagtailimages`, `wagtaildocs` or `wagtailsnippets` namespaces, these should be updated as follows:
*`wagtaildocs:chooser` is now `wagtaildocs_chooser:choose`
*`wagtaildocs:chooser_results` is now `wagtaildocs_chooser:choose_results`
*`wagtaildocs:document_chosen` is now `wagtaildocs_chooser:chosen`
*`wagtaildocs:chooser_upload` is now `wagtaildocs_chooser:create`
*`wagtailsnippets:list`, `wagtailsnippets:list_results`, `wagtailsnippets:add`, `wagtailsnippets:edit`, `wagtailsnippets:delete-multiple`, `wagtailsnippets:delete`, `wagtailsnippets:usage`, `wagtailsnippets:history`: These now exist in a separate `wagtailsnippets_{app_label}_{model_name}` namespace for each snippet model, and no longer take `app_label` and `model_name` as arguments.
*`wagtailsnippets:choose`, `wagtailsnippets:choose_results`, `wagtailsnippets:chosen`: These now exist in a separate `wagtailsnippetchoosers_{app_label}_{model_name}` namespace for each snippet model, and no longer take `app_label` and `model_name` as arguments.
As part of the introduction of the new live preview panel, we have changed the `WAGTAIL_AUTO_UPDATE_PREVIEW` setting to be on (`True`) by default. This can still be turned off by setting it to `False`. The `WAGTAIL_AUTO_UPDATE_PREVIEW_INTERVAL` setting has been introduced for sites willing to reduce the performance cost of the live preview without turning it off completely.
The page explorer listings now use Wagtail’s new slim header, replacing the previous large teal header. The parent page’s metadata and related actions are now available within the “Info” side panel, while the majority of buttons are now available under the Actions dropdown in the header, identically to the page create/edit forms.
Customising which actions are available and adding extra actions is still possible, but has to be done with the [`register_page_header_buttons`](register_page_header_buttons) hook, rather than [`register_page_listing_buttons`](register_page_listing_buttons) and [`register_page_listing_more_buttons`](register_page_listing_more_buttons). Those hooks still work as-is to define actions for each page within the listings.
* The following hooks `construct_page_listing_buttons`, `register_page_listing_buttons`, `register_page_listing_more_buttons` no longer accept the `is_parent` keyword argument and this should be removed.
*`is_parent` was the previous approach for determining whether the buttons would show in the listing rows or the page's more button, this can be now achieved with discrete hooks instead.
As part of our support for theming across all colors, we’ve had to rename or remove some of the pre-existing CSS variables. Wagtail’s indigo is now customisable with `--w-color-primary`, and the teal is customisable as `--w-color-secondary`. See [](custom_user_interface_colours) for an overview of all customisable colours. Here are replaced variables:
We’ve additionally removed all `--color-input-focus` and `--color-input-focus-border` variables, as Wagtail’s form fields no longer have a different colour on focus.
### `WAGTAILDOCS_DOCUMENT_FORM_BASE` and `WAGTAILIMAGES_IMAGE_FORM_BASE` must inherit from `BaseDocumentForm` / `BaseImageForm`
Previously, it was valid to specify an arbitrary model form as the `WAGTAILDOCS_DOCUMENT_FORM_BASE` / `WAGTAILIMAGES_IMAGE_FORM_BASE` settings. This is no longer supported; these forms must now inherit from `wagtail.documents.forms.BaseDocumentForm` and `wagtail.images.forms.BaseImageForm` respectively.
As part of the page editor redesign, we have removed support for the `classname="full"` customisation to panels. Existing `title` and `collapsed` customisations remain unchanged.
### Optional replacement for regex only `route` decorator for `RoutablePageMixin`
- This is an optional replacement, there are no immediate plans to remove the `route` decorator at this time.
- The `RoutablePageMixin` contrib module now provides a `path` decorator that behaves the same way as Django's [`django.urls.path`](https://docs.djangoproject.com/en/stable/ref/urls/#django.urls.path) function.
-`RoutablePageMixin`'s `route` decorator will now redirect to a new `re_path` decorator that emulates the behaviour of [`django.urls.re_path`](https://docs.djangoproject.com/en/stable/ref/urls/#django.urls.re_path).
### `BaseSetting` model replaced by `BaseSiteSetting`
The `wagtail.contrib.settings.models.BaseSetting` model has been replaced by two new base models `BaseSiteSetting` and `BaseGenericSetting`, to accommodate settings that are shared across all sites. Existing setting models that inherit `BaseSetting` should be updated to use `BaseSiteSetting` instead:
```python
from wagtail.contrib.settings.models import BaseSetting, register_setting
@register_setting
class SiteSpecificSocialMediaSettings(BaseSetting):
facebook = models.URLField()
```
should become
```python
from wagtail.contrib.settings.models import BaseSiteSetting, register_setting
@register_setting
class SiteSpecificSocialMediaSettings(BaseSiteSetting):