Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
ae7f22d
Add support for AVIF transparency checks during image uploads
b1ink0 Oct 30, 2025
a1aff66
Improve Imagick version string regex validation
b1ink0 Nov 2, 2025
be0817b
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Nov 13, 2025
3fe6954
Add site health checks for Imagick AVIF transparency support
b1ink0 Nov 14, 2025
2247b61
Add custom image editor class to help with AVIF transparency detection
b1ink0 Dec 17, 2025
1a58d1c
Move Imagick AVIF transparency support site health test
b1ink0 Dec 26, 2025
fdf65ec
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Dec 26, 2025
50f2be1
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Jan 13, 2026
f8af1e9
Allow `webp_uploads_get_upload_image_mime_transforms()` to omit the f…
b1ink0 Jan 13, 2026
991d7c9
Add explicit return value check for `getImageAlphaChannel` method
b1ink0 Jan 15, 2026
fece741
Add transparency check caching to custom image editor class
b1ink0 Jan 20, 2026
9020b24
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Jan 20, 2026
435f5ff
Refactor to use filename instead of file hash for transparency check
b1ink0 Jan 20, 2026
4da1758
Fix transparency detection to exclude fully opaque pixels
b1ink0 Jan 20, 2026
717e768
Fix image editor confilict with Dominant Color Images
b1ink0 Jan 21, 2026
c033c44
Dynimacally extend the image editor class
b1ink0 Jan 21, 2026
b28885e
Fix parameters order in `is_subclass_of`
b1ink0 Jan 22, 2026
6004d18
Simplify conditional checks
b1ink0 Jan 22, 2026
d218d0f
Fix transparency detection for fully transparent images
b1ink0 Jan 22, 2026
41f94e1
Improve doc comments
b1ink0 Jan 22, 2026
28f2583
Skip unnecessary transparency check when image format is already WebP
b1ink0 Jan 22, 2026
b421017
Improve doc comments
b1ink0 Jan 22, 2026
433ea1c
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Jan 29, 2026
b00d2d0
Add unit tests for AVIF transparency detection
adamsilverstein Jan 29, 2026
28d6020
Enhance transparency detection logic
b1ink0 Jan 29, 2026
4cf8302
Improve image editor selection logic
b1ink0 Jan 30, 2026
a28415f
Merge pull request #1 from WordPress/fix/imagemagick-old-version-avif…
b1ink0 Feb 2, 2026
99a2704
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Feb 2, 2026
92f6528
Ensure helper class is loaded
b1ink0 Feb 2, 2026
23f528b
Add filter to transparency check function
b1ink0 Feb 9, 2026
06f67f7
Improve test code coverage
b1ink0 Feb 9, 2026
4e1ac64
Update test plugin GitHub action to use `tests-wordpress` instead of …
b1ink0 Feb 12, 2026
fec8109
Update commands to use `tests-wordpress` instead of `tests-cli`
b1ink0 Feb 12, 2026
50e74ad
Update all commands to usee `tests-wordpress`
b1ink0 Feb 12, 2026
d8acc81
Fix failing tests
b1ink0 Feb 12, 2026
0e0ee09
Fix failing tests on PHP 7.2
b1ink0 Feb 13, 2026
23e12d5
Fix failing tests on PHP 8.1
b1ink0 Feb 13, 2026
1045006
Finally fix failing tests on PHP 8.1
b1ink0 Feb 13, 2026
789906c
Use `method_exists` instead of `is_callable`
b1ink0 Feb 16, 2026
8140089
Return null when file property does not exist
b1ink0 Feb 16, 2026
2c50ed7
Improve conditional checks
b1ink0 Feb 16, 2026
d01f2d6
Narrow down types
b1ink0 Feb 16, 2026
315d6c3
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Feb 16, 2026
3190c5b
Use fallback for more failure conditions
b1ink0 Feb 17, 2026
f0beb09
Improve test code coverage
b1ink0 Feb 25, 2026
346a61e
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Feb 25, 2026
3f55c70
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Feb 27, 2026
59d39dc
Only consider default channels for mean calculation
b1ink0 Mar 4, 2026
be178ec
Merge branch 'trunk' into fix/imagemagick-old-version-avif-transparen…
b1ink0 Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions plugins/webp-uploads/class-webp-uploads-image-editor-imagick.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php
/**
* WordPress Image Editor Class for Image Manipulation through Imagick
* for transparency detection
*
* @package webp-uploads
*
* @since n.e.x.t
*/

// @codeCoverageIgnoreStart
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
// @codeCoverageIgnoreEnd

if ( class_exists( 'WebP_Uploads_Image_Editor_Imagick_Base' ) ) {

/**
* WordPress Image Editor Class for Image Manipulation through Imagick
* for transparency detection.
*
* @since n.e.x.t
*
* @see WP_Image_Editor
*/
class WebP_Uploads_Image_Editor_Imagick extends WebP_Uploads_Image_Editor_Imagick_Base {
/**
* The current instance of the image editor.
*
* @since n.e.x.t
*
* @var WebP_Uploads_Image_Editor_Imagick|null $current_instance The current instance.
*/
public static $current_instance = null;

/**
* Stores already checked images for transparency.
*
* @since n.e.x.t
*
* @var array<string, bool> Associative array with file paths as keys and transparency detection results as values.
*/
private static $checked_images = array();

/**
* Load the image and set the current instance.
*
* @since n.e.x.t
*
* @return WP_Error|true True on success, WP_Error on failure.
*/
public function load() {
// @phpstan-ignore-next-line -- Parent class is created via class_alias at runtime.
$result = parent::load();
if ( ! is_wp_error( $result ) ) {
self::$current_instance = $this;
}
return $result;
}

/**
* Get the file path of the image.
*
* @since n.e.x.t
*
* @return string The file path of the image.
*/
public function get_file(): string {
if ( property_exists( $this, 'file' ) && is_string( $this->file ) ) {
return $this->file;
}
return '';
}

/**
* Looks for transparent pixels in the image.
* If there are none, it returns false.
*
* @since n.e.x.t
*
* @return bool|WP_Error True or false based on whether there are transparent pixels, or an error on failure.
*/
public function has_transparency() {
if ( ! property_exists( $this, 'image' ) ) {
return false;
}

if ( ! (bool) $this->image ) {
return new WP_Error( 'image_editor_has_transparency_error_no_image', __( 'Transparency detection no image found.', 'webp-uploads' ) );
}

$file_path = $this->get_file();
if ( isset( self::$checked_images[ $file_path ] ) ) {
return self::$checked_images[ $file_path ];
}

if ( ! $this->image instanceof Imagick ) {
return false;
}

try {
/*
* Check if the image has an alpha channel if false, then it can't have transparency so return early.
*
* Note that Imagick::getImageAlphaChannel() is only available if Imagick
* has been compiled against ImageMagick version 6.4.0 or newer.
*/
if ( is_callable( array( $this->image, 'getImageAlphaChannel' ) ) ) {
if ( Imagick::ALPHACHANNEL_UNDEFINED === $this->image->getImageAlphaChannel() ) {
self::$checked_images[ $file_path ] = false;
return false;
}
}

// 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;
}
}
}
Copy link

Copilot AI Jan 22, 2026

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.

Suggested change
// 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;
}
}

Copilot uses AI. Check for mistakes.
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’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.

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.

What about using getImageChannelMean method.

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 have found a way to make this more efficient using getImageChannelMean and getImageChannelRange done in 28d6020.

example:

$rgb_mean    = $this->image->getImageChannelMean( Imagick::CHANNEL_ALL );
$alpha_range = $this->image->getImageChannelRange( Imagick::CHANNEL_ALPHA );

if ( isset( $rgb_mean['mean'], $alpha_range['maxima'] ) ) {
	$maxima = (int) $alpha_range['maxima'];
	$mean   = (int) $rgb_mean['mean'];

	if ( 0 > $maxima || 0 > $mean ) {
		// For invalid values assume no transparency.
		$transparency = false;
	} elseif ( 0 === $maxima && 0 === $mean ) {
		// Alpha channel is all zeros AND no RGB content indicates fully transparent image.
		$transparency = true;
	} elseif ( 0 === $maxima && $mean > 0 ) {
		// Alpha maxima of 0 with RGB content present indicates no real alpha channel exists (hence fully opaque).
		$transparency = false;
	} elseif ( 0 < $maxima && 0 < $mean ) {
		// Non-zero alpha values with RGB content present indicates some transparency.
		$transparency = true;
	}
}

self::$checked_images[ $file_path ] = false;
return false;

} catch ( Exception $e ) {
/* translators: %s is the error message */
return new WP_Error( 'image_editor_has_transparency_error', sprintf( __( 'Transparency detection failed: %s', 'webp-uploads' ), $e->getMessage() ) );
}
}
}
}
78 changes: 76 additions & 2 deletions plugins/webp-uploads/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@
* @since 2.0.0 Added support for AVIF.
* @since 2.2.0 Added support for PNG.
*
* @param string|null $filename Optional. The filename. Default null.
* @return array<string, array<string>> An array of valid mime types, where the key is the mime type and the value is the extension type.
*/
function webp_uploads_get_upload_image_mime_transforms(): array {
function webp_uploads_get_upload_image_mime_transforms( ?string $filename = null ): array {
$avif_support = webp_uploads_mime_type_supported( 'image/avif' );

if ( $avif_support && webp_uploads_check_image_transparency( $filename ) ) {
$avif_support = false;
Copy link
Copy Markdown
Member

@adamsilverstein adamsilverstein Jan 12, 2026

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 ^^

}

// Check the selected output format.
$output_format = webp_uploads_mime_type_supported( 'image/avif' ) ? webp_uploads_get_image_output_format() : 'webp';
$output_format = $avif_support ? webp_uploads_get_image_output_format() : 'webp';

$default_transforms = array(
'image/jpeg' => array( 'image/' . $output_format ),
Expand Down Expand Up @@ -512,3 +518,71 @@ function webp_uploads_get_attachment_file_mime_type( int $attachment_id, string
$mime_type = $filetype['type'] ?? get_post_mime_type( $attachment_id );
return is_string( $mime_type ) ? $mime_type : '';
}

/**
* 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 );
Copy link

Copilot AI Jan 22, 2026

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.

Copilot uses AI. Check for mistakes.
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.

Commit 92f6528 will make sure that WebP_Uploads_Image_Editor_Imagick class is loaded in rare case where the webp_uploads_check_image_transparency() function is called before wp_image_editors filter resolving issue of skipped check.


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 ];
}
Comment on lines +520 to +625
Copy link

Copilot AI Jan 22, 2026

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.

Copilot uses AI. Check for mistakes.
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.

@copilot open a new pull request to add test coverage based on this feedback

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.

hmmm... copilot seems to have ignored me :( I'll give Claude a try locally...

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 it's because this PR uses a branch from a fork 🤔.

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’m still working on some feedback from Copilot. Once that’s done, I’ll write the tests.

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.

Here is what Claude came up with: b1ink0#1

52 changes: 49 additions & 3 deletions plugins/webp-uploads/hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ function webp_uploads_create_sources_property( array $metadata, int $attachment_
return $metadata;
}

$valid_mime_transforms = webp_uploads_get_upload_image_mime_transforms();

$valid_mime_transforms = webp_uploads_get_upload_image_mime_transforms( $file );
// Not a supported mime type to create the sources property.
if ( ! isset( $valid_mime_transforms[ $mime_type ] ) ) {
return $metadata;
Expand Down Expand Up @@ -334,7 +333,7 @@ function webp_uploads_filter_image_editor_output_format( $output_format, ?string
}

// Use the original mime type if this type is allowed.
$valid_mime_transforms = webp_uploads_get_upload_image_mime_transforms();
$valid_mime_transforms = webp_uploads_get_upload_image_mime_transforms( $filename );
if (
! isset( $valid_mime_transforms[ $mime_type ] ) ||
in_array( $mime_type, $valid_mime_transforms[ $mime_type ], true )
Expand Down Expand Up @@ -970,3 +969,50 @@ function webp_uploads_convert_palette_png_to_truecolor( $file ): array {
}
add_filter( 'wp_handle_upload_prefilter', 'webp_uploads_convert_palette_png_to_truecolor' );
add_filter( 'wp_handle_sideload_prefilter', 'webp_uploads_convert_palette_png_to_truecolor' );

/**
* Overloads wp_image_editors() to load the extended class when AVIF transparency is not supported.
*
* @since n.e.x.t
*
* @param string[] $editors Array of available image editor class names. Defaults are 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD'.
* @return string[] Registered image editors class names.
*/
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] ) ) {
Copy link

Copilot AI Jan 22, 2026

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

Suggested change
if ( ! is_subclass_of( WP_Image_Editor_Imagick::class, $editors[0] ) ) {
if ( ! is_subclass_of( $editors[0], WP_Image_Editor_Imagick::class ) ) {

Copilot uses AI. Check for mistakes.
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.

Alternatively, instanceof is easier to read and generally better, AFAIK.

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.

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

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' );
Copy link

Copilot AI Jan 22, 2026

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.

Copilot uses AI. Check for mistakes.
2 changes: 1 addition & 1 deletion plugins/webp-uploads/image-edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ function webp_uploads_update_image_onchange( $override, string $file_path, WP_Im
return (bool) $override;
}

$transforms = webp_uploads_get_upload_image_mime_transforms();
$transforms = webp_uploads_get_upload_image_mime_transforms( $file_path );
if ( ! isset( $transforms[ $mime_type ] ) || ! is_array( $transforms[ $mime_type ] ) || 0 === count( $transforms[ $mime_type ] ) ) {
return null;
}
Expand Down
1 change: 1 addition & 0 deletions plugins/webp-uploads/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@
require_once __DIR__ . '/picture-element.php';
require_once __DIR__ . '/hooks.php';
require_once __DIR__ . '/deprecated.php';
require_once __DIR__ . '/site-health/load.php';
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
/**
* Helper functions used for checking Imagick AVIF transparency support.
*
* @package webp-uploads
* @since n.e.x.t
*/

// @codeCoverageIgnoreStart
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'm curious why this needs to be ignored for code coverage?

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.

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.

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.

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:

// @codeCoverageIgnoreStart
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
// @codeCoverageIgnoreEnd

if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
// @codeCoverageIgnoreEnd

/**
* Callback for Imagick AVIF transparency support test.
*
* @since n.e.x.t
*
* @return array{label: string, status: string, badge: array{label: string, color: string}, description: string, actions: string, test: string} Result.
*/
function webp_uploads_imagick_avif_transparency_supported_test(): array {
$result = array(
'label' => __( 'Your site supports AVIF image format transparency with ImageMagick', 'webp-uploads' ),
'status' => 'good',
'badge' => array(
'label' => __( 'Performance', 'webp-uploads' ),
'color' => 'blue',
),
'description' => sprintf(
'<p>%s</p>',
__( 'Older versions of ImageMagick do not support transparency in AVIF images, which can result in loss of transparency when uploading AVIF files.', 'webp-uploads' )
),
'actions' => sprintf(
'<p><strong>%s</strong></p>',
__( 'Your ImageMagick installation supports AVIF transparency.', 'webp-uploads' )
),
'test' => 'is_imagick_avif_transparency_supported_enabled',
);

if ( ! webp_uploads_imagick_avif_transparency_supported() ) {
$result['status'] = 'recommended';
$result['label'] = __( 'Your site does not support AVIF transparency', 'webp-uploads' );
$result['actions'] = sprintf(
'<p>%s</p>',
__( 'Update ImageMagick to the latest version by contacting your hosting provider.', 'webp-uploads' )
);
}

return $result;
}
Comment on lines +22 to +51
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The site health check function lacks test coverage. The repository has comprehensive test coverage for other functionality, but there are no tests for webp_uploads_imagick_avif_transparency_supported_test() or the site health integration. Tests should verify the correct status, labels, and messages are returned for both supported and unsupported ImageMagick versions.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

@b1ink0 b1ink0 Nov 14, 2025

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?

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.

Just seeing this comment. I think it makes sense to move all Site Health tests for images to the plugin. See #1781

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
/**
* Hook callbacks used for checking Imagick AVIF transparency support.
*
* @package webp-uploads
* @since n.e.x.t
*/

// @codeCoverageIgnoreStart
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
// @codeCoverageIgnoreEnd

/**
* Adds tests to site health.
*
* @since n.e.x.t
*
* @param array{direct: array<string, array{label: string, test: string}>} $tests Site Health Tests.
* @return array{direct: array<string, array{label: string, test: string}>} Amended tests.
*/
function webp_uploads_add_imagick_avif_transparency_supported_test( array $tests ): array {
$tests['direct']['imagick_avif_transparency_supported'] = array(
'label' => __( 'Imagick AVIF Transparency Support', 'webp-uploads' ),
'test' => 'webp_uploads_imagick_avif_transparency_supported_test',
);
return $tests;
}
add_filter( 'site_status_tests', 'webp_uploads_add_imagick_avif_transparency_supported_test' );
Loading
Loading