Skip to content

Disable AVIF when ImageMagick does not support AVIF transparency#2540

Merged
westonruter merged 15 commits into
WordPress:trunkfrom
b1ink0:add/imagemagick-old-version-avif-transparency-loss-warning
Jun 30, 2026
Merged

Disable AVIF when ImageMagick does not support AVIF transparency#2540
westonruter merged 15 commits into
WordPress:trunkfrom
b1ink0:add/imagemagick-old-version-avif-transparency-loss-warning

Conversation

@b1ink0

@b1ink0 b1ink0 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

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-68 was chosen, and see the discussion in PR #2245 for additional context.

Screenshots

Screenshot 2026-06-19 at 12 41 44 AM

Use of AI Tools

Used Codex to review the code and tests.

@b1ink0 b1ink0 added this to the webp-uploads n.e.x.t milestone Jun 18, 2026
@b1ink0 b1ink0 requested a review from adamsilverstein as a code owner June 18, 2026 19:13
@b1ink0 b1ink0 added [Type] Bug An existing feature is broken [Plugin] Modern Image Formats Issues for the Modern Image Formats plugin (formerly WebP Uploads) labels Jun 18, 2026
@b1ink0 b1ink0 requested a review from westonruter June 18, 2026 19:13
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 79.06977% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.38%. Comparing base (98437a5) to head (272a61f).
⚠️ Report is 2 commits behind head on trunk.

Files with missing lines Patch % Lines
plugins/webp-uploads/helper.php 77.77% 6 Missing ⚠️
plugins/webp-uploads/settings.php 81.25% 3 Missing ⚠️
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     
Flag Coverage Δ
multisite 70.38% <79.06%> (+0.28%) ⬆️
single 35.59% <46.51%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

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 props-bot label.

Unlinked Accounts

The 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.

Unlinked contributors: xtecneo, wes-davis.

Co-authored-by: b1ink0 <b1ink0@git.wordpress.org>
Co-authored-by: westonruter <westonruter@git.wordpress.org>
Co-authored-by: mindctrl <mindctrl@git.wordpress.org>
Co-authored-by: adamsilverstein <adamsilverstein@git.wordpress.org>
Co-authored-by: paulgibbs <djpaul@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Comment thread plugins/webp-uploads/helper.php Outdated
return false;
}

$supported = version_compare( $imagick_version, '6.9.12-68', '>=' );

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it seems to work: https://3v4l.org/5NVBB

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added tests for different version strings in d76f49b.

Comment thread plugins/webp-uploads/settings.php Outdated
$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' );

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

// Check the selected output format.
$output_format = webp_uploads_mime_type_supported( 'image/avif' ) ? webp_uploads_get_image_output_format() : 'webp';
$default_transforms = array(
'image/jpeg' => array( 'image/' . $output_format ),
'image/webp' => array( 'image/' . $output_format ),
'image/avif' => array( 'image/avif' ),
'image/png' => array( 'image/' . $output_format ),
);

@b1ink0 b1ink0 Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of something like "AVIF is supported, but not fully: transparency support is lacking."

@b1ink0 b1ink0 Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm in that case should we allow selecting AVIF.
No we will keep it disabled.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. If AVIF isn't fully supported, it is not safe to allow it to be the default.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or even to be selected, really.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay yes the current logic does not allow it to be selected.

Comment thread plugins/webp-uploads/helper.php Outdated
Comment on lines +31 to +32
$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';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@westonruter

Copy link
Copy Markdown
Member

@mindctrl Once this is ready for review, please verify whether it in addresses the issue you raised. 🙇‍♂️

Comment thread plugins/webp-uploads/helper.php Outdated

// 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();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in c2011a9.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes in c2011a9 look good to me

Comment thread plugins/webp-uploads/settings.php Outdated
b1ink0 and others added 2 commits June 30, 2026 19:23
Co-authored-by: westonruter <westonruter@git.wordpress.org>
@b1ink0 b1ink0 force-pushed the add/imagemagick-old-version-avif-transparency-loss-warning branch from 68f2d66 to 9095d39 Compare June 30, 2026 14:07
@b1ink0 b1ink0 requested a review from westonruter June 30, 2026 16:09
@westonruter westonruter requested review from Copilot and mindctrl and removed request for mindctrl June 30, 2026 16:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +578 to +589
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;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e08e821.

Comment on lines +53 to +55
if ( ! webp_uploads_mime_type_supported( 'image/avif' ) ) {
$this->markTestSkipped( 'Mime type image/avif is not supported.' );
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e08e821.

Comment on lines +479 to +481
if ( ! webp_uploads_mime_type_supported( 'image/avif' ) ) {
$this->markTestSkipped( 'Mime type image/avif is not supported.' );
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e08e821.

Comment thread plugins/webp-uploads/tests/data/class-testcase.php

@mindctrl mindctrl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice improvement. Maybe we could improve GD-based test coverage, but that's not a blocker IMO.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment on lines +156 to 160
$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' );

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in c69e471.

Comment on lines 361 to 363
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();
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in c69e471.

Comment thread plugins/webp-uploads/settings.php

@westonruter westonruter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

Comment thread plugins/webp-uploads/helper.php Outdated
Comment thread plugins/webp-uploads/helper.php Outdated
Comment thread plugins/webp-uploads/helper.php
Comment thread plugins/webp-uploads/helper.php Outdated
// 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';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

westonruter and others added 4 commits June 30, 2026 11:09
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.
*

@adamsilverstein adamsilverstein Jun 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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 adamsilverstein left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left a few non blocking suggestions

westonruter and others added 2 commits June 30, 2026 15:08
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>
@westonruter westonruter merged commit e5098bf into WordPress:trunk Jun 30, 2026
20 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Plugin] Modern Image Formats Issues for the Modern Image Formats plugin (formerly WebP Uploads) [Type] Bug An existing feature is broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Transparent backgrounds lost when converting to AVIF under certain conditions

5 participants