# Wagtail 8.0 release notes

*August 25, 2026*

> * [What’s new](#what-s-new)
> * [Upgrade considerations - removal of deprecated features from Wagtail 6.4 - 7.3](#upgrade-considerations-removal-of-deprecated-features-from-wagtail-6-4-7-3)
> * [Upgrade considerations - changes affecting all projects](#upgrade-considerations-changes-affecting-all-projects)
> * [Upgrade considerations - deprecation of old functionality](#upgrade-considerations-deprecation-of-old-functionality)
> * [Upgrade considerations - changes affecting Wagtail customizations](#upgrade-considerations-changes-affecting-wagtail-customizations)
> * [Upgrade considerations - changes to undocumented internals](#upgrade-considerations-changes-to-undocumented-internals)

## What’s new

### Wagtail REST API v3 (preview)

Wagtail 8.0 introduces a preview of a new [v3 API](../advanced_topics/api/v3/index.html.md#api-v3), built on [Django Ninja](https://django-ninja.dev/) and type hints. The v2 API was designed for headless site and other data publication needs. v3 serves similar use cases, and adds support for CMS operations on top: authenticated clients can create, edit, publish and unpublish, move, copy, and revert content, and manage revisions, across pages, sites, locales, redirects, images, documents, and API-enabled snippets. You can create new pages with writable StreamField content, rich text as HTML or Markdown. The API auto-generates precise OpenAPI 3.1 schemas based on your project’s models, and uses API token authentication tied to user accounts. See the [v3 API documentation](../advanced_topics/api/v3/index.html.md#api-v3) for full details.

The v3 API is released as a preview to signify we want to adapt it based on feedback: it may change in backwards-incompatible ways in any release until stabilised. We welcome [feedback via discussions](https://github.com/wagtail/wagtail/discussions/14531), feature requests and bug reports. This feature was developed by Thibaud Colas and Sage Abdullah.

### Custom base page models

This release introduces [the ability to swap out the base `Page` model](../advanced_topics/customization/custom_base_page_models.html.md#custom-page-models) with a custom project-specific model. Any fields and methods defined on this model will be shared by all page types. This feature is only supported for newly-created projects, and certain add-on packages may not yet be compatible with it (see [Adapting reusable apps to support custom base page models](../extending/reusable_app_base_page.html.md#reusable-app-base-page)). This feature was developed by Matt Westcott.

### Permission policy registry

A permission policy for every model managed by Wagtail is now registered to a global permission policy registry. The registry allows you to retrieve the permission policy of a model from anywhere in the code, which can be useful for performing permission checks outside of a view’s request-response cycle, such as in a background task. It can also be used to implement custom permission logic, including for Wagtail’s built-in models.

For more details, refer to the [Permissions](../reference/permissions.html.md#permissions-reference) reference documentation. This feature was developed by Sage Abdullah.

### Django 6.1 support

This release introduces formal support for [Django 6.1](https://docs.djangoproject.com/en/6.1/releases/6.1/).

### Guide website improvements

The [Wagtail user guide](https://guide.wagtail.org/) has been updated to use a new versioning scheme, better search and navigation, and better support for Right-to-Left (RTL) languages.

Thank you to Raghad Dahi for leading this work. For more information, read her project report: [Streamlining content ops with LLMs: Wagtail user guide](https://wagtail.org/blog/streamlining-content-operations-with-llms-wagtail-user-guide/).

### Automated dependency management

We now provide [SBOM exports of our dependency graph](https://github.com/wagtail/wagtail/network/dependencies) in SPDX JSON format. This complements a number of improvements to dependency management, implemented by Sage Abdullah, Dan Braghis, and Thibaud Colas:

* Automated testing with latest versions of all dependencies
* Lockfiles and pinned dependencies for reproducible CI builds
* zizmor for GitHub Actions quality checks
* Automated dependency updates via Renovate

### Security fix: Improper restriction handling on Pages admin API

The internal Pages admin API incorrectly returned page fields without access control when they were declared in `api_fields`. A user with access to the Wagtail admin could use this API to fetch draft and live page fields’ contents that are part of `api_fields` on the base page model (title, slug, seo_title, search_description), as well as all custom fields declared in `api_fields`.

Many thanks to xuliang@QAX for reporting this issue. For further details, please see [security advisory GHSA-3vrh-m9w7-v94f](https://github.com/wagtail/wagtail/security/advisories/GHSA-3vrh-m9w7-v94f).

### Security fix: Identification of documents by SHA1 hash

By passing specific HTTP headers to the document serve URL endpoint, an attacker was able to determine whether a document with a given ID matched a specified SHA1 hash, regardless of any permission restrictions on the document or knowing its filename. This could allow an attacker to determine whether a document with a specific known hash is present in the Wagtail document library.

Many thanks to Anand Himanshu for reporting this issue. For further details, please see [security advisory GHSA-92hv-j533-69wc](https://github.com/wagtail/wagtail/security/advisories/GHSA-92hv-j533-69wc).

### Security fix: Improper restriction handling on descendant collections in Documents and Images API

The Documents and Images API incorrectly listed items in descendants of private collections, which should inherit the view restrictions defined on their ancestors. A user with access to the API could see the filename and name of documents and images in these descendant collections.

Many thanks to Ta Duc Thien for reporting this issue. For further details, please see [security advisory GHSA-c2xx-cjmh-9q8f](https://github.com/wagtail/wagtail/security/advisories/GHSA-c2xx-cjmh-9q8f).

### Security fix: Improper permission handling when copying snippets

A CMS user with “add” permission over a snippet model, but not “change” or “view” permission, could copy an existing snippet that they do not have access to, allowing them to view its contents.

Many thanks to tinyb0y for reporting this issue. For further details, please see [security advisory GHSA-x5cx-w6p2-mxf2](https://github.com/wagtail/wagtail/security/advisories/GHSA-x5cx-w6p2-mxf2).

### Security fix: Improper restriction handling on Page translation API endpoint

A CMS user with the “submit translations” permission, could use the Admin API’s “copy for translation” endpoint to copy an existing page that they do not have edit access to, allowing them to view its contents.

Many thanks to tinyb0y for reporting this issue. For further details, please see [security advisory GHSA-jm5p-837g-rv8g](https://github.com/wagtail/wagtail/security/advisories/GHSA-jm5p-837g-rv8g).

### Other features

* Add customizability for all remaining page views to `PageViewSet` (Sage Abdullah)
* Set `FieldPanel(required_on_save=True)` for `AbstractFormField`’s `field_type` field (Alex Tomkins)
* Handle pasting of multiple tags separated by newlines or commas (Matthias Brück)
* Make `Button` component render a `<button>` element when no URL is supplied (Nayeli De Jesus, LB (Ben Johnston), Sage Abdullah)
* Show site name in site switcher dropdown in site settings editor (Jack Morgan)
* Improve clarity of different task states in workflow details dialog (Dan Braghis)
* Add `submenu_hook` attribute to `ViewSetGroup` for collecting submenu items registered via a hook (Hunzlah Malik, MariyaOT, Sage Abdullah)
* Respect `ViewSet.menu_order` when used in a `ViewSetGroup` (Sage Abdullah)
* Use a more accessible label for blank values of `ChoiceBlock` (Sage Abdullah)
* Use a more accessible label for blank values of dropdowns in locked page report filters (Sage Abdullah)
* Make audit log messages for scheduling/unscheduling generic (Sage Abdullah)
* Stop converting AVIF and WebP images to PNG by default (Thibaud Colas)
* Add rich text [serializing to HTML](../advanced_topics/api/v2/configuration.html.md#api-v2-rich-text) support in the v2 API (Thibaud Colas)
* Expose the block `id` [as a template context variable](../topics/streamfield.html.md#streamfield-block-id-context-variable) when rendering children of `StreamBlock` and `ListBlock` (Sage Abdullah)
* Add extension blocks for image and document stats in the edit view templates (Preeti Singh)

### Bug fixes

* Make `SnippetChooserViewSet.widget_class` a class instead of an instance (Amrinder Singh, Sage Abdullah)
* Prevent an error when approving a workflow that has been cancelled in a different session (Kailesh)
* Accommodate multilingual sites in skipping the “choose parent” step when creating a new page from a flat page listing (Amrinder Singh)
* Prevent error when moving a page to a destination with missing translations and `WAGTAILSIMPLETRANSLATION_SYNC_PAGE_TREE = True` (Sahil Kumar)
* Handle Pillow detecting decompression bombs when validating image pixel count (Jake Howard, Sage Abdullah)
* Use canonical URL for TED oEmbed provider (Marquis Nobles)
* Prevent stale content types from breaking audit log message formatting (Thibaud Colas)
* Prevent icons from capturing clicks inside buttons (Maciek Baron)
* Ensure form field clean_name is consistently set on form pages if autosave runs prematurely (Joey Jurjens)
* Enforce ‘choose’ permission on image chooser select-format view (Matt Westcott)

### Documentation

* Add reference documentation entry for `SnippetChooserViewSet` (Sage Abdullah)
* Fix panel classname and deprecated usage of `format_html` in `construct_homepage_panels` example (Andreas Nüßlein)
* Update django-ninja code examples to use new Meta class implemented in django-ninja V1 (Jack Whitworth)
* Document [`request.in_preview_panel`](../topics/writing_templates.html.md#custom-rendering-in-preview-panel) to explain its use (Raghad Dahi)
* Update image format docs to encourage more intentional conversions (Thibaud Colas)
* Clarify Wagtail XSS protections for uploaded documents (Thibaud Colas)
* Add section on customizing StreamField block API output with `get_api_representation` (Pranith Beeram)
* Removed now-deprecated `USE_L10N` setting from internationalization and project setup documentation (Piyush Bhakuni)
* Add a new [images overview page](../advanced_topics/images/overview.html.md#images-overview) (Dmitry Khlopyev)

### Maintenance

* Rename `request` argument to `cache_object` in `Page._get_site_root_paths()` for correctness (Kailesh)
* Fix blank choice tests for Django 6.1 (Sage Abdullah)
* Ignore `EMAIL_BACKEND` setting deprecation on Django 6.1 when running project template tests (Sage Abdullah)
* Add `one` and `not` match support to `RulesController` (LB (Ben Johnston))
* Refactor pages’ function-based views to class-based views (Sage Abdullah)
* Enable flake8-bandit security-focused linting rules (Storm Heg)
* Add support for latest Azure SDK for frontend cache invalidation (Sage Abdullah, Tomasz Knapik)
* Update guide.wagtail.org links to new versioning scheme (Raghad Dahi)
* Format Python code in documentation using ruff (Thibaud Colas)
* Use Ubuntu 26.04 ARM runner for GitHub Actions workflows (Storm Heg)

## Upgrade considerations - removal of deprecated features from Wagtail 6.4 - 7.3

Features previously deprecated in Wagtail 6.4, 7.0, 7.1, 7.2, and 7.3 have been fully removed:

* The `construct_wagtail_userbar` hook now receives a third argument `page` in addition to `request` and `items`; hook functions that only accept two arguments will now fail.
* The JavaScript functions `buildExpandingFormset` and `initPrefillTitleFromFilename` are removed.
* The settings `TAG_LIMIT` and `TAG_SPACES_ALLOWED` are replaced by `WAGTAIL_TAG_LIMIT` and `WAGTAIL_TAG_SPACES_ALLOWED`.
* Custom listing views using the template `wagtailadmin/generic/index.html` must now provide a `breadcrumbs_items` context variable.
* The template `wagtailadmin/pages/_editor_js.html` is removed.
* The `PageListingButton`, `SnippetListingButton` and `UserListingButton` classes are removed in favour of `ListingButton` and `Button`.
* The function `wagtail.admin.signals.init_new_page` is moved to `wagtail.signals.init_new_page`.
* The module `wagtail.telepath` is moved to `wagtail.admin.telepath`.
* The module `wagtail.widget_adapters` is moved to `wagtail.admin.telepath.widgets`.
* The JavaScript include `wagtailadmin/js/telepath/telepath.js` is removed.
* The `INDEX` option on `WAGTAILSEARCH_BACKENDS` is replaced by `INDEX_PREFIX` (for example, `"INDEX": "mysite"` now becomes `"INDEX_PREFIX": "mysite_"`).
* Userbar items now follow the template component API and do not provide a `render` method.
* The `resetValue` property is removed from `TeleportController`.

For additional details on these changes, see:

* [Wagtail 6.4 release notes](6.4.html.md)
* [Wagtail 7.0 release notes](7.0.html.md)
* [Wagtail 7.1 release notes](7.1.html.md)
* [Wagtail 7.2 release notes](7.2.html.md)
* [Wagtail 7.3 release notes](7.3.html.md)

## Upgrade considerations - changes affecting all projects

### AVIF and WebP images are no longer converted to PNG by default

Browser support for AVIF and WebP is now solid enough that Wagtail no longer converts images in these formats to PNG when no output format is specified. Rather than relying on this setting, we recommend controlling output formats explicitly with the `format-*` filter or `picture` template tag. See [Customizing output formats](../advanced_topics/images/image_file_formats.html.md#customizing-output-formats) for more details.

If you need to retain the previous behavior as-is, add the following to your settings:

```python
WAGTAILIMAGES_FORMAT_CONVERSIONS = {
    "bmp": "png",
    "heic": "jpeg",
    "avif": "png",
    "webp": "png",
}
```

## Upgrade considerations - deprecation of old functionality

### Support for legacy versions of `azure-mgmt-cdn`, `azure-mgmt-frontdoor`, and `azure-mgmt-resource` 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 13 or above
* For Azure Front Door: upgrade `azure-mgmt-frontdoor` to version 1.1 or above

In addition, if you do not set `SUBCRIPTION_ID` and thus rely on `azure-mgmt-resource` to retrieve the default subscription, you should install the `azure-mgmt-subscription` package instead of (or in addition to) `azure-mgmt-resource`.

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

## Upgrade considerations - changes affecting Wagtail customizations

### Support for custom base page models in add-on packages

Reusable apps that work with the `Page` model are likely to require updating in order to be usable on projects that use the new custom base page model feature. This process is detailed at [Adapting reusable apps to support custom base page models](../extending/reusable_app_base_page.html.md#reusable-app-base-page).

### Custom permission policy in viewsets must be registered separately

If you use the [Generic views](../extending/generic_views.html.md#generic-views) and have a [`ModelViewSet`](../reference/viewsets.html.md#wagtail.admin.viewsets.model.ModelViewSet), [`SnippetViewSet`](../reference/viewsets.html.md#wagtail.snippets.views.snippets.SnippetViewSet), or [`ChooserViewSet`](../reference/viewsets.html.md#wagtail.admin.viewsets.chooser.ChooserViewSet) that defines a custom value for the (previously-undocumented) [`permission_policy`](../reference/viewsets.html.md#wagtail.admin.viewsets.model.ModelViewSet.permission_policy), you must now register the permission policy separately.

Registering a permission policy can be done by calling
[`register_permission_policy(Model, <policy_instance>)`](../reference/permissions.html.md#wagtail.permissions.register_permission_policy)
at the top of the model app’s `wagtail_hooks.py`.

```py
# wagtail_hooks.py
from wagtail.permissions import register_permission_policy
from .models import MyModel


register_permission_policy(MyModel, my_custom_policy_instance)
...  # More customizations
```

Alternatively, you can also put the registration in the app’s
[`AppConfig.ready()`](https://docs.djangoproject.com/en/stable/ref/applications/#django.apps.AppConfig.ready).

```py
# apps.py
class MyAppConfig(AppConfig):
    ...

    def ready(self):
        from wagtail.permissions import register_permission_policy
        from .models import MyModel

        register_permission_policy(MyModel, my_custom_policy_instance)
```

If you do not register the permission policy explicitly, Wagtail will automatically register the viewset’s `permission_policy`, and a deprecation warning will be raised. This support will be removed in a future release.

This change does not affect viewsets that do not have a custom `permission_policy`.

### `SnippetChooserViewSet.widget_class` is now a class

The [`SnippetChooserViewSet.widget_class`](../reference/viewsets.html.md#wagtail.snippets.views.chooser.SnippetChooserViewSet.widget_class) attribute now correctly returns a widget class instead of an instance, consistent with [`ChooserViewSet.widget_class`](../reference/viewsets.html.md#wagtail.admin.viewsets.chooser.ChooserViewSet.widget_class). This change may require updates to any customizations that relied on the previous behavior, such as an override in a `SnippetChooserViewSet` subclass that uses `super().widget_class`.

### `ViewSet.menu_order` is now respected when used in a `ViewSetGroup`

[`ViewSet`](../reference/viewsets.html.md#wagtail.admin.viewsets.base.ViewSet)s that are registered as part of a [`ViewSetGroup`](../reference/viewsets.html.md#wagtail.admin.viewsets.base.ViewSetGroup) now have their [`menu_order`](../reference/viewsets.html.md#wagtail.admin.viewsets.base.ViewSet.menu_order) respected instead of always using its position in [`ViewSetGroup.items`](../reference/viewsets.html.md#wagtail.admin.viewsets.base.ViewSetGroup.items).

If you rely on the previous behavior that used the `items` ordering, remove [`menu_order`](../reference/viewsets.html.md#wagtail.admin.viewsets.base.ViewSet.menu_order) in your `ViewSet` definition.

### Setting `submissions_list_view_class` on form page models no longer works

The `submissions_list_view_class` attribute on the form builder’s `AbstractForm` model, previously documented at [Customize form submissions listing in Wagtail Admin](../reference/contrib/forms/customization.html.md#custom-form-submission-listing), is no longer directly usable. This is because the `wagtail.contrib.forms.views` module can no longer be imported at model load time without introducing a circular import, and so there is no way to refer to a subclass of `SubmissionsListView` within a model definition. Instead, the `get_submissions_list_view_class` method can be overridden to achieve the same result. First, the definition of the `SubmissionsListView` subclass, and the import of `SubmissionsListView`, should be moved to a separate `views` module within the app. Then, the attribute assignment:

```python
class FormPage(AbstractEmailForm):
    # ...
    submissions_list_view_class = CustomSubmissionsListView
```

can be replaced with:

```python
class FormPage(AbstractEmailForm):
    # ...
    def get_submissions_list_view_class(self):
        from myapp.views import CustomSubmissionsListView

        return CustomSubmissionsListView
```

## Upgrade considerations - changes to undocumented internals

### `request` argument to `Page._get_site_root_paths` is now `cache_object`

The `request` argument to the undocumented method `Page._get_site_root_paths()` is renamed to `cache_object` to reflect the fact that it is not always a request object, but may be any object that can be used for caching purposes.

If you pass `request` as a positional argument, no changes are needed. If you pass `request` as a keyword argument to this method, you will need to update the argument name to `cache_object` in your code or turn it into a positional argument.

Passing a `request` keyword argument will continue to work for now and raise a deprecation warning, but support for this will be removed in a future release.
