By default, WordPress cannot upload SVG for security reasons. But what to do when it is very necessary? There is a solution!

WordPress Error for SVG
When I try to download SVG, I get the message "Sorry, this file type is not valid for security reasons."

For information on whether SVG will be allowed to be uploaded to WordPress by default and why developers avoid it, see ticket #24251 Reconsider SVG inclusion to get_allowed_mime_types.

Plugin ― you can also enable svg loading via the Safe SVG plugin. Among other things, it clears the code of the downloaded file.

See also: Allowing the download of prohibited file types

Step 1 - Include SVG in the list of files allowed for download

To do this, let's use the upload_mimes hook, which allows you to change the list of files available for download by MIME type.

add_filter( 'upload_mimes', 'svg_upload_allow' ); # Adds SVG to the list of files allowed for loading. function svg_upload_allow( $mimes ) { $mimes['svg'] = 'image/svg+xml'; return $mimes;
}

Sometimes this code is enough, but not for all svg files. Let's see why.

The real MIME type of svg file, which in WP is defined by the php function finfo_file() (see code wp_check_filetype_and_ext() ) can be of two variants:

  • image/svg+xml is when there is an xml header in the svg code.
  • image/svg - When the svg code has only a tag , without any headers.<svg>

You need to add both of these options here, but you can only add one, so this code alone is not enough and a second step is needed.

Step 2 - Spoofing the SVG mime type

 

As described above, the previous code is not sufficient to solve the problem. More precisely, as a result of checking and mismatching the specified MIME type and the actual (obtained by WP itself) MIME type, the type will simply be reset. Bring it back to us will help hook wp_check_filetype_and_ext.

add_filter( 'wp_check_filetype_and_ext', 'fix_svg_mime_type', 10, 5 ); # FIX MIME type for SVG files. function fix_svg_mime_type( $data, $file, $filename, $mimes, $real_mime = '' ){  WP 5.1 + if(  version_compare( $GLOBALS['wp_version'], '5.1.0', '>=' ) ){ $dosvg = in_array( $real_mime, [ 'image/svg', 'image/svg+xml' ] ); } else { $dosvg = ( '.svg' === strtolower( substr( $filename, -4 ) ) ); }  mime type has been reset, fix it  and also check the user right if( $dosvg ){   resolve if( current_user_can('manage_options') ){ $data['ext'] = 'svg'; $data['type'] = 'image/svg+xml'; }  deny else { $data['ext'] = false; $data['type'] = false; } } return $data;
}

If you remove the administrator check from the code above, the code will become unsafe and potentially open a hole in the protection of the site.

In the code above, a check for the WP version has been added. With WP 5.1.0, thanks to the ticket of the author of this site, the parameter . It allows you to make a more reliable validation of the file— at the mime level of determining the file type by its code, not by extension.$real_mime

I also recommend limiting the size of the downloaded svg file, for example, no more than 50kb. SVG files are usually small and a large size may indicate that there is some bad code in the file.

The code above is enough for WordPress to allow SVG to be uploaded to the media library. The next step is purely visual.

Display SVG in the Media Library

After the steps are done, SVG files will be displayed as documents, not images:

Error SVG

The code generated by the wp_print_media_templates() function from the wp-includes/media-template file.php is responsible for marking these blocks with images:

<div class="thumbnail"> <# if ( data.uploading ) { #> <div class="media-progress-bar"><div style="width: {{ data.percent }}%"></div></div> <# } else if ( 'image' ===  data.type && data.sizes ) { #> <div class="centered"> <img src="{{ data.size.url }}" draggable="false" alt="" /> </div> <# } else { #> <div class="centered"> < # if ( data.image && data.image.src && data.image.src !== data.icon ) { #> <img src="{{ data.image.src }}" class="thumbnail" draggable="false" alt="" /> <# } else if ( data.sizes && data.sizes.medium  ) { #> <img src="{{ data.sizes.medium.url }}" class="thumbnail" draggable="false" alt="" /> <# } else { #> <img src="{{ data.icon }}" class="icon" draggable="false" alt="" />  <# } #> </div> <div class="filename"> <div>{{ data.filename }}</div> </div> <# } #> </div>

The point of the code is that it will display an image if

  • it has a src property (image link) and is not equal to a link to the document icon (any file is essentially a document);
  • or if the image has a medium size (the svg file is not sprinkled at all).

The SVG file has neither the first nor the second, so we need to simulate one of these options ourselves and the filter wp_prepare_attachment_for_js will help us with this, use any of the options to taste.

Option 1 - With file name output

  SVG Error in WP
add_filter( 'wp_prepare_attachment_for_js', 'show_svg_in_media_library' ); # Generates data to display SVG as images in the media library. function show_svg_in_media_library( $response ) { if ( $response['mime'] === 'image/svg+xml' ) {  With file name displayed $response['image'] = [ 'src' => $response['url'], ]; } return $response;
}

Option 2 - No file name display

  SVG
add_filter( 'wp_prepare_attachment_for_js', 'show_svg_in_media_library' ); # Generates data to display SVG as images in the media library. function show_svg_in_media_library( $response ) { if ( $response['mime'] === 'image/svg+xml' ) {  Without displaying file name $response['sizes'] = [ 'medium' => [ 'url' = > $response['url'], ],  when editing a picture 'full' => [ 'url' => $response['url'], ], ]; } return $response;
}