Reputation: 307
I'm trying to implement lazy loading for my blog post images, but I'm utilizing RichTextField for my blog posts, so I'm unable to specify each image tag like the Wagtail-LazyImages documentation suggets I should.
According to the Wagtail Docs on RichTextField internals, an image may be stored as <embed embedtype="image" id="10" alt="A pied wagtail" format="left" />
but upon rendering is translated to <img alt="A pied wagtail" class="richtext-image left" height="294" src="/media/images/pied-wagtail.width-500_ENyKffb.jpg" width="500">
meaning there's not every any explicit tag usage like LazyImages is looking for.
This is more of a conceptual question, as I'm just not sure where in the process to hook into Wagtail's RTF processing.
Could I utilize the register_rich_text_features hook to make a new "feature" for lazy images that will then use the lazyimages class?
Upvotes: 1
Views: 494
Reputation: 188
I solved this by subclassing Format(Changing rich text representation) in image_formats.py
file. I overwrote its image_to_html
method to replace 'src'
attribute with placeholder and add 'data-src'
attribute.
Don't forget to add lazy load library like lazysizes before closing </body>
tag.
from django.utils.html import format_html
from django.utils.html import escape
from wagtail.images.formats import Format, register_image_format
from wagtail.images.shortcuts import get_rendition_or_not_found
class LazyImageFormat(Format):
def image_to_html(self, image, alt_text, extra_attributes=None):
if extra_attributes is None:
extra_attributes = {}
rendition = get_rendition_or_not_found(image, self.filter_spec)
#Placeholder scaling based on image height. Needed ONLY if you use this SVG "loading" placeholder.
svg_width = rendition.width//2
svg_height = rendition.height//2
load_scale = rendition.height//100
#Overwriting 'src' and adding 'data-src' attribute. 'src' - can be any placeholder value
extra_attributes['src'] = format_html('''data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 {} {}'%3E%3Ccircle cx='{}' cy='{}' fill='none' stroke='%23393939' stroke-width='{}' r='{}' stroke-dasharray='{} {}' transform='rotate(175 50 50)'%3E%3CanimateTransform attributeName='transform' type='rotate' repeatCount='indefinite' dur='2s' values='0 {} {};360 {} {}' keyTimes='0;1'/%3E%3C/circle%3E%3C/svg%3E''',
rendition.width, rendition.height, svg_width, svg_height, 5*load_scale, 15*load_scale, 70*load_scale, 25*load_scale, svg_width, svg_height, svg_width, svg_height)
extra_attributes['data-src'] = rendition.url
extra_attributes['alt'] = escape(alt_text)
if self.classnames:
extra_attributes['class'] = "%s" % escape(self.classnames)
return rendition.img_tag(extra_attributes)
#register our custom LazyImageFormat and add 'lazyload' class
register_image_format(LazyImageFormat('lazy_fullwidth', 'Centered-1000 lazy', 'richtext-image centered lazyload', 'width-1000'))
register_image_format(LazyImageFormat('lazy_original', 'Original lazy', 'richtext-image centered lazyload', 'original'))
Upvotes: 2