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

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.


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' ],
        ];
    }

}