[OpenSearch](https://opensearch.org/) is now formally supported as an alternative to Elasticsearch. For configuration details, see [OpenSearch configuration](opensearch). This feature was developed by Matt Westcott.
* Add [`wagtailcache`](wagtailcache) and [`wagtailpagecache`](wagtailpagecache) template tags to ensure previewing Pages or Snippets will not be cached (Jake Howard)
* Increase the read buffer size to improve efficiency and performance when generating file hashes for document or image uploads, use `hashlib.file_digest` if available (Python 3.11+) (Jake Howard)
* Filter out comments on Page editing counts that do not correspond to a valid field / block path on the page such as when a field has been removed (Matt Westcott)
* Ensure the panel title for a user's settings correctly reflects the `WAGTAIL_EMAIL_MANAGEMENT_ENABLED` setting by not showing 'email' if disabled (Omkar Jadhav)
* Migrate all other `data-tippy` HTML attribute usage to the Stimulus data-*-value attributes for w-tooltip & w-dropdown (Subhajit Ghosh, LB (Ben) Johnston)
* Replace `<script type="text/django-form-template"><-/script>` template approach with HTML `template` elements in InlinePanel and expanding formset (Mansi Gundre, Subhajit Ghosh, LB (Ben) Johnston)
### Adoption of `classname` convention for `MenuItem` related classes and hooks
Wagtail `MenuItem` and menu hooks have been updated to use the more consistent naming of `classname` (singular) instead of `classnames` (plural), a convention that started in Wagtail 4.2.
The current `classnames` keyword argument naming will be supported, but will trigger a deprecation warning. Support for this variant will be removed in a future release.
The following classes will adopt this new convention.
-`admin.menu.MenuItem`
-`admin.ui.sidebar.ActionMenuItem`
-`admin.ui.sidebar.LinkMenuItem`
-`admin.ui.sidebar.PageExplorerMenuItem`
-`contrib.settings.registry.SettingMenuItem`
The following hooks usage may be impacted if `classnames` were used when generating menu items.
The legacy moderation system, which was replaced by the new workflow system in Wagtail 2.10, is now deprecated. Since Wagtail 2.10, submitting a page for moderation will use the new workflow system. However, the legacy moderation system is still in place for approving and rejecting pages that were submitted for moderation before Wagtail 2.10.
To view all pages that are still in the legacy moderation system backlog, you can sign in as a superuser and see if there is a "Pages awaiting moderation" section in the admin dashboard. You can approve or reject the pages from there. You can also do this programmatically by querying for `Revision.objects.filter(submitted_for_moderation=True)` and calling `revision.approve_moderation()` or `revision.reject_moderation()` on each revision.
The legacy moderation system will be removed in a future release. If you still have pages in the moderation queue that were submitted for moderation before Wagtail 2.10, you should approve or reject them before upgrading. See [](./2.10) for more details.
As a result, the following features are now deprecated:
If you use any of the above features, remove them or replace them with the equivalent features from the new workflow system. The above features will be removed in a future release.
### Edit and delete URLs in `ModelViewSet` changed to allow non-integer primary keys
To accommodate models with non-integer primary keys, the URL patterns for the edit and delete views in {class}`~wagtail.admin.viewsets.model.ModelViewSet` have been changed.
Relative to the viewset's {attr}`~wagtail.admin.viewsets.base.ViewSet.url_prefix`, the following changes have been made:
- The edit URL pattern has been changed from `<int:pk>/` to `edit/<str:pk>/`
- The delete URL pattern has been changed from `<int:pk>/delete/` to `delete/<str:pk>/`
If you use {func}`~django.urls.reverse` with {meth}`~wagtail.admin.viewsets.base.ViewSet.get_url_name` to generate the URLs for these views, no changes are needed. However, if you have hard-coded these URLs in your code, you will need to update them to match the new patterns.
Redirects for the legacy URLs are in place for backwards compatibility, but will be removed in a future release.
The URLs for snippets underwent similar changes in Wagtail 2.14. The redirects for the legacy URLs in {class}`~wagtail.snippets.views.snippets.SnippetViewSet` have now been marked for removal in a future release.
### `ModelViewSet` automatically registers the model to the reference index
Models that are registered with a `ModelViewSet` now have reference index tracking enabled by default. This means that you no longer need to call `ReferenceIndex.register_model()` in your app's `ready()` method for such models. If this is undesired, you can disable it by setting {attr}`~wagtail.admin.viewsets.model.ModelViewSet.add_to_reference_index` to `False` on the `ModelViewSet` subclass. For more details, see [](managing_the_reference_index).
### Groups `IndexView.results_template_name` renamed from `results.html` to `index_results.html`
The `IndexView`'s `results_template_name` attribute in the `GroupViewSet` has been renamed from `wagtailusers/groups/results.html` to `wagtailusers/groups/index_results.html` for consistency with the other viewsets. If you have customised or extended the template, e.g. for [](customising_group_views), you will need to rename it to match the new name.
### Snippets templates refactored to reuse the shared `slim_header.html` template
The templates for the snippets views have been refactored to reuse the shared `slim_header.html` template. If you have customised or extended the templates, e.g. for [](wagtailsnippets_custom_admin_views), you will need to update them to match the new structure. As a result, the following templates have been removed:
In most cases, the usage of those templates can be replaced with the `wagtailadmin/shared/headers/slim_header.html` template. Refer to the snippets views and templates code for more details.
### `BaseSidePanels`, `PageSidePanels` and `SnippetSidePanels` classes are removed
The `BaseSidePanels`, `PageSidePanels` and `SnippetSidePanels` classes that were used to combine the side panels (i.e. status, preview and comments side panels) have been removed. Each side panel is now instantiated directly in the view. The `wagtail.admin.ui.components.MediaContainer` class can be used to combine the [`Media`](django:topics/forms/media) objects for the side panels.
The `BasePreviewSidePanel`, `PagePreviewSidePanel` and `SnippetPreviewSidePanel` classes have been replaced with the consolidated `PreviewSidePanel` class.
The `BaseStatusSidePanel` class has been renamed to `StatusSidePanel`.
If you use these classes in your code, you will need to update your code to instantiate the side panels directly in the view.
For example, if you have the following code:
```python
from wagtail.admin.ui.side_panels import PageSidePanels
### `construct_snippet_listing_buttons` hook no longer accepts a `context` argument
The [`construct_snippet_listing_buttons`](construct_snippet_listing_buttons) hook no longer accepts a `context` argument. If you have implemented this hook, you will need to remove the `context` argument from your implementation. If you need to access values computed by the view, you'll need to override the {attr}`~wagtail.snippets.views.snippets.SnippetViewSet.index_view_class` with a custom `IndexView` subclass. The `get_list_buttons` and `get_list_more_buttons` methods in particular may be overridden to customise the buttons on the listing.
Defining a function for this hook that accepts the `context` argument will raise a warning, and the function will receive an empty dictionary (`{}`) as the `context`. Support for defining the `context` argument will be completely removed in a future Wagtail release.
## Upgrade considerations - changes to undocumented internals
### Breadcrumbs now use different data attributes and events
The undocumented JavaScript implementation for the header breadcrumbs component has been migrated to a Stimulus controller and now uses different data attributes.
This may impact custom header implementations that relied on the previous approach, custom breadcrumbs that did not use `breadcrumbs` and require the expand/collapse behaviour may be impacted.
### `window.updateFooterSaveWarning` global util removed
The undocumented global util `window.updateFooterSaveWarning` has been removed, this is part of the footer 'unsaved' messages toggling behaviour on page forms.
This behaviour has now moved to a Stimulus controller and leverages DOM events instead. Calling this function will do nothing and in a future release will throw an error.
You can implement roughly the equivalent functionality with this JavaScript function, however, this will not be guaranteed to work in future releases.
Use the HTML [`template`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) element to avoid content from being parsed by the browser on load.
### Adoption of `classname` convention within the Image `Format` instance
When using `wagtail.images.formats.Format`, the created instance set the argument for classes to the attribute `classnames` (plural), this has now changed to `classname` (singular).
For any custom code that accessed or modified this undocumented attribute, updates will need to be made as follows.
Accessing `self.classnames` will still work until a future release, simply returning `self.classname`, but this will raise a deprecation warning.
```python
# image_formats.py
from django.utils.html import format_html
from wagtail.images.formats import Format, register_image_format