Add ability to set default configurable attributes to image tags

- Allow users to override the default attributes given to an image
- Update tests to account for new tags
- Add documentation for custom image attributes
- Recommend that loading=lazy & decoding=async be considered for performance in front-end sites
pull/9061/head
Jake Howard 2022-05-26 11:40:12 +01:00 zatwierdzone przez LB (Ben Johnston)
rodzic 36e4e9b93d
commit 5108b5f82a
8 zmienionych plików z 77 dodań i 3 usunięć

Wyświetl plik

@ -7,6 +7,7 @@ Changelog
* Add basic keyboard control and screen reader support for page listing re-ordering (Paarth Agarwal, Thomas van der Hoeven)
* Add `PageQuerySet.private` method as an alias of `not_public` (Mehrdad Moradizadeh)
* Allow setting default attributes on image tags (Jake Howard)
* Fix: Prevent `PageQuerySet.not_public` from returning all pages when no page restrictions exist (Mehrdad Moradizadeh)

Wyświetl plik

@ -83,3 +83,9 @@ TEMPLATES = [{
To support high volumes of traffic with excellent response times, we recommend a caching proxy. Both [Varnish](https://varnish-cache.org/) and [Squid](http://www.squid-cache.org/) have been tested in production. Hosted proxies like [Cloudflare](https://www.cloudflare.com/) should also work well.
Wagtail supports automatic cache invalidation for Varnish/Squid. See [](frontend_cache_purging) for more information.
### Image attributes
For some images, it may be beneficial to lazy load images, so the rest of the page can continue to load. It can be configured site-wide [](adding_default_attributes_to_images) or per-image [](image_tag_alt). For more details you can read about the [`loading='lazy'` attribute](https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading#images_and_iframes) and the [`'decoding='async'` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-decoding) or this [web.dev article on lazy loading images](https://web.dev/lazy-loading-images/).
This optimisation is already handled for you for images in the admin site.

Wyświetl plik

@ -16,10 +16,10 @@ Wagtail 4.1 is designated a Long Term Support (LTS) release. Long Term Support r
* Add basic keyboard control and screen reader support for page listing re-ordering (Paarth Agarwal, Thomas van der Hoeven)
* Add `PageQuerySet.private` method as an alias of `not_public` (Mehrdad Moradizadeh)
* Allow setting default attributes on image tags [](adding_default_attributes_to_images) (Jake Howard)
### Bug fixes
* Prevent `PageQuerySet.not_public` from returning all pages when no page restrictions exist (Mehrdad Moradizadeh)
## Upgrade considerations

Wyświetl plik

@ -161,7 +161,7 @@ Wagtail does not allow deforming or stretching images. Image dimension ratios wi
Wagtail provides two shortcuts to give greater control over the `img` element:
**1. Adding attributes to the {% image %} tag**
### 1. Adding attributes to the {% image %} tag
Extra attributes can be specified with the syntax `attribute="value"`:
@ -171,7 +171,9 @@ Extra attributes can be specified with the syntax `attribute="value"`:
You can set a more relevant `alt` attribute this way, overriding the one automatically generated from the title of the image. The `src`, `width`, and `height` attributes can also be overridden, if necessary.
**2. Generating the image "as foo" to access individual properties**
You can also add default attributes to all images (a default class or data attribute for example) - see [](adding_default_attributes_to_images).
### 2. Generating the image "as foo" to access individual properties
Wagtail can assign the image data to another variable using Django's `as` syntax:
@ -228,6 +230,35 @@ Therefore, if you'd added the field `author` to your AbstractImage in the above
(Due to the links in the database between renditions and their parent image, you _could_ access it as `{{ tmp_photo.image.author }}`, but that has reduced readability.)
(adding_default_attributes_to_images)=
## Adding default attributes to all images
We can configure the `wagtail.images` application to specify additional attributes to add to images. This is done by setting up a custom `AppConfig` class within your project folder (i.e. the package containing the top-level settings and urls modules).
To do this, create or update your existing `apps.py` file with the following:
```python
from wagtail.images.apps import WagtailImagesAppConfig
class CustomImagesAppConfig(WagtailImagesAppConfig):
default_attrs = {"decoding": "async", "loading": "lazy"}
```
Then, replace `wagtail.images` in `settings.INSTALLED_APPS` with the path to `CustomUsersAppConfig`:
```python
INSTALLED_APPS = [
...,
"myapplication.apps.CustomImagesAppConfig",
# "wagtail.images",
...,
]
```
Now, images created with `{% image %}` will additionally have `decoding="async" loading="lazy"` attributes. This also goes for images added to Rich Text and `ImageBlock` blocks.
## Alternative HTML tags
The `as` keyword allows alternative HTML image tags (such as `<picture>` or `<amp-img>`) to be used.

Wyświetl plik

@ -11,6 +11,7 @@ class WagtailImagesAppConfig(AppConfig):
label = "wagtailimages"
verbose_name = _("Wagtail images")
default_auto_field = "django.db.models.AutoField"
default_attrs = {}
def ready(self):
register_signal_handlers()

Wyświetl plik

@ -7,6 +7,7 @@ from contextlib import contextmanager
from io import BytesIO
from typing import Union
from django.apps import apps
from django.conf import settings
from django.core import checks
from django.core.cache import InvalidCacheBackendError, caches
@ -826,7 +827,11 @@ class AbstractRendition(ImageFileMixin, models.Model):
def img_tag(self, extra_attributes={}):
attrs = self.attrs_dict.copy()
attrs.update(apps.get_app_config("wagtailimages").default_attrs)
attrs.update(extra_attributes)
return mark_safe("<img{}>".format(flatatt(attrs)))
def __html__(self):

Wyświetl plik

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*
import os
import unittest.mock
from django.apps import apps
from django.conf import settings
from django.core import serializers
from django.test import TestCase
@ -55,6 +57,19 @@ class TestImageChooserBlock(TestCase):
self.assertHTMLEqual(html, expected_html)
def test_render_with_custom_default_attrs(self):
block = ImageChooserBlock()
with unittest.mock.patch.object(
apps.get_app_config("wagtailimages"),
"default_attrs",
new={"decoding": "async", "loading": "lazy"},
):
html = block.render(self.bad_image)
self.assertHTMLEqual(
html,
'<img alt="missing image" src="/media/not-found" width="0" height="0" decoding="async" loading="lazy">',
)
def test_render_missing(self):
block = ImageChooserBlock()
html = block.render(self.bad_image)

Wyświetl plik

@ -1,6 +1,8 @@
import os
import unittest.mock
from django import template
from django.apps import apps
from django.conf import settings
from django.core import serializers
from django.template import engines
@ -99,6 +101,19 @@ class TestImagesJinja(TestCase):
with self.assertRaises(template.TemplateSyntaxError):
self.render('{{ image(myimage, "fill-200×200") }}', {"myimage": self.image})
def test_custom_default_attrs(self):
with unittest.mock.patch.object(
apps.get_app_config("wagtailimages"),
"default_attrs",
new={"decoding": "async", "loading": "lazy"},
):
self.assertHTMLEqual(
self.render(
'{{ image(myimage, "width-200") }}', {"myimage": self.bad_image}
),
'<img alt="missing image" src="/media/not-found" width="0" height="0" decoding="async" loading="lazy">',
)
def test_chaining_filterspecs(self):
self.assertHTMLEqual(
self.render(