Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
The current usage requires configuring the web server via .htaccess, which isn't very portable (many hosting providers are using nginx nowadays). WebP can also be used without web server configuration using the <picture>
element (see https://css-tricks.com/using-webp-images/#article-header-id-3), which is the same mechanism used by the responsive_image module provided in core.
Here's a patch that works in combination with the responsive_image module. Each <source>
entry is duplicated with a copy pointing to the webp URL.
Comments
Comment #2
floretan CreditAttribution: floretan at Wunder commentedUpdated patch to handle the case where originally a single source is originally available. In this case the responsive_image module generates a single image tag, which we want to prevent since we have at least two sources.
Comment #3
floretan CreditAttribution: floretan at Wunder commentedI didn't properly remove the image style derivatives while testing. This patch works only if the webp images have been generated already, I'll update the patch to handle the case where the first call is done to the webp url.
Comment #4
Bart Vanhoutte CreditAttribution: Bart Vanhoutte at Duo commentedUpdated README.md to reflect this feature.
Comment #5
floretan CreditAttribution: floretan at Wunder commentedThe two last pieces that needed to be added were:
The attached patch should do just that and seems to be working fine.
Comment #6
floretan CreditAttribution: floretan at Wunder commentedOne important limitation of the current patch: it doesn't work in combination with the imageapi_optimize module.
Comment #7
Bart Vanhoutte CreditAttribution: Bart Vanhoutte at Duo commentedBecause it tries to optimize WebP images? Or am I missing something?
Comment #8
mansspams CreditAttribution: mansspams at Wunder commentedUpdated patch that fixes
$derivative_uri
is undefined variable error.Comment #9
mansspams CreditAttribution: mansspams at Wunder commentedNope, wrong fix previously.
Comment #10
thejimbirch CreditAttribution: thejimbirch at Kanopi Studios commentedThe patch in #9 in combination with a responsive image seems to be outputting correctly, but the image is giving me a page not found.
Any suggestions on how to proceed?
Thanks!
Comment #11
mherchel@thejimbirch Make sure your GD library supports it. Check your watchdog log for any PHP errors. The error I seem to be getting is
Error: Call to undefined function Drupal\webp\imagewebp() in Drupal\webp\Webp->createWebpCopy()
.You can also run
gd_info()
to get output to see if WebP is supported. http://php.net/manual/en/function.gd-info.phpComment #12
sahaj CreditAttribution: sahaj commentedI have similar issue as @thejimbirch, the image code is rendered correctly (i.e. sites/default/files/styles/pack_card_thumb/public/2018-06/pic-d4b6b8e55f3ca6a78486e6ee79575b83.webp?h=7540f041&itok=S72y1wrq), and the image is generated in that folder, only it is not displayed on the page.
My GD library is supporting, according to PHPinfo.
Comment #13
JohnAlbinI'm not seeing what sahaj is seeing. My problem sounds similar to thejimburch's bug description.
In my case this is because I have the imageapi_optimize module installed. In webp's RouteSubscriber.php file, there is a specific exception made so that public image styles do NOT make webp versions if the imageapi_optimize module is installed.
I don't know what the purpose of those lines are, but if I remove them, the image gets created as expected. I'm not sure if removing those lines is the correction solution, but this new patch makes that change. Otherwise, it is the same as the patch in #9.
Comment #14
JohnAlbinComment #15
JohnAlbin[Edit: sorry for the issue thrashing. I was trying to get the issue queue to stop showing me as the "author" in the git commit message since I barely modified the code that you all wrote.]
Comment #16
JohnAlbinOne weird thing that this latest patch does is it will generate a derivative example.jpg and an example.jpg.webp file, but the responsive image HTML references example.webp. So, while the "example.webp" image doesn't actually exist in the files directory, the web server still serves the example.jpg.webp file. It's odd, but it doesn't cause me any issues. However, maybe that is what sahaj is experiencing? Sahaj, can you check if the file written to the files directory has a different file name than what is put in the HTML?
Comment #17
saschaeggi@johnalbin @thejimbirch @sahaj I fixed the filename issue of the generated webp file from e.g. *.jpg.webp to *.webp and also added a check if the file exists before adding an entry to the responsive image array. works for me, should also work for you too.
Comment #18
RaphaelBriskie CreditAttribution: RaphaelBriskie as a volunteer commentedThis patch needs to check if the srcset attribute exists so it doesn't throw errors.
For example, when used in conjunction with the Lazyload Images module (https://www.drupal.org/project/lazyload_images) it should really be using the data-srcset attribute.
Comment #19
saschaeggi@PaphaelBriskie you could to something like this in your theme:
Or just use your proposed function in your theme to override the default module's behavior -> THEME_preprocess_responsive_image() {}
Comment #20
saschaeggiThis is an update to my previous patch.
Comment #21
saschaeggiAnd another round as there was an issue with applying the previous patch, sorry.
Comment #22
saschaeggiComment #23
szeidler CreditAttribution: szeidler at Ramsalt Lab commentedPatch in #21 was working great for me.
I tested it also in a setup, where we're lazyloading images with the Blazy module. Here I'm getting the following error.
Error: Call to a member function value() on null in webp_preprocess_responsive_image() (line 35 of modules/contrib/webp/webp.module).
While investigating i found, that the blazy module replaces the default
srcset
attribute withdata-srcset
, to apply their lazyloading processing.Although it might not be the nicest solution and not directly this module's responsibility, I'm currently working around this by checking for the existence of the attribute, like in the following patch.
Comment #24
scott_euser CreditAttribution: scott_euser as a volunteer commentedComment #25
scott_euser CreditAttribution: scott_euser as a volunteer commentedI have tried to review this as thoroughly as possible, checked
markup and validated dev tools network download of webp for each of the following scenarios:
No php notices or warnings any more in any scenario.
All working well and producing expected markup, eg:
What I did notice is if you have a Media entity referencing lets say Responsive Style A then you delete Responsive Style A, the responsive image module continues to produce a picture element with no styles, just image tag. $variables['sources'] is then undefined. Patch wraps this in isset.
Patch also checks that srcset is actually existing in case another unknown module removes srcset in favour of something other than data-srcset.
Just a couple minor coding standards nitpicks.
Comment #26
lindsay.wils CreditAttribution: lindsay.wils commentedI have just tried to apply the latest patch with composer and it failed without any substantial messaging, other than it failed. Not sure of the correct procedure for logging this. Has anyone else successfully applied the patch? thanks. really interested in this feature
Comment #27
alexiscott CreditAttribution: alexiscott commentedThe patch applied for me with
Comment #28
Xen CreditAttribution: Xen at Reload for Reload commentedPatch doesn't like files with multiple extensions (file.jpeg.jpg for instance). New patch attached.
Comment #29
alexmoreno CreditAttribution: alexmoreno at Acquia commentedpatch applies for me, but I don't see the markup being generated.
This patch makes a lot of sense as it's the recommended way to serve webp images
Comment #30
iamdroid CreditAttribution: iamdroid commented@alexmoreno do you use image style mode in responsive image style settings?
markup provided only in image style mode because only in this mode used
picture
tag.in sizes mode used
img
tag withscrset
attribute, so markup can't be provided.Comment #31
alexmoreno CreditAttribution: alexmoreno at Acquia commentedIgnore my comment, you need to have responsive images installed and breakpoints configured.
Some docs would be good, but we can do that later updating the Readme
Comment #32
alexmoreno CreditAttribution: alexmoreno at Acquia commentedComment #33
alexmoreno CreditAttribution: alexmoreno at Acquia commentedI found some issues in some long paths with arguments. This is what I changed:
Also added some phpunits:
I'll upload a new patch tomorrow at some point in the day.
Comment #34
alexmoreno CreditAttribution: alexmoreno at Acquia commentedComment #35
alexmoreno CreditAttribution: alexmoreno at Acquia commentedComment #37
alexmoreno CreditAttribution: alexmoreno at Acquia commentedthis has been merged now. It includes the unit tests as per the interdiff, added just for reference.
Thanks everyone
Comment #39
C. S. Comfort CreditAttribution: C. S. Comfort as a volunteer and commentedWith the latest 8.x-1.x-dev release, I'm finding that when multiple paths are present the resulting
srcset
only includes one properly generated webp image path; the other(s) keep the original image format. For example:This looks to be the result of the
getWebpFilename($filepath)
method that is attempting to parse the$filepath
as a URL even though it's either a single path or a comma-separated set of paths that may also include pixel density parameters (e.g. 2x). As a result, I've run into some inconsistent behavior when the browser tries to load the appropriate image -- sometimes it loads the webp version, and others the original full-sized version. I'm not sure it's necessary to havegetWebpFilename()
parse the incoming string as a URL; rather, it seems simpler to just replace the original file extension with the webp version (which I believe was suggested in an earlier patch).This is my first contributed patch, so please let me know if there's anything that I should do differently to keep with community expectations/guidelines.
Comment #40
C. S. Comfort CreditAttribution: C. S. Comfort as a volunteer and commentedUpdated my previous patch to include the appropriate (and accordingly named) unit tests.
Comment #41
alexmoreno CreditAttribution: alexmoreno at Acquia commentedwill this work as well for the extensions in Capital? Just double checking if you tested that
Apart of that, looks great, thanks a lot for your contribution CS. Putting this back to needs review. I would have preferred to open a new ticket, but let's move forward
Comment #42
alexmoreno CreditAttribution: alexmoreno at Acquia commentedComment #43
Xen CreditAttribution: Xen at Reload for Reload commentedFrom the docs:
str_ireplace — Case-insensitive version of str_replace()
So yes, I would assume it works with extensions in capital.
Comment #44
C. S. Comfort CreditAttribution: C. S. Comfort as a volunteer and commentedAs Xen mentioned, yes,
str_ireplace
should accommodate varying usage of capitals in the file extension. We could update the test assertions to explicitly test a number of variations, though currently the last four passing assertions do see a.JPG
in the string.Comment #45
acontia CreditAttribution: acontia commentedTested patch in #40.
It works for me. It solves the issue where multiple sources are specified as a single string separated by commas ", ". Without the patch they are not parsed correctly.
I think the patch might fail if the filename contains ".jpg". For example test.jpg.jgp would converted to test.webp.webp as opposed to test.jpg.webp
Maybe the regular expression should check that the character after ".jpg" is an "?" or ", " or end of string?
Comment #46
Xen CreditAttribution: Xen at Reload for Reload commentedOK, I should pay attention here.
Patch #39/#40 reverts the fix for handling multiple extensions (as seen in the wild) I added in #28. We only want to fix the last extension, that's why I changed str_ireplace to preg_replace.
And in order to make the replacement case insensitive, there's no need for duplicating the extensions,
preg_replace('/\.(png|jpg|jpeg)(\\?.*)?$/i', '.webp\\2', $path);
will do that, and also cover the "JpEg" case.For those not reading regex,
(\\?.*)?$
translates to "an optional questionmark followed by anything, at the end of string", and the \\2 then replaces whatever that parenthesis matched into the result string. In other words, the regex matches a dot, any of the extensions and then an optional query argument, and carries the query over to the result.Comment #47
renguer0 CreditAttribution: renguer0 as a volunteer commentedI can't apply this patches because it shows corrupted patch at lines 62 (#39) and 102 (#40). I applied this manually but still don't working in my site (only on PNG images).I'm applying them into lastest dev version. Maybe there could be something wrong in some another config? This is really weird.
EDIT: I see that errors with webp conversion on JPG files are caused by my hosting that's blocking that action. The module only works on PNG files.
Maybe someone knows if I can avoid it. I'm dealing with that and thinking into moving out from there because of this issue.
Sorry about this OT, maybe this answer helps someone in the same situation.
Comment #48
mherchel@renguer0 - Yeah, it's a little off topic, but still relevant. It might be best to document the errors in another issue (so maybe the module can surface issues to the user beforehand).
Can you create an issue with 1) your host info, 2) errors you're seeing, 3) if you're using GD or imagemagic 4) relevant info from phpinfo() including GD or ImageMagick info?
Comment #49
renguer0 CreditAttribution: renguer0 as a volunteer commentedForget it @mherchel but thanks anyway. I'm in SiteGround that blocks the generation of webp (only enables that from PNG) on their basic plan. I'm moving to Digital Ocean and manage the server by my own, the module with last patch works well for me.
This answer maybe can helps to someone that have the same problem. I lost a lot of time trying different things and falling into a headache :P
I hope that merging the last patch with the recomendations from #46 by Xen, could resolve that issue.
Comment #50
saschaeggi@xen can you create a new patch with your changes?
Comment #51
alexmoreno CreditAttribution: alexmoreno at Acquia commentedcould someone add a patch with the latest recommendations if needed? If not there is not really anything to do here. Could you have time for that @Xen?
Thanks.
Comment #52
Xen CreditAttribution: Xen at Reload for Reload commented@saschaeggi/@alexmoreno
I'm trying, but first I have to figure out what the latest patch really does in order to not break that.
Comment #53
alexmoreno CreditAttribution: alexmoreno at Acquia commentedI built some tests for that part, they should come handy for the changes you are trying to do. Shout if I can help somehow
Thanks a lot :-)
Comment #54
Xen CreditAttribution: Xen at Reload for Reload commentedThere.
Comment #55
Xen CreditAttribution: Xen at Reload for Reload commentedComment #56
saschaeggi@xen your patch works like a charm for me
Comment #57
saschaeggi@xen can you include this into dev?
Comment #58
Xen CreditAttribution: Xen at Reload for Reload commented@saschaeggi
I'm not a maintainer on this project, so no. alexmoreno can.
Comment #59
alexmoreno CreditAttribution: alexmoreno at Acquia commentedI’ll get it done this weekend, it was in my todo list
Comment #60
saschaeggi@alexmoreno any update on this?
Comment #61
alexmoreno CreditAttribution: alexmoreno at Acquia commentedsorry, Drupalcon and work got in the middle. Will get it reviewed and merged soon
Comment #63
alexmoreno CreditAttribution: alexmoreno at Acquia commentedmerged, thanks all
Comment #64
alexmoreno CreditAttribution: alexmoreno at Acquia commented