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.
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).
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).
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).
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.
The CMS now includes an accessibility checker in the [user bar](wagtailuserbar_tag), in order 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.
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.
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/).
* 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)
* 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 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)
* Resolve issue where workflow and other notification emails would not include the correct tab URL for account notification management (LB (Ben) Johnston)
* 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)
* 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)
* Mention the importance of passing `request` and `current_site` to `get_url` on the [performance](performance_overview) documentation page (Jake Howard)
* 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)
| `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="..." %}` |
### `InlinePanel` JavaScript function is now a class
The (internal, undocumented) `InlinePanel` JavaScript function, used to initialise client-side behaviour 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 initialised 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.
The [`wagtailuserbar`](wagtailuserbar_tag) template tag now initialises 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 customising the position of the userbar, target the styles to `wagtail-userbar::part(userbar)` instead of `.wagtail-userbar`. For example:
### 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
### 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.
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`.
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.