# Wagtail 4.2 release notes

_February 6, 2023_

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

## What's new

### StreamField data migration helpers

Wagtail now provides a set of utilities for creating data migrations on StreamField data. For more information, see [StreamField data migrations](streamfield_data_migrations). This feature was developed by Sandil Ranasinghe, initially as the [wagtail-streamfield-migration-toolkit](https://github.com/wagtail/wagtail-streamfield-migration-toolkit) add-on package, as part of the Google Summer of Code 2022 initiative, with support from Jacob Topp-Mugglestone, Joshua Munn and Karl Hobley.

### Locking for snippets

Snippets can now be locked by users to prevent other users from editing, through the use of the `LockableMixin`. For more details, see [](wagtailsnippets_locking_snippets).

This feature was developed by Sage Abdullah.

### Workflows for snippets

Snippets can now be assigned to workflows through the use of the `WorkflowMixin`, allowing new changes to be submitted for moderation before they are published. For more details, see [](wagtailsnippets_enabling_workflows).

This feature was developed by Sage Abdullah.

### `fullpageurl` template tag

Wagtail now provides a `fullpageurl` template tag (for both Django templates and Jinja2) to output a page's full URL including the domain. For more details, see [](fullpageurl_tag).

This feature was developed by Jake Howard.

### CSP compatibility & Stimulus adoption

Wagtail now uses the Stimulus framework for client-side interactivity (see [RFC 78](https://github.com/wagtail/rfcs/pull/78)). Our [Outreachy contributor](https://wagtail.org/blog/our-very-first-outreachy-interns/) Loveth Omokaro has refactored significant portions of the admin interface:

* The Skip Link component displayed on all pages.
* The dashboard’s Upgrade notification message.
* Auto-submitting of listing filters.
* Loading of Wagtail’s icon sprite
* Page lock/unlock actions
* Workflow enable actions

Those changes improve the maintainability of the code, and help us move towards compatibility with strict CSP (Content Security Policy) rules. Thank you to Loveth and project mentors LB (Ben) Johnston, Thibaud Colas, and Paarth Agarwal.

### Accessibility checker integration

The CMS now includes an accessibility checker in the [user bar](wagtailuserbar_tag), to assist users in building more accessible websites and follow [ATAG 2.0 guidelines](https://www.w3.org/TR/ATAG20/). The checker, which is based on the Axe testing engine, is designed for content authors to identify and fix accessibility issues on their own. It scans the loaded page for errors and displays the results, with three rules turned on in this release. It’s configurable with the [`construct_wagtail_userbar`](construct_wagtail_userbar) hook.

This new feature was implemented by Albina Starykova as part of an [Outreachy internship](https://wagtail.org/blog/our-very-first-outreachy-interns/), with support from mentors Thibaud Colas, Sage Abdullah, and Joshua Munn.

### Rich text improvements

Following feedback from Wagtail users on [rich text UI improvements in Wagtail 4.0](rich_text_improvements_4), we have further refined the behavior of rich text fields to cater for different scenarios:

* Users can now choose between an “inline” floating toolbar, and a fixed toolbar at the top of the editor. Both toolbars display all formatting options.
* The ‘/’ command palette and block picker in rich text fields now contain all formatting options except text styles.
* The ‘/’ command palette and block picker are now always available no matter where the cursor is placed, to support inserting content at any point within text, transforming existing content, and splitting StreamField blocks in the middle of a paragraph when needed.
* The block picker interface now displays two columns so more options are visible without scrolling.

Thank you to all who provided feedback, participants to our usability testing sessions, and to Nick Lee and Thibaud Colas for the implementation.

### Multiple chooser panel

A new panel type [](multiple_chooser_panel) is available. This is a variant of `InlinePanel` which improves the editor experience when adding large numbers of linked item - rather than creating and populating each sub-form individually, a chooser modal is opened allowing multiple objects to be selected at once.

This feature was developed by Matt Westcott, and sponsored by [YouGov](https://yougov.com/).

### Other features

 * Test assertion [`WagtailPageTestCase.assertCanCreate`](testing_reference) now supports the kwarg `publish=True` to determine whether to publish the page (Harry Percival, Akua Dokua Asiedu, Matt Westcott)
 * Ensure that the `rebuild_references_index` command can run without console output if called with `--verbosity 0` (Omerzahid Ali, Aman Pandey)
 * Add full support for secondary buttons with icons in the Wagtail design system - `button bicolor button--icon button-secondary` including the `button-small` variant (Seremba Patrick)
 * Add [`purge_embeds`](purge_embeds) management command to delete all the cached embed objects in the database (Aman Pandey)
 * Make it possible to resize the page editor’s side panels (Sage Abdullah)
 * Add ability to include [`form_fields` as an APIField](form_page_fields_api_field) on `FormPage` (Sævar Öfjörð Magnússon, Suyash Singh, LB (Ben) Johnston)
 * Ensure that images listings are more consistently aligned when there are fewer images uploaded (Theresa Okoro)
 * Add more informative validation error messages for non-unique slugs within the admin interface and for programmatic page creation (Benjamin Bach)
 * Always show the page editor title field’s border when the field is empty (Thibaud Colas)
 * Snippet models extending `DraftStateMixin` now automatically define a "Publish" permission type (Sage Abdullah)
 * Users now remain on the edit page after saving a snippet as draft (Sage Abdullah)
 * Base project template now populates the meta description tag from the search description field (Aman Pandey)
 * Added support for `azure-mgmt-cdn` version >= 10 and `azure-mgmt-frontdoor` version >= 1 in the frontend cache invalidator (Sylvain Fankhauser)
 * Add a system check to warn when a `django-storages` backend is configured to allow overwriting (Rishabh jain)
 * Update admin focus outline color to have higher contrast against white backgrounds (Thibaud Colas)
 * Implement latest design for the admin dashboard header (Thibaud Colas, Steven Steinwand)
 * Restyle the userbar to follow the visual design of the Wagtail admin (Albina Starykova)
 * Adjust the size of panel labels on the "Account" form (Thibaud Colas)
 * Delay hiding the contents of the side panels when closing, so the animation is smoother (Thibaud Colas)
 * ListBlock now shows item-by-item differences when comparing versions (Tidiane Dia)
 * Switch StreamField blocks to use the same picker interface as within rich text fields (Thibaud Colas)

### Bug fixes

 * Make sure workflow timeline icons are visible in high-contrast mode (Loveth Omokaro)
 * Ensure authentication forms (login, password reset) have a visible border in Windows high-contrast mode (Loveth Omokaro)
 * Ensure visual consistency between buttons and links as buttons in Windows high-contrast mode (Albina Starykova)
 * Ensure `ChooserBlock.extract_references` uses the model class, not the model string (Alex Tomkins)
 * Incorrectly formatted link in the documentation for Wagtail community support (Bolarinwa Comfort Ajayi)
 * Ensure logo shows correctly on log in page in Windows high-contrast mode (Loveth Omokaro)
 * Comments notice background overflows its container (Yekasumah)
 * Ensure links within help blocks meet color contrast guidelines for accessibility (Theresa Okoro)
 * Ensure the skip link (used for keyboard control) meets color contrast guidelines for accessibility (Dauda Yusuf)
 * Ensure tag fields correctly show in both dark and light Windows high-contrast modes (Albina Starykova)
 * Ensure new tooltips & tooltip menus have visible borders and tip triangle in Windows high-contrast mode (Juliet Adeboye)
 * Ensure there is a visual difference of 'active/current link' vs normal links in Windows high-contrast mode (Mohammad Areeb)
 * Avoid issues where trailing whitespace could be accidentally removed in translations for new page & snippet headers (Florian Vogt)
 * Make sure minimap error indicators follow the minimap scrolling (Thibaud Colas)
 * Remove the ability to view or add comments to `InlinePanel` inner fields to avoid lost or incorrectly linked comments (Jacob Topp-Mugglestone)
 * Use consistent heading styles on top-level fields in the page editor (Sage Abdullah)
 * Allow button labels to wrap onto two lines in dropdown buttons (Coen van der Kamp)
 * Remove spurious horizontal resize handle from text areas (Matt Westcott)
 * Move DateField, DateTimeField, TimeField comment buttons to be right next to the fields (Theresa Okoro)
 * Support text resizing in workflow steps cards (Ivy Jeptoo)
 * Ignore images added via fixtures when using `WAGTAILIMAGES_FEATURE_DETECTION_ENABLED` to avoid errors for images that do not exist (Aman Pandey)
 * Restore ability to perform JSONField query operations against StreamField when running against the Django 4.2 development branch (Sage Abdullah)
 * Ensure there is correct grammar and pluralization for Tab error counts shown to screen readers (Aman Pandey)
 * Pass through expected expected `cc`, `bcc` and `reply_to` to the Django mail helper from `wagtail.admin.mail.send_mail` (Ben Gosney)
 * Allow reviewing or reverting to a Page's initial revision (Andy Chosak)
 * Use the correct padding for autocomplete block picker (Umar Farouk Yunusa)
 * Ensure that short content pages (such as editing snippets) do not show an inconsistent background (Sage Abdullah)
 * Fix horizontal positioning of rich text inline toolbar (Thibaud Colas)
 * Ensure that `DecimalBlock` correctly handles `None`, when `required=False`, values (Natarajan Balaji)
 * Close the userbar when clicking its toggle (Albina Starykova)
 * Add a border around the userbar menu in Windows high-contrast mode so it can be identified (Albina Starykova)
 * Make sure browser font resizing applies to the userbar (Albina Starykova)
 * Fix check for `delete_url_name` attribute in generic `DeleteView` (Alex Simpson)
 * Re-implement design system colors so HSL values exactly match the desired RGB (Albina Starykova)
 * Resolve issue where workflow and other notification emails would not include the correct tab URL for account notification management (LB (Ben) Johnston)
 * Use consistent spacing above and below page headers (Thibaud Colas)
 * Use the correct icon sizes and spacing in slim header (Thibaud Colas)
 * Use the correct color for placeholders in rich text fields (Thibaud Colas)
 * Prevent obstructing the outline around rich text fields (Thibaud Colas)
 * Page editor dropdowns now use indigo backgrounds like elsewhere in the admin interface (Thibaud Colas)
 * Allow parsing of multiple key/value pairs from string in `wagtail.search.utils.parse_query_string` (Beniamin Bucur)
 * Prevent memory exhaustion when purging a large number of revisions (Jake Howard)
 * Add right-to-left (RTL) support for the following form components: Switch, Minimap, live preview (Thibaud Colas)
 * Improve right-to-left (RTL) positioning for the following components: Page explorer, Sidebar sub-menu, rich text tooltips, rich text toolbar trigger, editor section headers (Thibaud Colas)
 * Center-align StreamField and rich text block picker buttons with the dotted guide line (Thibaud Colas)
 * Search bar in chooser modals now performs autocomplete searches under PostgreSQL (Matt Westcott)
 * Server-side document filenames are preserved when replacing a document file (Suyash Singh, Matt Westcott)
 * Do not show bulk actions checkbox in page type usage view (Sage Abdullah)
 * Prevent account name from overflowing the sidebar (Aman Pandey)
 * Ensure edit form is displayed as unlocked immediately after canceling a workflow (Sage Abdullah)
 * Prevent `latest_revision` pointer from being copied over when copying translatable snippets for translation (Sage Abdullah)

### Documentation

 * Wagtail's documentation (v2.9 to v4.0) has been updated on [Dash user contributions](https://github.com/Kapeli/Dash-User-Contributions) for [Dash](https://kapeli.com/dash) or [Zeal](https://zealdocs.org/) offline docs applications (Damilola Oladele, Mary Ayobami, Elizabeth Bassey)
 * Wagtail's documentation (v2 to v4.0) has been added to [DevDocs](https://devdocs.io/wagtail/) which has offline support and is easily accessible in any browser (Vallabh Tiwari)
 * Add custom permissions section to permissions documentation page (Dan Hayden)
 * Add documentation for how to get started with [contributing translations](contributing_translations) for the Wagtail admin (Ogunbanjo Oluwadamilare)
 * Officially recommend `fnm` over `nvm` in development documentation (LB (Ben) Johnston)
 * Mention the importance of passing `request` and `current_site` to `get_url` on the [performance](performance_overview) documentation page (Jake Howard)
 * Add documentation for [`register_user_listing_buttons`](register_user_listing_buttons) hook (LB (Ben Johnston))
 * Add development (contributing to Wagtail) documentation notes for [development on Windows](development_on_windows) (Akua Dokua Asiedu)
 * Mention Wagtail’s usage of Django’s default user model by default (Temidayo Azeez)
 * Add links to treebeard documentation for relevant methods (Temidayo Azeez)
 * Add clarification on where to register entity plugins (Mark McOsker)
 * Fix logo in README not being visible in high-contrast mode (Benita Anawonah)
 * Improve 'first wagtail site' tutorial (Akua Dokua Asiedu)
 * Grammatical adjustments of `page models` usage guide (Damilola Oladele)
 * Add class inheritance information to StreamField block sreference (Temidayo Azeez)
 * Document the hook [`register_image_operations`](register_image_operations) and add an example of a [custom Image filter](custom_image_filters) (Coen van der Kamp)
 * Fix incorrect example code for StreamField migration of `RichTextField` (Matt Westcott)
 * Document the policy needed to create invalidations in CloudFront (Jake Howard)
 * Document how to add permission restriction to a report view (Rishabh jain)
 * Add example for how to configure API `renderer_classes` (Aman Pandey)
 * Document potential data loss for BaseLogEntry migration in 3.0 (Sage Abdullah)
 * Add documentation for the reference index mechanism (Daniel Kirkham)

### Maintenance

 * Switch to using [Willow](https://github.com/wagtail/Willow/) instead of Pillow for images (Darrel O'Pry)
 * Remove unsquashed `testapp` migrations (Matt Westcott)
 * Upgrade to Node 18 for frontend build tooling (LB (Ben) Johnston)
 * Run Python tests with coverage and upload coverage data to codecov (Sage Abdullah)
 * Clean up duplicate JavaScript for the `escapeHtml` function (Jordan Rob)
 * Ensure that translation file generation ignores JavaScript unit tests and clean up unit tests for Django gettext utils (LB (Ben Johnston))
 * Migrated `initButtonSelects` from core.js to own TypesScript file and add unit tests (Loveth Omokaro)
 * Migrated `initSkipLink` util to TypeScript and add JSDoc & unit tests (Juliet Adeboye)
 * Clean up some unused utility classes and migrate `unlist` to Tailwind utility class `w-list-none` (Loveth Omokaro)
 * Clean up linting on legacy code and add shared util `hasOwn` in TypeScript (Loveth Omokaro)
 * Remove unnecessary box-sizing: border-box declarations in SCSS (Albina Starykova)
 * Migrated `initTooltips` to TypeScript add JSDoc and unit tests (Fatuma Abdullahi)
 * Migrated `initTagField` from core.js to own TypeScript file and add unit tests (Chisom Okeoma)
 * Added unit tests & JSDoc to `initDissmisibles` (Yekasumah)
 * Standardise on `classname` for passing HTML class attributes (LB (Ben Johnston))
 * Clean up expanding formset and `InlinePanel` JavaScript initialization code and adopt a class approach (Matt Westcott)
 * Extracted revision and draft state logic from generic views into mixins (Sage Abdullah)
 * Extracted generic lock / unlock views from page lock / unlock views (Sage Abdullah)
 * Move `identity` JavaScript util into shared utils folder (LB (Ben Johnston))
 * Remove unnecessary declaration of function to determine URL query params, instead use `URLSearchParams` (Loveth Omokaro)
 * Update `tsconfig` to better support modern TypeScript development and clean up some code quality issues via Eslint (Loveth Omokaro)
 * Switch userbar to initialize a Web Component to avoid styling clashes (Albina Starykova)
 * Refactor userbar stylesheets to use the same CSS loading as the rest of the admin (Albina Starykova)
 * Remove unused search-bar and button-filter styles (Thibaud Colas)
 * Use util method to construct dummy requests in tests (Jake Howard)
 * Remove unused dev-only react-axe integration (Thibaud Colas)
 * Split up `wagtail.admin.panels` into submodules, existing exports have been preserved (Matt Westcott)
 * Refactor userbar styles to use the same stylesheet as other components (Thibaud Colas)
 * Add deprecation warnings for `wagtail.core` and other imports deprecated in Wagtail 3.0 (Matt Westcott)
 * Upgraded Transifex configuration to v3 (Loic Teixeira)
 * Replace repeated HTML `avatar` component with a template tag include `{% avatar ... %}` throughout the admin interface (Aman Pandey)
 * Refactor accessibility checker userbar item (Albina Starykova)

## Upgrade considerations

### Wagtail-specific image field (`WagtailImageField`)

The `AbstractImage` and `AbstractRendition` models use a Wagtail-specific `WagtailImageField` which extends Django's `ImageField`
to use [Willow](https://github.com/wagtail/Willow/) for image file handling. This will generate a new migration if you
are using a [custom image model](custom_image_model).

### Comments within `InlinePanel` not supported

When the commenting system was introduced, support for `InlinePanel` fields was incorrectly added. This has led to issues
where comments can be lost on save, or in most cases will be added to the incorrect item within the `InlinePanel`. The ability
to add comments here has now been removed and as such any existing comments that were added will no longer show.

See https://github.com/wagtail/wagtail/issues/9685 for tracking of adding this back officially in the future.

### Adoption of `classname` convention for some template tags & includes

Some undocumented Wagtail admin template tags and includes have been refactored to adopt a more consistent naming of `classname`.

If these are used within packages or customizations they will need to be updated to the new variable naming convention.

| Name                | New (`classname`)                                                                                      | Old (various)                                                                                        |
| ------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
| `icon` (see note)   | `{% icon name='spinner' classname='...' %}`                                                            | `{% icon name='spinner class_name='...' %}`                                                          |
| `dialog_toggle`     | `{% dialog_toggle classname='...' %}`                                                                  | `{% dialog_toggle class_name='...' %}`                                                               |
| `paginate`          | `{% paginate pages classname="..." %}`                                                                 | `{% paginate pages classnames="..." %}`                                                              |
| `tab_nav_link`      | `{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with classname="..." %}`                      | `{% include 'wagtailadmin/shared/tabs/tab_nav_link.html' with classes="..." %}`                      |
| `side_panel_button` | `{% include 'wagtailadmin/shared/side_panels/includes/side_panel_button.html' with classname="..." %}` | `{% include 'wagtailadmin/shared/side_panels/includes/side_panel_button.html' with classes="..." %}` |

Note that the `icon` template tag will still support `class_name` with a deprecation warning. Support will be dropped in a future release.

### `InlinePanel` JavaScript function is now a class

The (internal, undocumented) `InlinePanel` JavaScript function, used to initialize client-side behavior for inline panels, has been converted to a class. Any user code that calls this function should now replace `InlinePanel(...)` calls with `new InlinePanel(...)`. Additionally, child form controls are now initialized automatically, and so it is no longer necessary to call `initChildControls`, `updateChildCount`, `updateMoveButtonDisabledStates` or `updateAddButtonState`.

Python code that uses the `InlinePanel` panel type is not affected by this change.

### `WAGTAILADMIN_GLOBAL_PAGE_EDIT_LOCK` setting is now `WAGTAILADMIN_GLOBAL_EDIT_LOCK`

The `WAGTAILADMIN_GLOBAL_PAGE_EDIT_LOCK` setting has been renamed to [`WAGTAILADMIN_GLOBAL_EDIT_LOCK`](wagtailadmin_global_edit_lock).

### Wagtail userbar as a web component

The [`wagtailuserbar`](wagtailuserbar_tag) template tag now initializes the userbar as a [Web Component](https://developer.mozilla.org/en-US/docs/Web/Web_Components), with a `wagtail-userbar` custom element using shadow DOM to apply styles without any collisions with the host page.

For any site customizing the position of the userbar, target the styles to `wagtail-userbar::part(userbar)` instead of `.wagtail-userbar`. For example:

```css
wagtail-userbar::part(userbar) {
    bottom: 30px;
}
```

### Configuration of the accessibility checker user bar item

Like other userbar items, the new accessibility checker is configurable with the [`construct_wagtail_userbar`](construct_wagtail_userbar) hook. For example, to remove the new item, use:

```python
from wagtail.admin.userbar import AccessibilityItem


@hooks.register('construct_wagtail_userbar')
def remove_userbar_accessibility_checks(request, items):
    items[:] = [item for item in items if not isinstance(item, AccessibilityItem)]
```

### Support for legacy versions of `azure-mgmt-cdn` and `azure-mgmt-frontdoor` packages will be dropped

If 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:

* For Azure CDN: upgrade `azure-mgmt-cdn` to version 10 or above
* For Azure Front Door: upgrade `azure-mgmt-frontdoor` to version 1 or above

Support for older versions will be dropped in a future release.

### Changes to `Workflow` and `Task` methods

To accommodate workflows support for snippets, the `page` parameter in {meth}`Workflow.start() <wagtail.models.Workflow.start>` has been renamed to `obj`.

In addition, some methods on the base {class}`~wagtail.models.Task` model have been changed. If you have {doc}`custom Task types </extending/custom_tasks>`, make sure to update the methods to reflect the following changes:

- `page_locked_for_user()` is now {meth}`~wagtail.models.Task.locked_for_user`. Using `page_locked_for_user()` is deprecated and will be removed in a future release.
- The `page` parameter in `user_can_access_editor()`, `locked_for_user()`, `user_can_lock()`, `user_can_unlock()`, `get_actions()`,  has been renamed to `obj`.

### Changes to `WorkflowState` and `TaskState` models

To accommodate workflows support for snippets, the `WorkflowState.page` foreign key has been replaced with a `GenericForeignKey` as `WorkflowState.content_object`. The generic foreign key is defined using a combination of the new `WorkflowState.base_content_type` and `WorkflowState.object_id` fields.

The `TaskState.page_revision` foreign key has been renamed to `TaskState.revision`.

### `wagtail.admin.forms.search.SearchForm` validation logic

The `wagtail.admin.forms.search.SearchForm` class (which is internal and undocumented, but may be in use by applications that extend the Wagtail admin) no longer treats an empty search field as invalid. Any code that checks `form.is_valid` to determine whether or not to apply a `search()` filter to a queryset should now explicitly check that `form.cleaned_data["q"]` is non-empty.
