Make WordPress Core

Opened 4 weeks ago

Closed 3 weeks ago

Last modified 9 days ago

#63302 closed defect (bug) (fixed)

SVG images can't be uploaded anymore due to a resizing issue

Reported by: audrasjb's profile audrasjb Owned by: adamsilverstein's profile adamsilverstein
Milestone: 6.8.1 Priority: normal
Severity: normal Version: 6.8
Component: Editor Keywords: has-screenshots has-patch needs-testing has-unit-tests commit fixed-major dev-reviewed
Focuses: Cc:

Description

Starting with WP 6.8, SVG images can't be uploaded anymore even when they are allowed using custom code or a plugin.

To reproduce the issue:

  1. Add support for SVG mime type with a custom filter or install a plugin like Safe SVG
  2. Try to insert a SVG using the image block
  3. Confirm that it fails because the server cannot resize the image (see screenshot below)

I don't think it's a Gutenberg issue so I'm opening this ticket here, but maybe it is, so I will report it upstream if needed.

Attachments (2)

Capture d’écran 2025-04-18 à 01.19.48.png (138.4 KB) - added by audrasjb 4 weeks ago.
Unable to upload any SVG file because of image resizing issue
63302.patch (789 bytes) - added by dilipbheda 4 weeks ago.

Download all attachments as: .zip

Change History (46)

@audrasjb
4 weeks ago

Unable to upload any SVG file because of image resizing issue

#1 @audrasjb
4 weeks ago

Note: it works when uploading it directly via the Media Library, but not directly in the editor.

#2 @audrasjb
4 weeks ago

Note 2: I assigned this ticket to milestone 6.8.1 because it looks like a 6.8 issue, but I'm not 100% sure it is not a third party (plugin) issue for now. Still investigating.

#3 @audrasjb
4 weeks ago

  • Keywords has-screenshots added

#4 follow-up: @pbiron
4 weeks ago

on an initial test I'm not able to reproduce (i.e., I'm able to upload an SVG directly in the Image block).

WP: 6.8
plugins: Safe SVG (and a bunch of others)
PHP: 8.3.15
PHP extensions: imagick (and a bunch of others)

I'll experiment more tomorrow and report findings.

#5 @sainathpoojary
4 weeks ago

Hey @audrasjb,

Thank you for reporting the issue. I was able to reproduce it on my end as well. I’ll try looking into possible solutions.

https://rioudcpuyg.ufs.sh/f/PL8E4NiPUWyORiCcatuTu5OnjW2XKY0IRv1P9lgoTaLbV4qy

#6 @sainathpoojary
4 weeks ago

I can confirm that I’m unable to reproduce the issue in WordPress 6.7.2

#7 follow-up: @sainathpoojary
4 weeks ago

Hey @audrasjb,

I've identified an issue with SVG uploads in WordPress 6.8 that was introduced in changeset 60084.

After investigating changeset 60084, I found that two different implementations exist for handling unsupported image formats:|

  1. Media Library path (wp-admin/includes/media.php):
if ( $prevent_unsupported_uploads ) {
    // Check if WebP images can be edited.
    if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) {
        $plupload_init['webp_upload_error'] = true;
    }
    // Check if AVIF images can be edited.
    if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) {
        $plupload_init['avif_upload_error'] = true;
    }
}
  1. Block Editor path (wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php):
if (
    $prevent_unsupported_uploads &&
    isset( $files['file']['type'] ) &&
    str_starts_with( $files['file']['type'], 'image/' )
) {
    // Check if the image editor supports the type.
    if ( ! wp_image_editor_supports( array( 'mime_type' => $files['file']['type'] ) ) ) {
        return new WP_Error(
            'rest_upload_image_type_not_supported',
            __( 'The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.' ),
            array( 'status' => 400 )
        );
    }
}

Difference between both:

  1. Media Library checks only WebP and AVIF specifically
  2. Block Editor checks all image types (anything starting with 'image/')
  3. Media Library sets a warning flag but allows upload
  4. Block Editor returns an error and prevents upload entirely

This inconsistency causes SVG files to pass in the Media Library (where they're not specifically checked) but fail in the Block Editor (where all image/* types are checked).

I’d love to hear your thoughts on this and discuss the best approach to resolving the inconsistency.

Last edited 4 weeks ago by sainathpoojary (previous) (diff)

@dilipbheda
4 weeks ago

#8 @dilipbheda
4 weeks ago

  • Keywords has-patch added

It seems that wp_get_default_extension_for_mime_type() ignores the upload_mimes filter because it uses wp_get_mime_types() directly, instead of get_allowed_mime_types(), which would include the values modified by the upload_mimes filter.

I've fixed it with the attached patch.

#9 @dilipbheda
4 weeks ago

I used the following filter to enable SVG image uploads.

function allow_svg_uploads( $mimes ) {
	$mimes['svg'] = 'image/svg+xml';
	return $mimes;
}
add_filter( 'upload_mimes', 'allow_svg_uploads' );

#10 @pratiklondhe
4 weeks ago

Test Report

Description

This report validates whether the indicated patch works as expected.

Patch tested: https://core.trac.wordpress.org/attachment/ticket/63302/63302.patch

Environment

  • WordPress: 6.9-alpha-20250418.114231
  • PHP: 8.1.29
  • Server: nginx/1.26.1
  • Database: mysqli (Server: 8.0.35 / Client: mysqlnd 8.1.29)
  • Browser: Firefox 136.0
  • OS: macOS
  • Theme: Twenty Twenty 2.9
  • MU Plugins: None activated
  • Plugins:
    • Query Monitor 3.17.2
    • Safe SVG 2.3.1
    • Test Reports 1.2.0

Actual Results

  1. ✅ Issue resolved with patch applied and using the custom code give above to enable SVG
  2. ❌ Issues still exists with Safe SVG plugin with patch applied.
Last edited 4 weeks ago by pratiklondhe (previous) (diff)

#11 @dilipbheda
4 weeks ago

@pratiklondhe Thanks for testing!

You're right, it's not working with the safe-svg plugin because it only allows SVG uploads in specific contexts using these hooks:

add_action( 'load-upload.php', array( $this, 'allow_svg_from_upload' ) );
add_action( 'load-post-new.php', array( $this, 'allow_svg_from_upload' ) );
add_action( 'load-post.php', array( $this, 'allow_svg_from_upload' ) );
add_action( 'load-site-editor.php', array( $this, 'allow_svg_from_upload' ) );

I tried calling allow_svg_from_upload() directly before these hooks, like this:

$this->allow_svg_from_upload();

add_action( 'load-upload.php', array( $this, 'allow_svg_from_upload' ) );
add_action( 'load-post-new.php', array( $this, 'allow_svg_from_upload' ) );
add_action( 'load-post.php', array( $this, 'allow_svg_from_upload' ) );
add_action( 'load-site-editor.php', array( $this, 'allow_svg_from_upload' ) );

And it worked!

Also found where the plugin uses the upload_mimes filter:
https://plugins.trac.wordpress.org/browser/safe-svg/tags/2.3.1/safe-svg.php#L134

#12 @SirLouen
4 weeks ago

  • Keywords changes-requested added; has-patch removed

@dilipbheda can you add a new patch to solve the issues that @pratiklondhe comment?

#13 follow-up: @dilipbheda
4 weeks ago

@SirLouen We can't fix this directly in the core because the issue is related to how the Safe SVG plugin handles its hooks. The hooks mentioned above don't work when uploading an image through the media block.

#14 in reply to: ↑ 4 @pbiron
4 weeks ago

Replying to pbiron:

I'll experiment more tomorrow and report findings.

OK, I've been able to reproduce the problem now...but only on a linux server, not my local Windows machine. Haven't yet figured out why it doesn't surface in Windows.

#15 @pbiron
4 weeks ago

I've now been able to reproduce in Windows.

What I've noticed is that things work (in both Windows & linux) while uploading from within an Image block when clicking on the Media Library button and then dragging/dropping the image into the media modal, but the error message reported by JB happens when clicking on the Upload button.

#16 in reply to: ↑ 7 ; follow-up: @pbiron
4 weeks ago

Replying to sainathpoojary:

  1. Block Editor path (wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php):
if (
    $prevent_unsupported_uploads &&
    isset( $files['file']['type'] ) &&
    str_starts_with( $files['file']['type'], 'image/' )
) {
    // Check if the image editor supports the type.
    if ( ! wp_image_editor_supports( array( 'mime_type' => $files['file']['type'] ) ) ) {
        return new WP_Error(
            'rest_upload_image_type_not_supported',
            __( 'The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.' ),
            array( 'status' => 400 )
        );
    }
}

Yup, this looks to be the cause. wp_image_editor_supports() eventually calls WP_Image_Editor_GD::supports_mime_type() or WP_Image_Editor_Imagick::supports_mime_type(), both of which return false for 'image/svg+xml'.

The problem is that SVG images don't need to have "responsive images generated"...so I'm not sure that calling wp_image_editor_supports() here is the right thing to do.

Perhaps we could introduce something like a wp_image_editor_needs_to_support() function (function name not great, suggertions welcome :-)) that applies a filter which tools like Safe SVG could hook into and return false, and then the change in WP_REST_Attachments_Controller::create_item_permissions_check() in 6.8 could be changed to something like:

if (
    $prevent_unsupported_uploads &&
    isset( $files['file']['type'] ) &&
    str_starts_with( $files['file']['type'], 'image/' )
) {
    // Check if the image editor supports the type.
    if (
        wp_image_editor_needs_to_support( array( 'mime_type' => $files['file']['type'] ) ) &&
        ! wp_image_editor_supports( array( 'mime_type' => $files['file']['type'] ) )
    ) {
        return new WP_Error(
            'rest_upload_image_type_not_supported',
            __( 'The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.' ),
            array( 'status' => 400 )
        );
    }
}

thoughts?

#17 in reply to: ↑ 13 @SirLouen
4 weeks ago

  • Keywords needs-patch added; changes-requested removed

Replying to dilipbheda:

@SirLouen We can't fix this directly in the core because the issue is related to how the Safe SVG plugin handles its hooks. The hooks mentioned above don't work when uploading an image through the media block.

As @sainathpoojary suggested, it seems a regression in 6.8 because of one of the latest changesets. Safe SVG was working in 6.7.2

Last edited 4 weeks ago by SirLouen (previous) (diff)

#18 in reply to: ↑ 16 @SirLouen
4 weeks ago

Replying to pbiron:

thoughts?

I'm trying to think of supported image types, and afaik, only svg can't support resizing and are the only ones not being converted, so, since this is an edge case, that could simply be handled by hard-coding it directly in the function you propose (instead of having to add another filter, because ultimately its going to become a 2-filter-sequence to support SVG after this, which is not ideal from my pov.

<?php
function wp_image_editor_needs_to_support( $args = array() ) {
        if ( isset( $args['mime_type'] ) && 'image/svg+xml' === $args['mime_type'] ) {
                return false;
        }
        return true;
}

#19 follow-up: @pbiron
4 weeks ago

@SirLouen I tend to agree, I was just trying to add some future proofing, in case some other image format in the future becomes common that doesn't need sub-sizes created.

This ticket was mentioned in PR #8714 on WordPress/wordpress-develop by @SirLouen.


4 weeks ago
#20

  • Keywords has-patch added; needs-patch removed

Rethinking on the idea by @pbiron of providing some sort of filtering to provide access to SVG uploads in block editor after
https://core.trac.wordpress.org/changeset/60084

The thing is that I believe that forcing users to add more hooks (over the hooks that have to be already added for SVG compatibility), is something undesirable. Maybe hard-coding image/svg+xml could be a little hard for future debugging or extensibility, or proofing in general. So the idea here is to provide some sort of descriptive term, that actually describes the faulting scenario: "If non-resizable formats are not considered, they won't be able to be uploaded in the block editor", by using some global constant.

Not gonna lie, I have not figured out where to best put this global const, so I've decided to place it a little at random and leave it to better criterion.

Trac ticket: https://core.trac.wordpress.org/ticket/63302

#21 in reply to: ↑ 19 @SirLouen
4 weeks ago

  • Keywords dev-feedback needs-testing has-testing-info added

Replying to pbiron:

@SirLouen I tend to agree, I was just trying to add some future proofing, in case some other image format in the future becomes common that doesn't need sub-sizes created.

I've come with the idea of adding a global constant for this purpose (future-proofing and providing a more descriptive idea of what's going on). As I've described, I still think that a double-filter to enable SVG is too much (moreover this is nothing helpful for the user, like the first filter, that is actually there for some sort of security purpose, in this case it's just a flaw in code, just because GD technically doesn't support resizing for a type of file that doesn't need resizing by its nature)

#22 @SirLouen
4 weeks ago

  • Keywords needs-unit-tests added

Todo: Adding in the current unit tests (if exist) this edge case is desirable.

#23 @adamsilverstein
4 weeks ago

  • Owner set to adamsilverstein
  • Status changed from new to assigned

#24 follow-ups: @adamsilverstein
4 weeks ago

After investigating changeset 60084, I found that two different implementations exist for handling unsupported image formats:|

Indeed, initially we handled only specific types, eventually we decided to include all supported types with the 'image/' prefix when running the handling check.

Media Library sets a warning flag but allows upload

The flag is later checked in JavaScript and uploading is actually prevented.

The problem is that SVG images don't need to have "responsive images generated".

This seems like the critical point: while having a mime type with an "image" prefix, SVG images are in fact "Scalable Vector Graphics" that can be scaled directly - unlike any other image type as far as I can tell.

For that reason I would prefer hard coding an exception for SVG's from the upload check, along with an inline comment to explain why, as well as a test validating the behavior.

I've come with the idea of adding a global constant for this purpose

This feels like too much, image formats change very rarely and I don't see us adding additional scalable formats in the future (are there any?). SVGs don't need resizing and should be included in this check. Is there a use case for being able to change that behavior?

Last edited 4 weeks ago by adamsilverstein (previous) (diff)

#25 in reply to: ↑ 24 @SirLouen
4 weeks ago

I've come with the idea of adding a global constant for this purpose

This feels like too much, image formats change very rarely and I don't see us adding additional scalable formats in the future (are there any?). SVGs don't need resizing and should be included in this check. Is there a use case for being able to change that behavior?

Yes I was exactly thinking this here, but with all the futureproofing thing, I came down to this alternative

The problem is that the check is picking supported formats from GD, and obv, SVG is not included, resulting in a failure. So, anything like "NON_RESIZABLE_FORMATS" (maybe not global, but at least local or at minimum a descriptive array variable, will help debug and come through in the future (agreeing with @pbiron) _just in case_ there is an unlikely new format in the future (instead of just hard-coding the format as I suggested previously)

Simply with this, I think this could be done. Which option do you like the most?

Last edited 4 weeks ago by SirLouen (previous) (diff)

#26 in reply to: ↑ 24 ; follow-up: @adamsilverstein
4 weeks ago

Yes I was exactly thinking this here, but with all the futureproofing thing, I came down to this alternative

A local variable would be fine to help clarify the purpose and might be easier to document.

#27 in reply to: ↑ 26 @SirLouen
4 weeks ago

Replying to adamsilverstein:

Yes I was exactly thinking this here, but with all the futureproofing thing, I came down to this alternative

A local variable would be fine to help clarify the purpose and might be easier to document.

Ok I updated the patch code with just the local variable

What it surprises me is that SVG supported by WP_Image_Editor_Imagick
https://imagemagick.org/script/formats.php#supported

https://i.imgur.com/jC0POjw.png

Not sure why its being ignored in the `wp_image_editor_supports part

#28 @adamsilverstein
4 weeks ago

What it surprises me is that SVG supported by WP_Image_Editor_Imagick

Interesting, does it actually resize them?

Not sure why its being ignored in the wp_image_editor_supports part

right, this should return true for your system, might be worth digging in a bit to see whats happening there.

#29 follow-up: @pbiron
4 weeks ago

looks like WP_Image_Editor_Imagick::supports_mime_type() results in a call to wp_get_default_extension_for_mime_type(), and asks if Imagick supports the returned extension.

wp_get_default_extension_for_mime_type() has a fixed assoc array that maps extensions to mime types. Of course, 'svg' => 'image/svg+xml' is not in that array. However, the mime_type filter is applied to that assoc array.

Unfortunately, Safe SVG does not hook into that filter. And so wp_get_default_extension_for_mime_type() can't find the right file extension to query Imagick for.

Whether Safe SVG wants to add a callback for the mime_type filter or not is up to them, but I don't think it really matters for 2 reasons

  1. SVGs don't need sub-sizes generated
  2. the upload should be allowed by the REST API even if Imagick isn't installed (i.e., GD is used for editing images)

#30 in reply to: ↑ 29 @SirLouen
4 weeks ago

Replying to pbiron:

Whether Safe SVG wants to add a callback for the mime_type filter or not is up to them, but I don't think it really matters for 2 reasons

  1. SVGs don't need sub-sizes generated
  2. the upload should be allowed by the REST API even if Imagick isn't installed (i.e., GD is used for editing images)

Good catch. By adding
'svg' => 'image/svg+xml'
to the wp_get_mime_types function, problem gets solved with Imagick

But as you said, SVG shouldn't really need resized individual files, nor Imagick should be a requirement for this purpose. Hence, I think that the solution of just using a referenced variable does the trick pretty well without the need of adding more hassle to the users with extra hooks.

Replying to adamsilverstein:

Interesting, does it actually resize them?

You can't resize them in the file editor. Probably for the same reason above. Everything is empty, the image, the sizings, etc...

right, this should return true for your system, might be worth digging in a bit to see whats happening there.

I was testing with the default docker container from wordpress-develop (for imagick support, setting PHP version to 8.2)

This ticket was mentioned in Slack in #core by jorbin. View the logs.


3 weeks ago

This ticket was mentioned in Slack in #core by jorbin. View the logs.


3 weeks ago

#33 @pbiron
3 weeks ago

@adamsilverstein Is there any chance you will be able to review the PR in time for this to get committed for 6.8.1 (RC1 next Mon, 2025-04-28, and GR next Wed 2025-04-30)?

#34 @adamsilverstein
3 weeks ago

yes, I will aim to get this in by monday.

#35 @pbiron
3 weeks ago

thanx Adam!

@adamsilverstein commented on PR #8714:


3 weeks ago
#36

I added a test in https://github.com/WordPress/wordpress-develop/pull/8714/commits/f2024a05748df58f87987aa47d1d80340a8d3929 - I verified this test fails on trunk while passing on this branch.

#37 @adamsilverstein
3 weeks ago

  • Keywords has-unit-tests commit added; dev-feedback has-testing-info needs-unit-tests removed

#38 @jorbin
3 weeks ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 60195:

Media: Don't try to resize image formats which can't be resized

While having a mime type with an "image" prefix, SVG images are in fact "Scalable Vector Graphics" that can be scaled directly.

Follow-up to [60084].

Props sirlouen, adamsilverstein, audrasjb, pbiron, sainathpoojary, dilipbheda, pratiklondhe.
Fixes #63302. See #61167.

#39 @jorbin
3 weeks ago

  • Keywords dev-feedback fixed-major added
  • Resolution fixed deleted
  • Status changed from closed to reopened

Reopening for backport considersation

#40 @desrosj
3 weeks ago

  • Keywords dev-reviewed added; dev-feedback removed

[60195] Looks good for backport.

#41 @desrosj
3 weeks ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 60196:

Media: Don't try to resize image formats which can't be resized

While having a mime type with an "image" prefix, SVG images are in fact "Scalable Vector Graphics" that can be scaled directly.

Follow-up to [60084].

Reviewed by desrosj.
Backports [60195] to the 6.8 branch.

Props sirlouen, adamsilverstein, audrasjb, pbiron, sainathpoojary, dilipbheda, pratiklondhe.
Fixes #63302. See #61167.

This ticket was mentioned in Slack in #core by pbiron. View the logs.


3 weeks ago

This ticket was mentioned in Slack in #core-media by enshrined. View the logs.


3 weeks ago

This ticket was mentioned in Slack in #core by bobbingwide. View the logs.


9 days ago

Note: See TracTickets for help on using tickets.