Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 37 additions & 0 deletions plugins/webp-uploads/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -514,3 +514,40 @@ 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
*
* @param string|null $version Optional Imagick version string. If not provided, the version will be retrieved from the Imagick class.
* @return bool True if Imagick has AVIF transparency support, false otherwise.
*/
function webp_uploads_imagick_avif_transparency_supported( ?string $version = null ): bool {
$supported = false;
$imagick_version = $version;

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;
}

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


/**
* Filters whether Imagick has AVIF transparency support.
*
* @since n.e.x.t
*
* @param bool $supported Whether AVIF transparency is supported.
*/
return (bool) apply_filters( 'webp_uploads_imagick_avif_transparency_supported', $supported );
}
18 changes: 13 additions & 5 deletions plugins/webp-uploads/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,10 @@ static function (): void {
*/
function webp_uploads_generate_avif_webp_setting_callback(): void {

$selected = webp_uploads_get_image_output_format();
$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."

$avif_transparency_supported = webp_uploads_imagick_avif_transparency_supported();
$webp_supported = webp_uploads_mime_type_supported( 'image/webp' );

// If neither format is support, the entire field is not shown.
if ( ! $avif_supported && ! $webp_supported ) {
Expand All @@ -170,15 +171,15 @@ function webp_uploads_generate_avif_webp_setting_callback(): void {
}

// If only one of the two formats is supported, the dropdown defaults to that type and the other type is disabled.
if ( ! $avif_supported && 'avif' === $selected ) {
if ( ! ( $avif_supported && $avif_transparency_supported ) && 'avif' === $selected ) {
$selected = 'webp';
} elseif ( ! $webp_supported && 'webp' === $selected ) {
$selected = 'avif';
}
?>
<select name="perflab_modern_image_format" id="perflab_modern_image_format" aria-describedby="perflab_modern_image_format_description">
<option value="webp"<?php selected( 'webp', $selected ); ?><?php disabled( ! $webp_supported ); ?>><?php esc_html_e( 'WebP', 'webp-uploads' ); ?></option>
<option value="avif"<?php selected( 'avif', $selected ); ?><?php disabled( ! $avif_supported ); ?>><?php esc_html_e( 'AVIF', 'webp-uploads' ); ?></option>
<option value="avif"<?php selected( 'avif', $selected ); ?><?php disabled( ! ( $avif_supported && $avif_transparency_supported ) ); ?>><?php esc_html_e( 'AVIF', 'webp-uploads' ); ?></option>
</select>
<label for="perflab_modern_image_format">
<?php esc_html_e( 'Generate images in this format', 'webp-uploads' ); ?>
Expand All @@ -201,6 +202,13 @@ function webp_uploads_generate_avif_webp_setting_callback(): void {
<p><?php esc_html_e( 'WebP support can only be enabled by your hosting provider, so contact them for more information.', 'webp-uploads' ); ?></p>
</div>
<?php endif; ?>
<?php if ( $avif_supported && ! $avif_transparency_supported ) : ?>
<br />
<div class="notice notice-warning inline">
<p><b><?php esc_html_e( 'AVIF transparency support is not available.', 'webp-uploads' ); ?></b></p>
<p><?php esc_html_e( 'Current ImageMagick version does not support transparent AVIF images, so contact your hosting provider for more information.', 'webp-uploads' ); ?></p>
</div>
<?php endif; ?>
<?php
}

Expand Down
16 changes: 16 additions & 0 deletions plugins/webp-uploads/tests/data/class-testcase.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,20 @@ public function mock_frontend_body_hooks(): void {
remove_all_actions( 'template_redirect' );
do_action( 'template_redirect' );
}

/**
* Mocks AVIF transparency support to force a specific scenario.
*
* @param bool $supported Whether to mock AVIF transparency as supported.
*/
public function mock_avif_transparency_support( bool $supported ): void {
remove_all_filters( 'webp_uploads_imagick_avif_transparency_supported' );
add_filter(
'webp_uploads_imagick_avif_transparency_supported',
static function () use ( $supported ) {
return $supported;
},
1
);
}
}
42 changes: 42 additions & 0 deletions plugins/webp-uploads/tests/test-helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -678,4 +678,46 @@ public function data_provider_to_test_webp_uploads_sanitize_image_format(): arra
public function test_webp_uploads_sanitize_image_format( $input, string $expected ): void {
$this->assertSame( $expected, webp_uploads_sanitize_image_format( $input ) );
}

/**
* Data provider for ImageMagick version strings.
*
* @return array<string, array{string, bool}> Test data with version strings and expected support.
*/
public function data_provider_imagick_versions(): array {
return array(
'ImageMagick 6.8.9 Q16 x86_64' => array( 'ImageMagick 6.8.9-9 Q16 x86_64 2018-09-28 https://imagemagick.org/index.php', false ),
'ImageMagick 6.9.11 Q16 x86_64' => array( 'ImageMagick 6.9.11-60 Q16 x86_64 2021-01-01 https://imagemagick.org', false ),
'ImageMagick 6.9.12 below minimum revision' => array( 'ImageMagick 6.9.12-27 Q16 x86_64 2021-10-24 https://imagemagick.org', false ),
'ImageMagick 6.9.12 just below minimum revision' => array( 'ImageMagick 6.9.12-67 Q16 x86_64 2025-06-01 https://imagemagick.org', false ),
'ImageMagick 6.9.12 exact minimum revision' => array( 'ImageMagick 6.9.12-68 Q16 x86_64 2025-06-04 https://imagemagick.org', true ),
'ImageMagick 6.9.13 above minimum revision' => array( 'ImageMagick 6.9.13-17 Q16 x86_64', true ),
'ImageMagick 7.0.24 above minimum major version' => array( 'ImageMagick 7.0.24 Q16 x86_64', true ),
'ImageMagick 7.0.25 above minimum major version' => array( 'ImageMagick 7.0.25 Q16 x86_64', true ),
'ImageMagick 7.1.0 Q16-HDRI x86_64' => array( 'ImageMagick 7.1.0-57 Q16-HDRI x86_64 d68553b17:20221230 https://imagemagick.org', true ),
'ImageMagick 7.1.1 Q16 aarch64' => array( 'ImageMagick 7.1.1-15 Q16 aarch64 98eceff6a:20230729 https://imagemagick.org', true ),
'ImageMagick 7.1.2 Q16-HDRI x86_64' => array( 'ImageMagick 7.1.2-7 Q16-HDRI x86_64 23405 https://imagemagick.org', true ),
'Empty string should return false' => array( '', false ),
'Invalid string without version should be false' => array( 'Invalid version string', false ),
'String with only text should be false' => array( 'ImageMagick', false ),
'Malformed version string should be false' => array( 'ImageMagick x.y.z', false ),
);
}

/**
* Tests webp_uploads_imagick_avif_transparency_supported checks version correctly.
*
* @dataProvider data_provider_imagick_versions
* @covers ::webp_uploads_imagick_avif_transparency_supported
*
* @param string $version ImageMagick version string.
* @param bool $expected_support Expected transparency support result.
*/
public function test_webp_uploads_imagick_avif_transparency_supported_checks_version( string $version, bool $expected_support ): void {
remove_all_filters( 'webp_uploads_imagick_avif_transparency_supported' );

$result = webp_uploads_imagick_avif_transparency_supported( $version );

$this->assertSame( $expected_support, $result );
}
}
30 changes: 29 additions & 1 deletion plugins/webp-uploads/tests/test-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
* @package webp-uploads
*/

class Test_WebP_Uploads_Settings extends WP_UnitTestCase {
use WebP_Uploads\Tests\TestCase;

class Test_WebP_Uploads_Settings extends TestCase {

/**
* @covers ::webp_uploads_add_media_settings_fields
Expand Down Expand Up @@ -43,4 +45,30 @@ public function test_webp_uploads_add_settings_action_link(): void {
webp_uploads_add_settings_action_link( $default_action_links )
);
}

/**
* @covers ::webp_uploads_generate_avif_webp_setting_callback
*/
public function test_webp_uploads_generate_avif_webp_setting_callback_disables_avif_and_shows_warning(): void {
if ( ! webp_uploads_mime_type_supported( 'image/avif' ) ) {
$this->markTestSkipped( 'Mime type image/avif is not supported.' );
}

$this->set_image_output_type( 'avif' );
$this->mock_avif_transparency_support( false );
$output = get_echo( 'webp_uploads_generate_avif_webp_setting_callback' );
$processor = new WP_HTML_Tag_Processor( $output );

$this->assertTrue( $processor->next_tag( array( 'tag_name' => 'OPTION' ) ) );
$this->assertSame( 'webp', $processor->get_attribute( 'value' ) );
$this->assertNotNull( $processor->get_attribute( 'selected' ) );

$this->assertTrue( $processor->next_tag( array( 'tag_name' => 'OPTION' ) ) );
$this->assertSame( 'avif', $processor->get_attribute( 'value' ) );
$this->assertNotNull( $processor->get_attribute( 'disabled' ) );
$this->assertNull( $processor->get_attribute( 'selected' ) );

$this->assertStringContainsString( 'AVIF transparency support is not available.', $output );
$this->assertStringContainsString( 'Current ImageMagick version does not support transparent AVIF images', $output );
}
}
Loading