Co-authored-by: Thibaud Colas <thibaudcolas@gmail.com>
19 KiB
Wagtail 5.1 release notes - IN DEVELOPMENT
Unreleased
---
local:
depth: 1
---
What's new
Read-only panels
FieldPanels can now be marked as read-only with the read_only=True
keyword argument, so that they are displayed in the admin but cannot be edited. This feature was developed by Andy Babic.
Wagtail tutorial improvements
As part of Google Season of Docs 2023, we worked with technical writer Damilola Oladele to make improvements to Wagtail’s "Getting started" tutorial. Here are the specific changes made as part of this project:
- Revamp the start of the getting started section, with separate quick install page
- Move the tutorial’s snippets section to come before tags
- Rewrite the getting started tutorial to address identified friction points
- Switch the Getting started tutorial’s snippets example to be more understandable
Thank you to Damilola for his work, and to Google for sponsoring this project.
Custom template support for wagtail start
The wagtail start
command now supports an optional --template
argument that allows you to specify a custom project template to use. This is useful if you want to use a custom template that includes additional features or customisations. For more details, see the project template reference. This feature was developed by Thibaud Colas.
Search query boosting on Elasticsearch 6 and above
The boost
option on SearchField
, to increase the ranking of search results that match on the specified field, is now respected by Elasticsearch 6 and above. This was previously only supported up to Elasticsearch 5, due to a change in Elasticsearch's API. This feature was developed by Shohan Dutta Roy.
Extend Stimulus adoption
As part of tackling Wagtail’s technical debt and improving CSP compatibility, we have continued extending our usage of Stimulus, based on the plans laid out in RFC 78: Adopt Stimulus.
- Migrate Tagit initialisation to a Stimulus Controller (LB (Ben) Johnston)
- Migrate legacy dropdown implementation to a Stimulus controller (Thibaud Colas)
- Migrate header search behaviour to
w-swap
, a Stimulus controller (LB (Ben) Johnston) - Replace Bootstrap tooltips with a new
w-tooltip
Stimulus controller (LB (Ben) Johnston)
Other features
- Mark calls to
md5
as not being used for secure purposes, to avoid flagging on FIPS-mode systems (Sean Kelly) - Return filters from
parse_query_string
as aQueryDict
to support multiple values (Aman Pandey) - Explicitly specify
MenuItem.name
for all admin menu and submenu items (Justin Koestinger) - Add oEmbed provider patterns for YouTube Shorts (e.g. https://www.youtube.com/shorts/nX84KctJtG0) and YouTube Live URLs (valnuro, Fabien Le Frapper)
- Add initial implementation of
PagePermissionPolicy
(Sage Abdullah) - Refactor
UserPagePermissionsProxy
andPagePermissionTester
to usePagePermissionPolicy
(Sage Abdullah, Tidiane Dia) - Add a predictable default ordering of the "Object/Other permissions" in the Group Editing view, allow this ordering to be customised (Daniel Kirkham)
- Implement a new design for chooser buttons with better accessibility (Thibaud Colas)
- Add
AbstractImage.get_renditions()
for efficient generation of multiple renditions (Andy Babic) - Optimise queries in collection permission policies using cache on the user object (Sage Abdullah)
- Phone numbers entered via a link chooser will now have any spaces stripped out, ensuring a valid
href="tel:..."
attribute (Sahil Jangra) - Auto-select the
StreamField
block when only one block type is declared (Sébastien Corbin) - Add support for more advanced Draftail customisation APIs (Thibaud Colas)
- Add the ability to export snippets listing via
SnippetViewSet.list_export
(Sage Abdullah) - Add support for adding HTML
attrs
onFieldPanel
,FieldRowPanel
,MultiFieldPanel
, and others (Aman Pandey, Antoni Martyniuk, LB (Ben) Johnston) - Change to always cache renditions (Jake Howard)
- Update link/document rich text tooltips for consistency with the inline toolbar (Albina Starykova)
- Increase the contrast between the rich text / StreamField block picker and the page in dark mode (Albina Starykova)
- Purge revisions of non-page models in
purge_revisions
command (Sage Abdullah)
Bug fixes
- Prevent choosers from failing when initial value is an unrecognised ID, e.g. when moving a page from a location where
parent_page_types
would disallow it (Dan Braghis) - Move comment notifications toggle to the comments side panel (Sage Abdullah)
- Remove comment button on InlinePanel fields (Sage Abdullah)
- Fix missing link to
UsageView
fromEditView
for snippets (Christer Jensen) - Prevent lowercase conversions of IndexView column headers (Virag Jain)
- Ensure that
RichText
objects with the same values compare as equal (NikilTn) - Use
gettext_lazy
on generic model views so that language settings are correctly used (Matt Westcott) - Prevent JS error when reverting the spinner on a submit button after a validation error (LB (Ben) Johnston)
- Prevent crash when comparing page revisions that include
MultipleChooserPanel
(Matt Westcott) - Ensure that title and slug continue syncing after entering non-URL-safe characters (LB (Ben) Johnston)
- Ensure that title and slug are synced on keypress, not just on blur (LB (Ben) Johnston)
- Add a more visible active state for side panel toggle buttons (Thibaud Colas)
- Debounce and optimise live preview panel to prevent excessive requests (Sage Abdullah)
- Page listings actions under the "More" dropdown are now accessible for screen reader and keyboard users (Thibaud Colas)
- Bulk actions under the "More" dropdown are now accessible for screen reader and keyboard users (Thibaud Colas)
- Navigation to translations via the locale dropdown is now accessible for screen reader and keyboard users (Thibaud Colas)
- Make it possible for speech recognition users to reveal chooser buttons (Thibaud Colas)
- Use constant-time comparison for image serve URL signatures (Jake Howard)
- Ensure taggit field type-ahead options show correctly in the dark mode theme (Sage Abdullah)
- Fix the lock description message missing the model_name variable when locked only by system (Sébastien Corbin)
- Fix empty blocks created in migration operations (Sandil Ranasinghe)
- Ensure that
gettext_lazy
works correctly when usingverbose_name
on a generic Settings models (Sébastien Corbin) - Remove unnecessary usage of
innerHTML
when modifying DOM content (LB (Ben) Johnston) - Avoid
ValueError
when extendingPagesAPIViewSet
and settingmeta_fields
to an empty list (Henry Harutyunyan, Alex Morega) - Improve accessibility for header search, remove autofocus on page load, advise screen readers that content has changed when results update (LB (Ben) Johnston)
- Fix incorrect override of
PagePermissionHelper.user_can_unpublish_obj()
in ModelAdmin (Sébastien Corbin) - Prevent memory exhaustion when updating a large number of image renditions (Jake Howard)
- Add missing Time Zone conversions and date formatting throughout the admin (Stefan Hammer)
- Ensure that audit logs and revisions are consistently use UTC and add migration for existing entries (Stefan Hammer)
- Make sure "critical" buttons have enough color contrast in dark mode (Albina Starykova)
Documentation
- Document how to add non-ModelAdmin views to a
ModelAdminGroup
(Onno Timmerman) - Document how to add StructBlock data to a StreamField (Ramon Wenger)
- Update ReadTheDocs settings to v2 to resolve urllib3 issue in linkcheck extension (Thibaud Colas)
- Update documentation for
log_action
parameter onRevisionMixin.save_revision
(Christer Jensen) - Reorganise snippets documentation to cover customisations and optional features (Sage Abdullah)
- Update color customisations guidance to include theme-agnostic options (Thibaud Colas)
- Mark LTS releases in release note page titles (Thiago C. S. Tioma)
- Revise main Getting started tutorial for clarity (Kevin Chung (kev-odin))
- Update the deployment documentation page and remove outdated information (Jake Howard)
- Add more items to performance page regarding pre-fetching images and frontend caching (Jake Howard)
Maintenance
- Removed support for Python 3.7 (Dan Braghis)
- Switch to ruff for flake8 / isort code checking (Oliver Parker)
- Deprecate
insert_editor_css
in favour ofinsert_global_admin_css
(Ester Beltrami) - Optimise use of
specific
on Task and TaskState (Matt Westcott) - Use table UI component for workflow task index view (Matt Westcott)
- Make header search available on generic index view (Matt Westcott)
- Update pagination behaviour to reject out-of-range / invalid page numbers (Matt Westcott)
- Remove color tokens which are duplicates / unused (Thibaud Colas)
- Add tests to help with maintenance of theme color tokens (Thibaud Colas)
- Split out a base listing view from generic index view (Matt Westcott)
- Update type hints in admin/ui/components.py so that
parent_context
is mutable (Andreas Nüßlein) - Deprecate
UserPagePermissionsProxy
(Sage Abdullah) - Optimise the Settings context processor to avoid redundantly finding a Site to improve cache ratios (Jake Howard)
- Convert page listing to a class-based view (Matt Westcott)
- Clean up page reports and type usage views to be independent of page listing views (Matt Westcott)
- Refactor "More" dropdowns, locale selector, "Switch locales", page actions, to use the same dropdown component (Thibaud Colas)
- Refactor GroupPagePermission to use Django's Permission model (Sage Abdullah)
- Convert the
CONTRIBUTORS
file to Markdown (Dan Braghis) - Move
django-filter
version upper bound to v24 (Yuekui) - Update Pillow dependency to allow 10.x, only include support for >= 9.1.0 (Yuekui)
- Replace ModelAdmin history header human readable date template tag (LB (Ben) Johnston)
- Update uuid to v9 and Jest to v29, with
jest-environment-jsdom
and new snapshot format (LB (Ben) Johnston) - Update test cases producing undesirable console output due to missing mocks, uncaught errors, warnings (LB (Ben) Johnston)
- Remove unused snippets _header_with_history.html template (Thibaud Colas)
Upgrade considerations
Removed support for Python 3.7
Python 3.7 is no longer supported as of this release; please upgrade to Python 3.8 or above before upgrading Wagtail.
Pillow dependency update
Wagtail no longer supports Pillow versions below 9.1.0
.
insert_editor_css
hook is deprecated
The insert_editor_css
hook has been deprecated. The insert_global_admin_css
hook has the same functionality, and all uses of insert_editor_css
should be changed to insert_global_admin_css
.
UserPagePermissionsProxy
is deprecated
The undocumented wagtail.models.UserPagePermissionsProxy
class is deprecated.
If you use the .for_page(page)
method of the class to get a PagePermissionTester
instance, you can replace it with page.permissions_for_user(user)
.
If you use the other methods, they can be replaced via the wagtail.permission_policies.pages.PagePermissionPolicy
class. The following is a list of the PagePermissionPolicy
equivalent of each method:
from wagtail.models import UserPagePermissionsProxy
from wagtail.permission_policies.pages import PagePermissionPolicy
# proxy = UserPagePermissionsProxy(user)
permission_policy = PagePermissionPolicy()
# proxy.revisions_for_moderation()
permission_policy.revisions_for_moderation(user)
# proxy.explorable_pages()
permission_policy.explorable_instances(user)
# proxy.editable_pages()
permission_policy.instances_user_has_permission_for(user, "change")
# proxy.can_edit_pages()
permission_policy.instances_user_has_permission_for(user, "change").exists()
# proxy.publishable_pages()
permission_policy.instances_user_has_permission_for(user, "publish")
# proxy.can_publish_pages()
permission_policy.instances_user_has_permission_for(user, "publish").exists()
# proxy.can_remove_locks()
permission_policy.user_has_permission(user, "unlock")
The UserPagePermissionsProxy
object that is available in page's ActionMenuItem
context as user_page_permissions
(which might be used as part of a register_page_action_menu_item
hook) has been deprecated. In cases where the page object is available (e.g. the page edit view), the PagePermissionTester
object stored as the user_page_permissions_tester
context variable can still be used.
The UserPagePermissionsProxy
object that is available in the template context as user_page_permissions
as a side-effect of the page_permissions
template tag has also been deprecated.
If you use the user_page_permissions
context variable or use the UserPagePermissionsProxy
class directly, make sure to replace it either with the PagePermissionTester
or the PagePermissionPolicy
equivalent.
get_pages_with_direct_explore_permission
, get_explorable_root_page
, and users_with_page_permission
are deprecated
The undocumented get_pages_with_direct_explore_permission
and get_explorable_root_page
functions in wagtail.admin.navigation
are deprecated. They can be replaced with PagePermissionPolicy().instances_with_direct_explore_permission(user)
and PagePermissionPolicy().explorable_root_instance(user)
, respectively.
The undocumented users_with_page_permission
function in wagtail.admin.auth
is also deprecated. It can be replaced with PagePermissionPolicy().users_with_permission_for_instance(action, page, include_superusers)
.
GroupPagePermission
now uses Django's Permission
model
The GroupPagePermission
model that is responsible for assigning page permissions to groups now uses Django's Permission
model instead of a custom string. This means that the permission_type
CharField
has been deprecated and replaced with a permission
ForeignKey
to the Permission
model.
In addition to this, "edit" permissions now use the term change
within the code. As a result, GroupPagePermission
s that were previously recorded with permission_type="edit"
are now recorded with a Permission
object that has the codename="change_page"
and a content_type
that points to the Page
model. Any permission checks that are done using PagePermissionPolicy
should also use change
instead of edit
.
If you have any fixtures for the GroupPagePermission
model, you will need to update them to use the new Permission
model. For example, if you have a fixture that looks like this:
{
"pk": 11,
"model": "wagtailcore.grouppagepermission",
"fields": {
"group": ["Event moderators"],
"page": 12,
"permission_type": "edit"
}
}
Update it to use a natural key for the permission
field instead of the permission_type
field:
{
"pk": 11,
"model": "wagtailcore.grouppagepermission",
"fields": {
"group": ["Event moderators"],
"page": 12,
"permission": ["change_page", "wagtailcore", "page"]
}
}
If you have any code that creates GroupPagePermission
objects, you will need to update it to use the Permission
model instead of the permission_type
string. For example, if you have code that looks like this:
from wagtail.core.models import GroupPagePermission
permission = GroupPagePermission(group=group, page=page, permission_type="edit")
permission.save()
Update it to use the Permission
model instead:
from django.contrib.auth.models import Permission
from wagtail.core.models import GroupPagePermission
permission = GroupPagePermission(
group=group,
page=page,
permission=Permission.objects.get(content_type__app_label="wagtailcore", codename="change_page"),
)
permission.save()
During the deprecation period, the permission_type
field will still be available on the GroupPagePermission
model and is used to automatically populate empty permission
field as part of a system check. The permission_type
field will be removed in Wagtail 6.0.
The default ordering of Group Editing Permissions models has changed
The ordering for "Object permissions" and "Other permissions" now follows a predictable order equivalent do Django's default Model
ordering.
This will be different to the previous ordering which never intentionally implemented.
This default ordering is now ["content_type__app_label", "content_type__model", "codename"]
, which can now be customised .
Shared include wagtailadmin/shared/last_updated.html
is no longer available
The undocumented shared include wagtailadmin/shared/last_updated.html
is no longer available as it used the legacy Bootstrap tooltips and was not accessible. If you need to achieve a similar output, an element that shows a simple date with a tooltip for the full date, use the human_readable_date
template tag instead.
Before
{% include "wagtailadmin/shared/last_updated.html" with last_updated=my_model.timestamp %}
After
{% load wagtailadmin_tags %}
<!-- ... -->
{% human_readable_date my_model.timestamp %}
Tag (Tagit) field usage now relies on data attributes
The AdminTagWidget
widget has now been migrated to a Stimulus controller, if using this widget in Python, no changes are needed to adopt the new approach.
If the widget is being instantiated in JavaScript or HTML with the global util window.initTagField
, this undocumented util should be replaced with the new data-*
attributes approach. Additionally, any direct usage of the jQuery widget in JavaScript (e.g. $('#my-element).tagit()
) should be removed.
The global util will be removed in a future release. It is recommended that the documented AdminTagWidget
be used. However, if you need to use the JavaScript approach you can do this with the following example.
Old syntax
<input id="id_tags" type="text" value="popular, technology" hidden />
<script>
window.initTagField('id_tags', 'path/to/url', { autocompleteOnly: true });
</script>
New syntax
<input
id="id_tags"
type="text"
value="popular, technology"
hidden
data-controller="w-tag"
data-w-tag-options-value='{"autocompleteOnly": true}'
data-w-tag-url-value="/path/to/url"
/>
Note: The data-w-tag-options-value
is a JSON object serialised into string. Django's HTML escaping will handle it automatically when you use the AdminTagWidget
, but if you are manually writing the attributes, be sure to use quotation marks correctly.
Image Renditions are now cached by default
Wagtail will try to use the cache called "renditions". If no such cache exists, it will fall back to using the default cache. You can configure the "renditions" cache to use a different cache backend or to provide additional configuration parameters.
Tooltips now rely on new data attributes
The undocumented Bootstrap jQuery tooltip widget is no longer in use, you will need to update any HTML that is using these attributes to the new syntax.
<!-- Old attributes: -->
<span data-wagtail-tooltip="Tooltip content here">Label</span>
<!-- New attributes: -->
<span data-controller="w-tooltip" data-w-tooltip-content-value="Tooltip content here">Label</span>