-
Notifications
You must be signed in to change notification settings - Fork 140
Prevent transparency loss in AVIF by falling back to WebP on older ImageMagick #2245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Prevent transparency loss in AVIF by falling back to WebP on older ImageMagick #2245
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## trunk #2245 +/- ##
==========================================
- Coverage 69.17% 68.34% -0.84%
==========================================
Files 90 94 +4
Lines 7708 7821 +113
==========================================
+ Hits 5332 5345 +13
- Misses 2376 2476 +100
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
plugins/webp-uploads/hooks.php
Outdated
| $imagick = $image_property->getValue( $editor ); | ||
|
|
||
| if ( $imagick instanceof Imagick ) { | ||
| wp_cache_set( 'webp_uploads_image_has_transparency', (bool) $imagick->getImageAlphaChannel(), 'webp-uploads' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this set here in the cache since this function runs first and then later webp_uploads_get_image_output_format() runs to then read the value from the cache? This seems perhaps brittle. Normally setting and getting a cache value would happen in the context of the same function, not across separate functions, right? It feels like there may not be guarantees that the cached value would be set when it is checked for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it works but is definitely brittle. The other approach I can think of is using a global variable or a transient with a short expiration time to store the transparency status and hash of any uploaded file for the current request, and then using it in the webp_uploads_filter_image_editor_output_format to determine the output format. If you have any ideas for a temporary storage that can be used within the same request, I’d appreciate that.
@adamsilverstein if you also have a better idea to handle this case, I’d appreciate that as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If these are both part of the same request, perhaps you could apply a filter inside the webp_uploads_filter_image_editor_output_format function, then add a filter here to set the value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are multiple approaches. I came up with this to solve it:
The most elegant way is to replace the WP_Image_Editor_Imagick class with a custom class WebP_Uploads_Image_Editor_Imagick, which can be used to detect transparency and provide access to the protected variable.
But this will interfere with other plugins if they are trying to use their own custom class. I was thinking of just dynamically extending any custom classes extended from the WP_Image_Editor_Imagick class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If these are both part of the same request, perhaps you could apply a filter inside the webp_uploads_filter_image_editor_output_format function, then add a filter here to set the value?
The issue I faced was with the subsize-image generation. The webp_uploads_filter_image_editor_output_format filter is called with an empty filename, so with this approach the sub-size images were getting generated as AVIF.
Because of that, the only way to check the current processing image calling the output-format filter is to access the $image of the image-editor instance that is processing it. But since the core does not expose the image-editor instance through globals or filters, there seems to be no way to determine the currently processed image. To solve this, the only idea I could come up with was using our own custom Image Editor class.
I have implemented the mentioned approach in this commit 2247b61.
cc: @adamsilverstein
plugins/webp-uploads/hooks.php
Outdated
| $reflection = new ReflectionClass( $editor ); | ||
| $image_property = $reflection->getProperty( 'image' ); | ||
| if ( PHP_VERSION_ID < 80100 ) { | ||
| $image_property->setAccessible( true ); | ||
| } | ||
| $imagick = $image_property->getValue( $editor ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's too bad that the image property is protected. Note how in the Image Placeholder plugin it actually extends WP_Image_Editor_Imagick with a Dominant_Color_Image_Editor_Imagick which it then uses. This is problematic though since multiple plugins can't each register their own editor classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did try to create an anonymous class and added a method to expose the image property, but the Reflection API seemed better.
plugins/webp-uploads/helper.php
Outdated
| function webp_uploads_imagick_avif_transparency_supported(): bool { | ||
| if ( extension_loaded( 'imagick' ) && class_exists( 'Imagick' ) ) { | ||
| $imagick_version = Imagick::getVersion(); | ||
| if ( (bool) preg_match( '/((?:[0-9]+\\.?)+)/', $imagick_version['versionString'], $matches ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if ( (bool) preg_match( '/((?:[0-9]+\\.?)+)/', $imagick_version['versionString'], $matches ) ) { | |
| if ( (bool) preg_match( '/^\d+(?:\.\d+)+$/', $imagick_version['versionString'], $matches ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated regex to /\d+(?:\.\d+)+(?:-\d+)?/ for handling version string like this:
ImageMagick 7.1.1-15 Q16 aarch64 98eceff6a:20230729 https://imagemagick.orgCo-authored-by: Weston Ruter <westonruter@google.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make more sense to move this Site Health test to the Modern Image Formats plugin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just seeing this comment. I think it makes sense to move all Site Health tests for images to the plugin. See #1781
|
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: @johnmagbag1995, @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. |
| * @since n.e.x.t | ||
| */ | ||
|
|
||
| // @codeCoverageIgnoreStart |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious why this needs to be ignored for code coverage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I know, this section gets flagged by Codecov as the constant is always defined in the test environment, and as there is no way to undefine or modify a const value in PHP, we have to ignore it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. However, this could be made slightly more concise:
if ( ! defined( 'ABSPATH' ) ) {
exit; // @codeCoverageIgnore
}This could be done at once for all files in the repo, since they all have it now, for example:
performance/plugins/performance-lab/load.php
Lines 18 to 22 in b4f9898
| // @codeCoverageIgnoreStart | |
| if ( ! defined( 'ABSPATH' ) ) { | |
| exit; // Exit if accessed directly. | |
| } | |
| // @codeCoverageIgnoreEnd |
| * has been compiled against ImageMagick version 6.4.0 or newer. | ||
| */ | ||
| if ( is_callable( array( $this->image, 'getImageAlphaChannel' ) ) ) { | ||
| if ( ! $this->image->getImageAlphaChannel() ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you should explicitly check against Imagick::ALPHACHANNEL_UNDEFINED. getImageAlphaChannel returned an int initially, a boolean later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 991d7c9.
| * has been compiled against ImageMagick version 6.4.0 or newer. | ||
| */ | ||
| if ( is_callable( array( $this->image, 'getImageAlphaChannel' ) ) ) { | ||
| if ( ! $this->image->getImageAlphaChannel() ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you checked that this works correctly with PNG, WebP and AVIF uploads with transparencies?
| } | ||
|
|
||
| // Walk through the pixels and look transparent pixels. | ||
| $w = $this->image->getImageWidth(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this strikes me as very heavy and deserving of caching at the very least to avoid repeating.
I would also be fine saying Imagick 6.4 is required for transparency support :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in fece741.
plugins/webp-uploads/helper.php
Outdated
| $avif_support = webp_uploads_mime_type_supported( 'image/avif' ); | ||
|
|
||
| if ( $avif_support && webp_uploads_check_image_transparency( $filename ) ) { | ||
| $avif_support = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AVIF should still be supported in Imagick is new enough, right? this line sets it as false if the image has a transparency without regard to the Imagick version.
misread that call ^^
|
@b1ink0 - overall this looks very good! I wonder if this belongs in core directly: does this impact AVIF with transparency uploads in core (without the upload transform from PNG->AVIF)? If so this probably belongs in core directly since we aim to support AVIF as completely as possible. You probably noticed the existing PNG transparency handling in core, we could add similar handling for AVIFs. |
|
@adamsilverstein I was just thinking all this complex logic is just so that if an image does not have transparency and the site has an AVIF transparency unsupported version of ImageMagick, we allow the AVIF conversion. The simplest way could be to turn off AVIF conversion completely, even for non-transparent images. |
Thats fine for the plugin! Happy to see this fix land here. I'm just thinking we may also be able to introduce a more general fix in core to handle this case. I will check to see if we have an existing ticket for this. |
…ilename parameter by defaulting it to null Co-authored-by: Weston Ruter <westonruter@google.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
plugins/webp-uploads/class-webp-uploads-image-editor-imagick.php
Outdated
Show resolved
Hide resolved
Co-authored-by: Adam Silverstein <adamjs@google.com>
I’m not sure about a Core integration, since this is an edge case and would affect a very small number of sites. I’m also unsure whether this belongs in Core at all, as we’re doing a very specific check whether the ImageMagick version is less than 7.0.25. But I think if there is no ticket regarding this it should be opened to discuss it further. |
Co-authored-by: Adam Silverstein <adamjs@google.com>
plugins/webp-uploads/class-webp-uploads-image-editor-imagick.php
Outdated
Show resolved
Hide resolved
plugins/webp-uploads/hooks.php
Outdated
| $key = array_search( WP_Image_Editor_Imagick::class, $editors, true ); | ||
| if ( false !== $key ) { | ||
| $editors[ $key ] = WebP_Uploads_Image_Editor_Imagick::class; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this not unfortunately conflict with Dominant Color Images?
performance/plugins/dominant-color-images/helper.php
Lines 32 to 42 in 34445d4
| $replaces = array( | |
| WP_Image_Editor_GD::class => Dominant_Color_Image_Editor_GD::class, | |
| WP_Image_Editor_Imagick::class => Dominant_Color_Image_Editor_Imagick::class, | |
| ); | |
| foreach ( $replaces as $old => $new ) { | |
| $key = array_search( $old, $editors, true ); | |
| if ( false !== $key ) { | |
| $editors[ $key ] = $new; | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fallback to the WP_Image_Editor_GD class was making the Dominant Color Images work, but that still wasn’t correct.
I’ve updated the logic to unshift the WebP_Uploads_Image_Editor_Imagick class instead of replacing WP_Image_Editor_Imagick class.
Done in 717e768.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this work still? I'm looking at _wp_image_editor_choose() in core, and it seems it loops over the array to find the first one that works. In other words, it seems like it is not possible for both the implementation in Modern Image Formats and the implementation in Image Placeholders to both be active. So if the issue is fixed here with AVIF, does this mean that the dominant color is no longer getting extracted from the image?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it will work. Dominant Color Images doesn’t rely solely on what _wp_image_editor_choose() returns by default, it passes specific arguments to ensure it gets a class that implements the get_dominant_color and has_transparency methods. I’ve tested this solution, and it works correctly. Also, this class is used temporarily and is removed as soon as its task is complete. See below:
performance/plugins/dominant-color-images/helper.php
Lines 97 to 114 in 34445d4
| add_filter( 'wp_image_editors', 'dominant_color_set_image_editors' ); | |
| /** | |
| * Editor. | |
| * | |
| * @see dominant_color_set_image_editors() | |
| * @var WP_Image_Editor|Dominant_Color_Image_Editor_GD|Dominant_Color_Image_Editor_Imagick|WP_Error $editor | |
| */ | |
| $editor = wp_get_image_editor( | |
| $file, | |
| array( | |
| 'methods' => array( | |
| 'get_dominant_color', | |
| 'has_transparency', | |
| ), | |
| ) | |
| ); | |
| remove_filter( 'wp_image_editors', 'dominant_color_set_image_editors' ); |
Co-authored-by: Weston Ruter <westonruter@google.com>
|
I’d like feedback on the approach I mentioned here: #2245 (comment) The idea is to dynamically extend the active image editor class. If a third-party plugin has extended I have added a temp commit with a POC: c033c44. |
There was a problem hiding this comment.
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 8 out of 8 changed files in this pull request and generated 12 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
plugins/webp-uploads/hooks.php
Outdated
|
|
||
| if ( ! class_exists( 'WebP_Uploads_Image_Editor_Imagick_Base' ) ) { | ||
| if ( WP_Image_Editor_Imagick::class !== $editors[0] ) { | ||
| if ( ! is_subclass_of( WP_Image_Editor_Imagick::class, $editors[0] ) ) { |
Copilot
AI
Jan 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The is_subclass_of() parameters are in the wrong order. The first parameter should be the child class and the second parameter should be the parent class. Currently, this checks if WP_Image_Editor_Imagick is a subclass of $editors[0], when it should check if $editors[0] is a subclass of WP_Image_Editor_Imagick. The parameters should be swapped to is_subclass_of($editors[0], WP_Image_Editor_Imagick::class).
| if ( ! is_subclass_of( WP_Image_Editor_Imagick::class, $editors[0] ) ) { | |
| if ( ! is_subclass_of( $editors[0], WP_Image_Editor_Imagick::class ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, instanceof is easier to read and generally better, AFAIK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue is that we don’t have an instance here we only have the class name as a string. That’s why I used is_subclass_of().
| // Walk through the pixels and look transparent pixels. | ||
| $w = $this->image->getImageWidth(); | ||
| $h = $this->image->getImageHeight(); | ||
| for ( $x = 0; $x < $w; $x++ ) { | ||
| for ( $y = 0; $y < $h; $y++ ) { | ||
| $pixel = $this->image->getImagePixelColor( $x, $y ); | ||
| $color = $pixel->getColor( 2 ); | ||
| if ( $color['a'] > 0 && $color['a'] < 255 ) { | ||
| self::$checked_images[ $file_path ] = true; | ||
| return true; | ||
| } | ||
| } | ||
| } |
Copilot
AI
Jan 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function walks through every pixel in the image to check for transparency, which can be extremely slow for large images. For example, a 4000x3000 pixel image would require 12 million iterations. Consider implementing sampling (checking a subset of pixels) or early exit strategies, or using alternative Imagick methods like getImageAlphaChannel combined with histogram analysis to detect transparency more efficiently.
| // Walk through the pixels and look transparent pixels. | |
| $w = $this->image->getImageWidth(); | |
| $h = $this->image->getImageHeight(); | |
| for ( $x = 0; $x < $w; $x++ ) { | |
| for ( $y = 0; $y < $h; $y++ ) { | |
| $pixel = $this->image->getImagePixelColor( $x, $y ); | |
| $color = $pixel->getColor( 2 ); | |
| if ( $color['a'] > 0 && $color['a'] < 255 ) { | |
| self::$checked_images[ $file_path ] = true; | |
| return true; | |
| } | |
| } | |
| } | |
| // Use the image histogram to look for partially transparent pixels more efficiently. | |
| $histogram = $this->image->getImageHistogram(); | |
| foreach ( $histogram as $pixel ) { | |
| // Get normalized color values (0-1), including alpha channel. | |
| $color = $pixel->getColor( true ); | |
| // Match previous behavior: consider pixels with partial transparency only. | |
| if ( isset( $color['a'] ) && $color['a'] > 0 && $color['a'] < 1 ) { | |
| self::$checked_images[ $file_path ] = true; | |
| return true; | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m not sure about this. Histogram calculation can also be expensive, and a large image like 4000×3000 could have millions of unique colors. It might be faster for smaller images, though. I’ll run some tests with different types of images first to get actual numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using getImageChannelMean method.
| if ( 'avif' !== webp_uploads_get_image_output_format() || webp_uploads_imagick_avif_transparency_supported() || ! class_exists( 'WebP_Uploads_Image_Editor_Imagick' ) ) { | ||
| return false; | ||
| } | ||
|
|
||
| if ( null === $filename ) { | ||
| if ( null === WebP_Uploads_Image_Editor_Imagick::$current_instance ) { | ||
| return false; | ||
| } | ||
| $file = WebP_Uploads_Image_Editor_Imagick::$current_instance->get_file(); | ||
| if ( '' === $file ) { | ||
| return false; | ||
| } | ||
| $filename = $file; | ||
| } | ||
|
|
||
| if ( ! is_string( $filename ) || ! file_exists( $filename ) ) { | ||
| return false; | ||
| } | ||
|
|
||
| if ( isset( $processed_images[ $filename ] ) ) { | ||
| return $processed_images[ $filename ]; | ||
| } | ||
| $processed_images[ $filename ] = false; | ||
|
|
||
| $editor = wp_get_image_editor( $filename ); |
Copilot
AI
Jan 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a circular dependency risk here. The function webp_uploads_check_image_transparency() calls wp_get_image_editor() at line 578, which triggers the 'wp_image_editors' filter (line 1018 in hooks.php). That filter callback webp_uploads_set_image_editors() loads the WebP_Uploads_Image_Editor_Imagick class, but that class is only needed if webp_uploads_check_image_transparency() returns true. However, webp_uploads_check_image_transparency() checks for the class existence at line 554, which can create a chicken-and-egg problem. This could lead to the transparency check being skipped when it shouldn't be, or infinite recursion in some edge cases.
plugins/webp-uploads/class-webp-uploads-image-editor-imagick.php
Outdated
Show resolved
Hide resolved
| /** | ||
| * Checks if Imagick has AVIF transparency support. | ||
| * | ||
| * @since n.e.x.t | ||
| * | ||
| * @return bool True if Imagick has AVIF transparency support, false otherwise. | ||
| */ | ||
| function webp_uploads_imagick_avif_transparency_supported(): bool { | ||
| if ( extension_loaded( 'imagick' ) && class_exists( 'Imagick' ) ) { | ||
| $imagick_version = Imagick::getVersion(); | ||
| if ( (bool) preg_match( '/\d+(?:\.\d+)+(?:-\d+)?/', $imagick_version['versionString'], $matches ) ) { | ||
| $imagick_version = $matches[0]; | ||
| } else { | ||
| $imagick_version = $imagick_version['versionString']; | ||
| } | ||
| return version_compare( $imagick_version, '7.0.25', '>=' ); | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Checks if an AVIF image has transparency | ||
| * | ||
| * @since n.e.x.t | ||
| * | ||
| * @param string|null $filename The uploaded file name. | ||
| * @return bool Whether the image has transparency. | ||
| */ | ||
| function webp_uploads_check_image_transparency( ?string $filename ): bool { | ||
| static $processed_images = array(); | ||
|
|
||
| if ( 'avif' !== webp_uploads_get_image_output_format() || webp_uploads_imagick_avif_transparency_supported() || ! class_exists( 'WebP_Uploads_Image_Editor_Imagick' ) ) { | ||
| return false; | ||
| } | ||
|
|
||
| if ( null === $filename ) { | ||
| if ( null === WebP_Uploads_Image_Editor_Imagick::$current_instance ) { | ||
| return false; | ||
| } | ||
| $file = WebP_Uploads_Image_Editor_Imagick::$current_instance->get_file(); | ||
| if ( '' === $file ) { | ||
| return false; | ||
| } | ||
| $filename = $file; | ||
| } | ||
|
|
||
| if ( ! is_string( $filename ) || ! file_exists( $filename ) ) { | ||
| return false; | ||
| } | ||
|
|
||
| if ( isset( $processed_images[ $filename ] ) ) { | ||
| return $processed_images[ $filename ]; | ||
| } | ||
| $processed_images[ $filename ] = false; | ||
|
|
||
| $editor = wp_get_image_editor( $filename ); | ||
|
|
||
| if ( is_wp_error( $editor ) || ! $editor instanceof WebP_Uploads_Image_Editor_Imagick ) { | ||
| return false; | ||
| } | ||
|
|
||
| $has_transparency = $editor->has_transparency(); | ||
| $processed_images[ $filename ] = is_wp_error( $has_transparency ) ? false : $has_transparency; | ||
|
|
||
| return $processed_images[ $filename ]; | ||
| } |
Copilot
AI
Jan 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new transparency checking functionality lacks test coverage. The repository has comprehensive test coverage for other functions (test-helper.php, test-load.php, etc.), but no tests are present for webp_uploads_imagick_avif_transparency_supported(), webp_uploads_check_image_transparency(), or the WebP_Uploads_Image_Editor_Imagick::has_transparency() method. Given the complexity and critical nature of this transparency detection logic, unit tests should be added to verify correct behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to add test coverage based on this feedback
plugins/webp-uploads/class-webp-uploads-image-editor-imagick.php
Outdated
Show resolved
Hide resolved
plugins/webp-uploads/class-webp-uploads-image-editor-imagick.php
Outdated
Show resolved
Hide resolved
| function webp_uploads_set_image_editors( array $editors ): array { | ||
| if ( 'avif' !== webp_uploads_get_image_output_format() || webp_uploads_imagick_avif_transparency_supported() ) { | ||
| return $editors; | ||
| } | ||
|
|
||
| if ( 0 === count( $editors ) || false === array_search( WP_Image_Editor_Imagick::class, $editors, true ) ) { | ||
| return $editors; | ||
| } | ||
|
|
||
| if ( ! class_exists( $editors[0] ) ) { | ||
| return $editors; | ||
| } | ||
|
|
||
| if ( ! class_exists( 'WebP_Uploads_Image_Editor_Imagick_Base' ) ) { | ||
| if ( WP_Image_Editor_Imagick::class !== $editors[0] ) { | ||
| if ( ! is_subclass_of( WP_Image_Editor_Imagick::class, $editors[0] ) ) { | ||
| return $editors; | ||
| } else { | ||
| $reflection = new ReflectionClass( $editors[0] ); | ||
| if ( $reflection->isFinal() ) { | ||
| return $editors; | ||
| } | ||
| class_alias( $editors[0], 'WebP_Uploads_Image_Editor_Imagick_Base' ); | ||
| } | ||
| } else { | ||
| class_alias( WP_Image_Editor_Imagick::class, 'WebP_Uploads_Image_Editor_Imagick_Base' ); | ||
| } | ||
| } | ||
|
|
||
| if ( ! class_exists( 'WebP_Uploads_Image_Editor_Imagick' ) ) { | ||
| require_once __DIR__ . '/class-webp-uploads-image-editor-imagick.php'; // @codeCoverageIgnore | ||
| } | ||
|
|
||
| array_unshift( $editors, WebP_Uploads_Image_Editor_Imagick::class ); | ||
|
|
||
| return $editors; | ||
| } | ||
| add_filter( 'wp_image_editors', 'webp_uploads_set_image_editors' ); |
Copilot
AI
Jan 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The webp_uploads_set_image_editors() function lacks test coverage. Given the repository's comprehensive test coverage for other functions and the complex conditional logic with class aliasing in this function (lines 981-1018), tests should be added to verify correct editor registration behavior under different scenarios: when AVIF support exists, when it doesn't, with different editor configurations, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to add test coverage based on this feedback
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Summary
Fixes #2237
Relevant technical choices
Prevents transparent backgrounds from being lost when converting PNG images to AVIF format on older ImageMagick
TODO: