Disable AVIF when ImageMagick does not support AVIF transparency#2540
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## trunk #2540 +/- ##
==========================================
+ Coverage 70.10% 70.38% +0.28%
==========================================
Files 91 91
Lines 7823 7850 +27
==========================================
+ Hits 5484 5525 +41
+ Misses 2339 2325 -14
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Unlinked AccountsThe following contributors have not linked their GitHub and WordPress.org accounts: @xtecneo, @wes-davis. Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases. If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
| return false; | ||
| } | ||
|
|
||
| $supported = version_compare( $imagick_version, '6.9.12-68', '>=' ); |
There was a problem hiding this comment.
The -68 here. Is that compared right? In looking at https://www.php.net/manual/en/function.version-compare.php it seems this would cause the version to be considered less than 6.9.12-dev.
There was a problem hiding this comment.
Added tests for different version strings in d76f49b.
| $avif_supported = webp_uploads_mime_type_supported( 'image/avif' ); | ||
| $webp_supported = webp_uploads_mime_type_supported( 'image/webp' ); | ||
| $selected = webp_uploads_get_image_output_format(); | ||
| $avif_supported = webp_uploads_mime_type_supported( 'image/avif' ); |
There was a problem hiding this comment.
I think this should actually be returning false if webp_uploads_imagick_avif_transparency_supported() is returning false.
This is because the plugin will still default to AVIF otherwise at present, even when it is not fully supported:
performance/plugins/webp-uploads/helper.php
Lines 30 to 38 in 4fdf1e9
There was a problem hiding this comment.
If webp_uploads_mime_type_supported() returns false for AVIF when webp_uploads_imagick_avif_transparency_supported() fails, showing a separate settings warning specifically for AVIF transparency support would make the notice logic more complex.
If we are okay with showing the existing generic message that AVIF support is not available, then I think this is fine.
@westonruter you can take over the PR if we want to release today.
There was a problem hiding this comment.
I was thinking of something like "AVIF is supported, but not fully: transparency support is lacking."
There was a problem hiding this comment.
Hmm in that case should we allow selecting AVIF.
No we will keep it disabled.
There was a problem hiding this comment.
Exactly. If AVIF isn't fully supported, it is not safe to allow it to be the default.
There was a problem hiding this comment.
Or even to be selected, really.
There was a problem hiding this comment.
Okay yes the current logic does not allow it to be selected.
| $avif_supported = webp_uploads_mime_type_supported( 'image/avif' ) && webp_uploads_imagick_avif_transparency_supported(); | ||
| $output_format = $avif_supported ? webp_uploads_get_image_output_format() : 'webp'; |
There was a problem hiding this comment.
I think this should actually be returning false if webp_uploads_imagick_avif_transparency_supported() is returning false.
Let's keep them separate so we can display two different inline warning based on the specific failure condition.
|
@mindctrl Once this is ready for review, please verify whether it in addresses the issue you raised. 🙇♂️ |
|
|
||
| // Check the selected output format. | ||
| $output_format = webp_uploads_mime_type_supported( 'image/avif' ) ? webp_uploads_get_image_output_format() : 'webp'; | ||
| $avif_supported = webp_uploads_mime_type_supported( 'image/avif' ) && webp_uploads_imagick_avif_transparency_supported(); |
There was a problem hiding this comment.
What about sites that don't have ImageMagick and use GD instead, which supports transparent AVIFs? Maybe we should add a check that _wp_image_editor_choose( array( 'mime_type' => 'image/avif' ) ) resolves to WP_Image_Editor_Imagick?
Co-authored-by: westonruter <westonruter@git.wordpress.org>
68f2d66 to
9095d39
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates the webp-uploads plugin to avoid generating/allowing AVIF when the server’s ImageMagick/Imagick stack is known to mishandle AVIF transparency (pre–6.9.12-68). It introduces a version-based transparency capability check, disables the AVIF option in the settings UI when transparency is unsupported, and adds test coverage around the new behavior.
Changes:
- Add helper functions to distinguish AVIF format support vs AVIF transparency support, including an ImageMagick version comparison.
- Update the settings UI to disable AVIF and show a warning notice when transparency support is lacking.
- Add/extend PHPUnit tests and shared test helpers for mocking transparency support and validating fallbacks.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/webp-uploads/helper.php | Adds AVIF support/transparency support helpers and ImageMagick version parsing to gate AVIF usage. |
| plugins/webp-uploads/settings.php | Disables AVIF in the dropdown and shows a warning notice when transparency is not supported. |
| plugins/webp-uploads/tests/test-helper.php | Adds tests for transform fallback behavior and version parsing. |
| plugins/webp-uploads/tests/test-settings.php | Adds a settings UI test asserting AVIF is disabled and warning text is shown. |
| plugins/webp-uploads/tests/data/class-testcase.php | Adds a shared test helper for mocking AVIF transparency support. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if ( null === $imagick_version && extension_loaded( 'imagick' ) && class_exists( 'Imagick' ) ) { | ||
| $imagick_version = Imagick::getVersion(); | ||
| $imagick_version = $imagick_version['versionString']; | ||
| } | ||
|
|
||
| if ( null !== $imagick_version && '' !== $imagick_version && (bool) preg_match( '/\d+(?:\.\d+)+(?:-\d+)?/', $imagick_version, $matches ) ) { | ||
| $imagick_version = $matches[0]; | ||
| } | ||
|
|
||
| if ( null === $imagick_version || '' === $imagick_version ) { | ||
| return false; | ||
| } |
| if ( ! webp_uploads_mime_type_supported( 'image/avif' ) ) { | ||
| $this->markTestSkipped( 'Mime type image/avif is not supported.' ); | ||
| } |
| if ( ! webp_uploads_mime_type_supported( 'image/avif' ) ) { | ||
| $this->markTestSkipped( 'Mime type image/avif is not supported.' ); | ||
| } |
mindctrl
left a comment
There was a problem hiding this comment.
Nice improvement. Maybe we could improve GD-based test coverage, but that's not a blocker IMO.
| $selected = webp_uploads_get_image_output_format(); | ||
| $avif_supported = webp_uploads_avif_supported(); | ||
| $avif_transparency_supported = webp_uploads_avif_transparency_supported(); | ||
| $webp_supported = webp_uploads_mime_type_supported( 'image/webp' ); | ||
|
|
| if ( 'image/avif' === $mime_type ) { | ||
| $editor = _wp_image_editor_choose( array( 'mime_type' => 'image/avif' ) ); | ||
| if ( false === $editor ) { | ||
| return false; | ||
| } | ||
| if ( is_a( $editor, WP_Image_Editor_GD::class, true ) ) { | ||
| return function_exists( 'imageavif' ); | ||
| } | ||
| if ( is_a( $editor, WP_Image_Editor_Imagick::class, true ) && class_exists( 'Imagick' ) ) { | ||
| return 0 !== count( Imagick::queryFormats( 'AVIF' ) ); | ||
| } | ||
| return webp_uploads_avif_supported() && webp_uploads_avif_transparency_supported(); | ||
| } |
westonruter
left a comment
There was a problem hiding this comment.
Review by Claude (Opus 4.8), run by @westonruter via Claude Code. Inline notes below are AI-generated and posted on his behalf.
Overall this is solid and correctly solves #2237 — the 6.9.12-68 threshold, the version regex, and the data-provider coverage are all good. The 17 affected tests pass and PHPStan is clean on the changed lines. A few design/consistency notes follow; none are blockers.
| if ( is_a( $editor, WP_Image_Editor_Imagick::class, true ) && class_exists( 'Imagick' ) ) { | ||
| return 0 !== count( Imagick::queryFormats( 'AVIF' ) ); | ||
| } | ||
| return webp_uploads_avif_transparency_supported(); |
There was a problem hiding this comment.
🤖 Claude (Opus 4.8), via @westonruter
This silently changes the meaning of webp_uploads_mime_type_supported('image/avif') from "AVIF format supported" to "AVIF and transparency supported", on a function documented @since 2.0.0 as a plain format check.
A side effect: settings.php:113 still calls webp_uploads_mime_type_supported('image/avif') for the "neither format supported" gate, while the dropdown in webp_uploads_generate_avif_webp_setting_callback() now uses webp_uploads_avif_supported() (raw support). So two divergent notions of "AVIF supported" now live in the same file. In the (rare) case where AVIF works, transparency doesn't, and WebP is unsupported, line 113 hides the fallback settings field while the dropdown still renders AVIF + a transparency warning.
Consider keeping webp_uploads_mime_type_supported() purely about format support and handling the transparency gate explicitly in webp_uploads_get_upload_image_mime_transforms(), so the overload is a deliberate choice rather than an emergent one.
There was a problem hiding this comment.
🤖 Claude (Opus 4.8), via @westonruter
Correction to the above: I overstated this. The dropdown's disabled state and the "neither format supported" gate both key off $avif_fully_supported ($avif_supported && $avif_transparency_supported), which is transparency-aware — the same notion as line 113's webp_uploads_mime_type_supported('image/avif'). The two are functionally equivalent:
- Line 113:
wp_image_editor_supports('image/avif') && webp_uploads_avif_transparency_supported() - Callback:
webp_uploads_avif_supported() && webp_uploads_avif_transparency_supported()
(wp_image_editor_supports() is essentially _wp_image_editor_choose() !== false under the hood, so the preconditions align too.)
So the "rare inconsistency" I described — AVIF works, transparency doesn't, WebP unsupported → line 113 hides the field while the dropdown still renders AVIF — can't actually happen. In that case both evaluate to not-available and hide consistently. The raw $avif_supported is used only to choose which warning to show ("not available" vs "transparency lacking"), not to gate the dropdown or field visibility. I'm retracting the divergence claim.
The only point that still stands is the narrower one: webp_uploads_mime_type_supported('image/avif') had its meaning changed (a @since 2.0.0 function now folds in transparency), so it's worth confirming that overload is intentional — but it does not produce divergent behavior.
There was a problem hiding this comment.
I think its fine to change the meaning/behavior here, but it would be nice to add a single line to the readme release notes that specifies the new behavior
There was a problem hiding this comment.
🤖 Claude (Opus 4.8), via @westonruter
Documented in 272a61f. Rather than the readme (the function-level change felt better captured at the source), I added a @since n.e.x.t note to webp_uploads_mime_type_supported(): "AVIF is now only reported as supported when the server can also encode transparent AVIF images." Happy to also add a readme release-notes line if you'd prefer it there as well. Credited you as co-author.
| // Check the selected output format. | ||
| $output_format = webp_uploads_mime_type_supported( 'image/avif' ) ? webp_uploads_get_image_output_format() : 'webp'; | ||
| $avif_supported = webp_uploads_mime_type_supported( 'image/avif' ); | ||
| $output_format = $avif_supported ? webp_uploads_get_image_output_format() : 'webp'; |
There was a problem hiding this comment.
🤖 Claude (Opus 4.8), via @westonruter
Likely out of scope, but noting it: just below, the 'image/avif' => array('image/avif') transform (line 37) is unconditional, so a directly uploaded transparent AVIF still gets AVIF sub-sizes regenerated even when transparency is unsupported — those sub-sizes would still lose transparency. The PR fixes the JPEG/PNG/WebP→AVIF output path but not this self-transform case. Probably fine to leave, but worth a note in #2237 as a known limitation.
Add a comment clarifying that GD's imageavif() preserves alpha, so AVIF support implies transparency support, and that the transparency regression being guarded against is specific to older ImageMagick. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build webp_uploads_avif_transparency_supported() on top of webp_uploads_avif_supported() instead of re-implementing the editor selection, false-editor guard, and GD branch. This also removes the redundant webp_uploads_imagick_avif_supported() call, since that check is now subsumed by the support gate. Behavior is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…forms() Inline the AVIF support check back into the ternary; the $avif_supported variable was referenced only once, and this restores the function to be identical to trunk. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
||
| /** | ||
| * Checks if Imagick has AVIF transparency support. | ||
| * |
There was a problem hiding this comment.
add an inline comment explaining what this function does, why this check is added, namely that Imagick before 6.9.12-68 supports AVIF but not transparencies in AVIF
There was a problem hiding this comment.
🤖 Claude (Opus 4.8), via @westonruter
Done in 703795d. Expanded the webp_uploads_imagick_avif_transparency_supported() docblock to explain that ImageMagick before 6.9.12-68 reports AVIF support but drops the alpha channel when encoding — so transparent images silently lose transparency — and that 6.9.12-68 is the version that fixed it (with a link to #2237). Also added an inline comment at the version_compare() check noting the same. Credited you as co-author.
adamsilverstein
left a comment
There was a problem hiding this comment.
left a few non blocking suggestions
Explain in webp_uploads_imagick_avif_transparency_supported() that older ImageMagick versions report AVIF support but drop the alpha channel when encoding, silently losing transparency, and that this was fixed in 6.9.12-68 (the gated minimum version). Co-authored-by: adamsilverstein <adamsilverstein@git.wordpress.org> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…supported() Add a @SInCE n.e.x.t note clarifying that image/avif is now only reported as supported when the server can also encode transparent AVIF images. Co-authored-by: adamsilverstein <adamsilverstein@git.wordpress.org> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Fixes #2237
Relevant technical choices
This PR adds a helper function to detect whether the installed ImageMagick version is older than
6.9.12-68.If the ImageMagick version does not fully support AVIF transparency, the AVIF option is disabled and a warning notice is shown on the settings screen.
See #2245 (comment) for why
6.9.12-68was chosen, and see the discussion in PR #2245 for additional context.Screenshots
Use of AI Tools
Used Codex to review the code and tests.