# Wagtail 4.0 release notes

_August 31, 2022_

```{contents}
---
local:
depth: 1
---
```

## What's new

### Django 4.1 support

This release adds support for Django 4.1. When upgrading, please note that the `django-taggit` library also needs to be updated to 3.0.0 or above.

### Global settings models

The new `BaseGenericSetting` base model class allows defining a settings model that applies to all sites rather than just a single site.

See [the Settings documentation](/reference/contrib/settings) for more information. This feature was implemented by Kyle Bayliss.

### Image renditions can now be prefetched by filter

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.

### Page editor redesign

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 all widget styles across the admin UI, including basic form widgets, as well as choosers.
* Updating field styles across forms, with help text consistently under fields, error messages above, and comment buttons to the side.
* Making all sections of the page editing UI collapsible by default.
* New designs for StreamField and InlinePanel blocks, with better support for nested blocks.
* 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.

(rich_text_improvements_4)=

### Rich text improvements

As part of the page editor redesign project sponsored by Google, we have made several improvements to our rich text editor:

* Inline toolbar: The toolbar now shows inline, to avoid clashing with the page’s header.
* Command palette: Start a block with a slash ‘/’ to open the palette and change the text format.
* 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.
* Split and insert: rich text fields can now be split while inserting a new StreamField block of the desired type.

### Live preview panel

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.

### Admin color themes

In Wagtail 2.12, we introduced theming support for Wagtail’s primary brand color. This has now been extended to almost all of Wagtail’s color palette. View our [](custom_user_interface_colors) documentation for more information, an overview of Wagtail’s customizable color palette, and a live demo of the supported customizations. 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 color 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
* Ensure disabled buttons are distinguishable from active buttons in forced colors mode
* Ensure that the fields on login and password reset forms are visible in forced colors mode
* Missing an outline on dropdown content and malformed tooltip arrow in forced colors mode

### UX unification and consistency improvements

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.

* **Login and password reset**
  * Refreshed design for login and password reset pages to better suit a wider range of device sizes
  * Better accessibility and screen reader support for the sign-in form due to a more appropriate DOM structure and skip link improvements
  * Remove usage of inline script to focus on username field and instead use `autofocus`
  * Wagtail logo added with the ability to override this logo via [](custom_branding)
* **Breadcrumbs**
  * Add Breadcrumbs to the Wagtail pattern library
  * Enhance new breadcrumbs so they can be added to any header or container element
  * Adopt new breadcrumbs on the page explorer (listing) view and the page chooser modal, remove legacy breadcrumbs code for move page as no longer used
  * Rename `explorer_breadcrumb` template tag to `breadcrumbs` as it is now used in multiple locations
  * Remove legacy (non-next) breadcrumbs no longer used, remove `ModelAdmin` usage of breadcrumbs completely and adopt consistent 'back' link approach
* **Headers**
  * Update classes and styles for the shared header templates to align with UI guidelines
  * Ensure the shared header template is more reusable, add ability to include classes, extra content and other blocks
  * Switch all report workflow, redirects, form submissions, site settings views to use Wagtail’s reusable header component
  * Resolve issues throughout Wagtail where the sidebar toggle would overlap header content on small devices
* **Tabs**
  * Add Tabs to the Wagtail pattern library
  * Adopt new Tabs component in the workflow history report page, removing the bespoke implementation there
* **Dashboard (home) view**
  * Migrate the dashboard (home) view header to the shared header template and update designs
  * Refresh designs for Home (Dashboard) site summary panels, use theme spacing and colors
  * Add support for RTL layouts and better support for small devices
  * Add CSS support for more than three summary items if added via customizations
* **Page Listing view**
  * Adopt the slim header in page listing views, with buttons moved under the "Actions" dropdown
  * Add convenient access to the translate page button in the parent "more" button

### Previews, revisions and drafts for snippets

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:

* [](wagtailsnippets_making_snippets_previewable)
* [](wagtailsnippets_saving_revisions_of_snippets)
* [](wagtailsnippets_saving_draft_changes_of_snippets)

These features were developed by Sage Abdullah.

### Documentation improvements

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 colors 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 the organization of the settings reference page with logical grouping and better internal linking (Akash Kumar Sen)
 * Improve the accessibility of the documentation with higher contrast colors, consistent focus outline, better keyboard only navigation through the sidebar (LB (Ben) Johnston, Vince Salvino)
 * Better sidebar scrolling behavior, 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.

### Other features

 * Add clarity to confirmation when being asked to convert an external link to an internal one (Thijs Kramer)
 * Add `base_url_path` to `ModelAdmin` so that the default URL structure of app_label/model_name can be overridden (Vu Pham, Khanh Hoang)
 * Add `full_url` to the API output of `ImageRenditionField` (Paarth Agarwal)
 * Use `InlinePanel`'s label when available for field comparison label (Sandil Ranasinghe)
 * Drop support for Safari 13 by removing left/right positioning in favor of CSS logical properties (Thibaud Colas)
 * 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)
 * Make it possible to reuse and customize Wagtail’s fonts with CSS variables (LB (Ben) Johnston)
 * Add better handling and informative developer errors for cross linking URLS (e.g. success after add) in generic views `wagtail.admin.views.generic` (Matt Westcott)
 * Introduce `wagtail.admin.widgets.chooser.BaseChooser` to make it easier to build custom chooser inputs (Matt Westcott)
 * 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)
 * Migrate Image and Document choosers to new JavaScript chooser module (Matt Westcott)
 * Add ability to select multiple items at once within bulk actions selections when holding shift on subsequent clicks (Hitansh Shah)
 * 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)
 * Implement redesign of the Workflow Status dialog, fixing accessibility issues (Steven Steinwand)
 * Add the ability to change the number of images displayed per page in the image library (Tidiane Dia, with sponsorship from YouGov)
 * Allow users to sort by different fields in the image library (Tidiane Dia, with sponsorship from YouGov)
 * Add `prefetch_renditions` method to `ImageQueryset` for performance optimization on image listings (Tidiane Dia, Karl Hobley)
 * Add ability to define a custom `get_field_clean_name` method when defining `FormField` models that extend `AbstractFormField` (LB (Ben) Johnston)
 * Migrate Home (Dashboard) view to use generic Wagtail class based view (LB (Ben) Johnston)
 * Combine most of Wagtail’s stylesheets into the global `core.css` file (Thibaud Colas)
 * Update `ReportView` to extend from generic `wagtail.admin.views.generic.models.IndexView` (Sage Abdullah)
 * Update pages `Unpublish` view to extend from generic `wagtail.admin.views.generic.models.UnpublishView` (Sage Abdullah)
 * Introduce a `wagtail.admin.viewsets.chooser.ChooserViewSet` module to serve as a common base implementation for chooser modals (Matt Westcott)
 * Add documentation for `wagtail.admin.viewsets.model.ModelViewSet` (Matt Westcott)
 * Added [multi-site support](api_filtering_pages_by_site) to the API (Sævar Öfjörð Magnússon)
 * Add `add_to_admin_menu` option for `ModelAdmin` (Oliver Parker)
 * Implement [Fuzzy matching](fuzzy_matching) for Elasticsearch (Nick Smith)
 * Cache model permission codenames in `PermissionHelper` (Tidiane Dia)
 * Selecting a new parent page for moving a page now uses the chooser modal which allows searching (Viggo de Vries)
 * Add clarity to the search indexing documentation for how `boost` works when using Postgres with the database search backend (Tibor Leupold)
 * Updated `django-filter` version to support 22 (Yuekui)
 * Use `.iterator()` in a few more places in the admin, to make it more stable on sites with many pages (Andy Babic)
 * Migrate some simple React component files to TypeScript (LB (Ben) Johnston)
 * 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)
 * Replace human-readable-date hover pattern with accessible tooltip variant across all of admin (Bernd de Ridder)
 * Added `WAGTAILADMIN_USER_PASSWORD_RESET_FORM` setting for overriding the admin password reset form (Michael Karamuth)
 * Prefetch workflow states in edit page view to avoid queries in other parts of the view/templates that need it (Tidiane Dia)
 * Remove the edit link from edit bird in previews to avoid confusion (Sævar Öfjörð Magnússon)
 * Introduce new template fragment and block level enclosure tags for easier template composition (Thibaud Colas)
 * Add a `classnames` template tag to easily build up classes from variables provided to a template (Paarth Agarwal)
 * Clean up multiple eslint rules usage and configs to align better with the Wagtail coding guidelines (LB (Ben Johnston))
 * Make `ModelAdmin` `InspectView` footer actions consistent with other parts of the UI (Thibaud Colas)
 * Add support for Twitter and other text-only embeds in Draftail embed previews (Iman Syed, Paarth Agarwal)
 * Use new modal dialog component for privacy settings modal (Sage Abdullah)
 * 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)
 * Add HTML-aware max_length validation and character count on RichTextField and RichTextBlock (Matt Westcott, Thibaud Colas)
 * Remove `is_parent` kwarg in various page button hooks as this approach is no longer required (Paarth Agarwal)
 * 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)
 * Allow generic chooser viewsets to support non-model data such as an API endpoint (Matt Westcott)
 * 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 customizations (Matt Westcott)
 * Introduce new template fragment and block level enclosure tags for easier template composition (Thibaud Colas)
 * Implement the new chooser widget styles as part of the page editor redesign (Thibaud Colas)
 * Update base Draftail/TextField form designs as part of the page editor redesign (Thibaud Colas)
 * Move commenting trigger to inline toolbar and move block splitting to the block toolbar and command palette only in Draftail (Thibaud Colas)
 * Pages are now locked when they are scheduled for publishing (Karl Hobley)
 * Simplify page chooser views by converting to class-based views (Matt Westcott)
 * Add "Translate" button within pages’ Actions dropdown when editing pages (Sage Abdullah)
 * Add translated labels to the bulk actions tags and collections bulk update fields (Stefan Hammer)
 * Add support for bulk actions, including [](wagtailsnippets_custom_bulk_actions) (Shohan Dutta Roy)

### Bug fixes

 * Fix issue where `ModelAdmin` index listings with export list enabled would show buttons with an incorrect layout (Josh Woodcock)
 * Fix typo in `ResumeWorkflowActionFormatter` message (Stefan Hammer)
 * Throw a meaningful error when saving an image to an unrecognized image format (Christian Franke)
 * Remove extra padding for headers with breadcrumbs on mobile viewport (Steven Steinwand)
 * Replace `PageRevision` with generic `Revision` model (Sage Abdullah)
 * Ensure that custom document or image models support custom tag models (Matt Westcott)
 * Ensure comments use translated values for their placeholder text (Stefan Hammer)
 * Ensure the upgrade notification, shown to admins on the dashboard if Wagtail is out of date, content is translatable (LB (Ben) Johnston)
 * Only show the re-ordering option to users that have permission to publish pages within the page listing (Stefan Hammer)
 * Ensure default sidebar branding (bird logo) is not cropped in RTL mode (Steven Steinwand)
 * Add an accessible label to the image focal point input when editing images (Lucie Le Frapper)
 * Remove unused header search JavaScript on the redirects import page (LB (Ben) Johnston)
 * Ensure non-square avatar images will correctly show throughout the admin (LB (Ben) Johnston)
 * Ignore translations in test files and re-include some translations that were accidentally ignored (Stefan Hammer)
 * Show alternative message when no page types are available to be created (Jaspreet Singh)
 * Prevent error on sending notifications for the legacy moderation process when no user was specified (Yves Serrano)
 * 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 behavior 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)
 * Ensure that `DecimalBlock` preserves the `Decimal` type when retrieving from the database (Yves Serrano)
 * When no snippets are added, ensure the snippet chooser modal has the correct URL for creating a new snippet (Matt Westcott)
 * `ngettext` in Wagtail's internal JavaScript internationalisation utilities now works (LB (Ben) Johnston)
 * Ensure the linting/formatting npm scripts work on Windows (Anuja Verma)
 * Fix display of dates in exported xlsx files on macOS Preview and Numbers (Jaap Roes)
 * Remove outdated reference to 30-character limit on usernames in help text (minusf)
 * Resolve multiple form submissions index listing page layout issues including title not being visible on mobile and interaction with large tables (Paarth Agarwal)
 * Ensure `ModelAdmin` single selection lists show correctly with Django 4.0 form template changes (Coen van der Kamp)
 * Ensure icons within help blocks have accessible contrasting colors, and links have a darker color plus underline to indicate they are links (Paarth Agarwal)
 * Ensure consistent sidebar icon position whether expanded or collapsed (Scott Cranfill)
 * Avoid redirects import error if the file had lots of columns (Jaap Roes)
 * Resolve accessibility and styling issues with the expanding status panel (Sage Abdullah)
 * Avoid 503 `AttributeError` when an empty search param `q=` is combined with other filters in the Images index view (Paritosh Kabra)
 * Fix error with string representation of FormSubmission not returning a string (LB (Ben) Johnston)
 * Ensure that bulk actions correctly support models with non-integer primary keys (id) (LB (Ben) Johnston)
 * Make it possible to toggle collapsible panels in the edit UI with the keyboard (Thibaud Colas)
 * Re-implement checkbox styles so the checked state is visible in forced colors mode (Thibaud Colas)
 * Re-implement switch component styles so the checked state is visible in forced colors mode (Thibaud Colas)
 * Always render select widgets consistently regardless of where they are in the admin (Thibaud Colas)
 * Make sure input labels and always take up the available space (Thibaud Colas)
 * Correctly style BooleanBlock within StructBlock (Thibaud Colas)
 * Make sure comment icons can’t overlap with help text (Thibaud Colas)
 * Make it possible to scroll input fields in admin on safari mobile (Thibaud Colas)
 * Stop rich text fields from overlapping with sidebar (Thibaud Colas)
 * Prevent comment buttons from overlapping with fields (Thibaud Colas)
 * Resolve MySQL search compatibility issue with Django 4.1 (Andy Chosak)
 * Resolve layout issues with reports (including form submissions listings) on md device widths (Akash Kumar Sen, LB (Ben) Johnston)
 * Resolve Layout issue with page explorer's inner header item on small device widths (Akash Kumar Sen)
 * Ensure that `BaseSiteSetting` / `BaseGenericSetting` objects can be pickled (Andy Babic)
 * Ensure `DocumentChooserBlock` can be deconstructed for migrations (Matt Westcott)
 * Resolve frontend console error and unintended console logging issues (Matt Westcott, Paarth Agarwal)
 * Resolve issue with sites that have not yet migrated away from `BaseSetting` when upgrading to Wagtail 4.0 (Stefan Hammer)
 * Use correct classnames for showing/hiding edit button on chooser widget (Matt Westcott)
 * Render MultiFieldPanel’s heading even when nested (Thibaud Colas)
 * Make sure select widgets render correctly regardless of the Django field and widget type (Thibaud Colas)
 * Consistently display boolean field labels above the widget so they render correctly (Thibaud Colas)
 * Address form field label alignment issues by always displaying labels above the widget (Thibaud Colas)
 * Make sure rich text URL editing tooltip is fully visible when displayed inside InlinePanel blocks (Thibaud Colas)
 * Allow input fields to scroll horizontally in Safari iOS (Thibaud Colas)
 * Ensure screen readers are made aware of page level messages added dynamically to the top of the page (Paarth Agarwal)
 * Fix `updatemodulepaths` command for Python 3.7 (Matt Westcott)
 * Only show locale filter in choosers when i18n is enabled in settings (Matt Westcott)
 * Ensure that the live preview panel correctly clears the cache when a new page is created (Sage Abdullah)
 * Ensure that there is a larger hoverable area for add block (+) within the Draftail editor (Steven Steinwand)
 * 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)
 * Fix issue where comments could not be added in StreamField that were already saved (Jacob Topp-Mugglestone)
 * Remove outdated reference to Image.LoaderError (Matt Westcott)


## Upgrade considerations

### 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.

### Opening links within the live preview panel

The live preview panel utilizes 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 %}
    <base target="_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.

### Dropped support for Safari 13

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.

### `PageRevision` replaced with `Revision`

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:

```python
from django.db import models
from wagtail import VERSION as WAGTAIL_VERSION


def get_revision_model():
    if WAGTAIL_VERSION >= (4, 0):
        return "wagtailcore.Revision"
    return "wagtailcore.PageRevision"


class MyModel(models.Model):
    # Before
    # revision = models.ForeignKey("wagtailcore.PageRevision")
    revision = models.ForeignKey(get_revision_model(), on_delete=models.CASCADE)
```

### `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`.

### `AdminChooser` replaced with `BaseChooser`

Custom choosers should no longer use `wagtail.admin.widgets.chooser.AdminChooser` which has been replaced with `wagtail.admin.widgets.chooser.BaseChooser`.

### `get_snippet_edit_handler` moved to `wagtail.admin.panels.get_edit_handler`

The `get_snippet_edit_handler` function in `wagtail.snippets.views.snippets` has been moved to `get_edit_handler` in `wagtail.admin.panels`.

### `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.

### Chooser widget JavaScript initializers replaced with classes

The internal JavaScript functions `createPageChooser`, `createSnippetChooser`, `createDocumentChooser` and `createImageChooser` used for initializing chooser widgets have been replaced by classes, and user code that calls them needs to be updated accordingly:

* `createPageChooser(id)` should be replaced with `new PageChooser(id)`
* `createSnippetChooser(id)` should be replaced with `new SnippetChooser(id)`
* `createDocumentChooser(id)` should be replaced with `new DocumentChooser(id)`
* `createImageChooser(id)` should be replaced with `new ImageChooser(id)`

### URL route names for image, document and snippet apps have changed

If your code contains references to URL route names within the `wagtailimages`, `wagtaildocs` or `wagtailsnippets` namespaces, these should be updated as follows:

* `wagtailimages:chooser` is now `wagtailimages_chooser:choose`
* `wagtailimages:chooser_results` is now `wagtailimages_chooser:choose_results`
* `wagtailimages:image_chosen` is now `wagtailimages_chooser:chosen`
* `wagtailimages:chooser_upload` is now `wagtailimages_chooser:create`
* `wagtailimages:chooser_select_format` is now `wagtailimages_chooser:select_format`
* `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.

### Auto-updating preview

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.

### Slim header on page listings

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.

Customizing 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.

### `is_parent` removed from page button hooks

* 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.

### Changed CSS variables for admin color themes

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 customizable with `--w-color-primary`, and the teal is customizable as `--w-color-secondary`. See [](custom_user_interface_colors) for an overview of all customizable colors. Here are replaced variables:

-   `--color-primary` is now `--w-color-secondary`
-   `--color-primary-hue` is now `--w-color-secondary-hue`
-   `--color-primary-saturation` is now `--w-color-secondary-saturation`
-   `--color-primary-lightness` is now `--w-color-secondary-lightness`
-   `--color-primary-darker` is now `--w-color-secondary-400`
-   `--color-primary-darker-hue` is now `--w-color-secondary-400-hue`
-   `--color-primary-darker-saturation` is now `--w-color-secondary-400-saturation`
-   `--color-primary-darker-lightness` is now `--w-color-secondary-400-lightness`
-   `--color-primary-dark` is now `--w-color-secondary-600`
-   `--color-primary-dark-hue` is now `--w-color-secondary-600-hue`
-   `--color-primary-dark-saturation` is now `--w-color-secondary-600-saturation`
-   `--color-primary-dark-lightness` is now `--w-color-secondary-600-lightness`
-   `--color-primary-lighter` is now `--w-color-secondary-100`
-   `--color-primary-lighter-hue` is now `--w-color-secondary-100-hue`
-   `--color-primary-lighter-saturation` is now `--w-color-secondary-100-saturation`
-   `--color-primary-lighter-lightness` is now `--w-color-secondary-100-lightness`
-   `--color-primary-light` is now `--w-color-secondary-50`
-   `--color-primary-light-hue` is now `--w-color-secondary-50-hue`
-   `--color-primary-light-saturation` is now `--w-color-secondary-50-saturation`
-   `--color-primary-light-lightness` is now `--w-color-secondary-50-lightness`

We’ve additionally removed all `--color-input-focus` and `--color-input-focus-border` variables, as Wagtail’s form fields no longer have a different color 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.

### Panel customizations

As part of the page editor redesign, we have removed support for the `classname="full"` customization to panels. Existing `title` and `collapsed` customizations 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 {func}`django.urls.path` function.
-   `RoutablePageMixin`'s `route` decorator will now redirect to a new `re_path` decorator that emulates the behavior of {func}`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):
    facebook = models.URLField()
```
