How to assign multiple file-mime-types to extension?

To allow extra file types for upload, we use:

add_filter('mime_types', 'my_mimes');
function my_mimes($all)
{
    $all['zip'] = 'application/zip';
    return $all;
}

But how to assign multiple file types to 1 extension? For example, zip extension might have application/zip mime and also application/x-zip (like, coming from 7zip). This way doesn't work:

$all['zip'] = ['application/zip', 'application/x-zip'] ;

Topic ziparchive uploads Wordpress

Category Web


I had a similar problem to solve where .zip files were seen as application/zip by PHP but detected as application/x-zip-compressed.

My workaround was to add this new value with an invented key

'xzip' => '`application/x-zip-compressed';

See https://github.com/WordPress/gutenberg/issues/23510

See also two WordPress TRACs:


A little improved birgire's answer. Had to add multiple mime types for svg, but because svg is forbidden by default, had to add dynamic filter to upload_mimes:

class Multiple_Mimes {

    public static function init() {
        add_filter( 'wp_check_filetype_and_ext', [self::class, 'add_multiple_mime_types'], 99, 3 );
    }


    public static function add_multiple_mime_types( $check, $file, $filename ) {
        if ( empty( $check['ext'] ) && empty( $check['type'] ) ) {
            foreach ( self::get_allowed_mime_types() as $mime ) {
                remove_filter( 'wp_check_filetype_and_ext', [ self::class, 'add_multiple_mime_types' ], 99 );
                $mime_filter = function($mimes) use ($mime) {
                    return array_merge($mimes, $mime);
                };

                add_filter('upload_mimes', $mime_filter, 99);
                $check = wp_check_filetype_and_ext( $file, $filename, $mime );
                remove_filter('upload_mimes', $mime_filter, 99);
                add_filter( 'wp_check_filetype_and_ext', [ self::class, 'add_multiple_mime_types' ], 99, 3 );
                if ( ! empty( $check['ext'] ) || ! empty( $check['type'] ) ) {
                    return $check;
                }
            }
        }

        return $check;
    }


    public static function get_allowed_mime_types(){
        return [
            [ 'svg' => 'image/svg' ],
            [ 'svg' => 'image/svg+xml' ],
        ];
    }

}

Note the stricter mime type check since WP 5.0.1 where the file content and file extension must match. See e.g. this recent question on the vtt file type.

Secondary mime type for a given file extension

Here's a suggestion how to support a secondary mime type for a given file extension. Let's take .vtt as an example. The core assumes the mime type of text/vtt for that file extension, but the real mime type from finfo_file() can sometimes be text/plain. The finfo_file() seems to be somewhat buggy. We can add a support for it as a secondary mime type with:

/**
 * Support for 'text/plain' as the secondary mime type of .vtt files,
 * in addition to the default 'text/vtt' support.
 */
add_filter( 'wp_check_filetype_and_ext', 'wpse323750_secondary_mime', 99, 4 );    

function wpse323750_secondary_mime( $check, $file, $filename, $mimes ) {
    if ( empty( $check['ext'] ) && empty( $check['type'] ) ) {
        // Adjust to your needs!
        $secondary_mime = [ 'vtt' => 'text/plain' ];

        // Run another check, but only for our secondary mime and not on core mime types.
        remove_filter( 'wp_check_filetype_and_ext', 'wpse323750_secondary_mime', 99, 4 );
        $check = wp_check_filetype_and_ext( $file, $filename, $secondary_mime );
        add_filter( 'wp_check_filetype_and_ext', 'wpse323750_secondary_mime', 99, 4 );
    }
    return $check;
}

Here we use the wp_check_filetype_and_ext filter to see if the check failed. In that case we run wp_check_filetype_and_ext() again but now only on our secondary mime type, disabling our filter callback in the meanwhile to avoid an infinite loop.

Multiple mime types for a given file extension

If we need to support more than two mime types for the .vtt files, then we can expand the above snippet with:

/**
 * Demo: Support for 'text/foo' and 'text/bar' mime types of .vtt files,
 * in addition to the default 'text/vtt' support.
 */
add_filter( 'wp_check_filetype_and_ext', 'wpse323750_multi_mimes', 99, 4 );

function wpse323750_multi_mimes( $check, $file, $filename, $mimes ) {
    if ( empty( $check['ext'] ) && empty( $check['type'] ) ) {
        // Adjust to your needs!
        $multi_mimes = [ [ 'vtt' => 'text/foo' ], [ 'vtt' => 'text/bar' ] ];

        // Run new checks for our custom mime types and not on core mime types.
        foreach( $multi_mimes as $mime ) {
            remove_filter( 'wp_check_filetype_and_ext', 'wpse323750_multi_mimes', 99, 4 );
            $check = wp_check_filetype_and_ext( $file, $filename, $mime );
            add_filter( 'wp_check_filetype_and_ext', 'wpse323750_multi_mimes', 99, 4 );
            if ( ! empty( $check['ext'] ) ||  ! empty( $check['type'] ) ) {
                return $check;
            }
        }
    }
    return $check;
}

I hope you can test it further and adjust it to your needs.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.