Essay
Get a WordPress attachment's file extension with wp_check_filetype()
Updated Justin Ahinon
To get a WordPress media attachment's file extension, pass its file path to wp_check_filetype(). The result contains ext (such as png) and type (such as image/png).
This example runs inside WordPress, in a plugin or theme. Replace 123 with your attachment's ID:
$attachment_id = 123;
$file = get_attached_file( $attachment_id );
$extension = false;
if ( $file ) {
$filetype = wp_check_filetype( $file );
$extension = $filetype['ext'];
}
if ( false !== $extension ) {
echo esc_html( strtoupper( $extension ) ); // PNG for an image.png attachment.
}
get_attached_file() retrieves the attachment's file path. Using that path avoids a problem with public URLs: a URL ending in image.png?version=2 won't match the extension check, which expects the extension at the end of the string.
If WordPress doesn't recognize the extension in its allowed MIME types, both ext and type are false. Check that before formatting the result.
Why I needed the extension
While working on WP Media Assistant in 2019, I needed readable extensions for the images in the media library. I used them to generate graphs with FusionCharts.
I first tried extracting the extension with PHP string functions. Finding the WordPress equivalent took longer than I expected, partly because I didn't know how to phrase the search. When developing for WordPress, I prefer to use its native functions where they fit. wp_check_filetype() gave me the extension and MIME type together.
Get image extensions from the media library
For several attachments, query their IDs and check each file in a loop. This function processes up to 100 images at a time:
function co_images_extensions( $page = 1 ) {
$query = new WP_Query( array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'post_status' => 'inherit',
'posts_per_page' => 100,
'paged' => max( 1, (int) $page ),
'fields' => 'ids',
'orderby' => 'ID',
'order' => 'ASC',
) );
$extensions = array();
foreach ( $query->posts as $attachment_id ) {
$file = get_attached_file( $attachment_id );
if ( ! $file ) {
continue;
}
$filetype = wp_check_filetype( $file );
if ( false !== $filetype['ext'] ) {
$extensions[] = strtoupper( $filetype['ext'] );
}
}
return array(
'extensions' => $extensions,
'pages' => (int) $query->max_num_pages,
);
}
$result = co_images_extensions( 1 );
// $result['extensions'] might contain array( 'PNG', 'JPG', 'PNG' ).
// Request pages 2 through $result['pages'] to process the remaining images.
The function keeps duplicate extensions: three PNG images produce three PNG entries. That lets you count how many images use each format afterward. It skips missing paths and unknown extensions, and returns an empty extensions array when the library is empty. Collect the results from every page before counting them. A page with no recognized extensions can still have more pages after it.
WP_Query handles the attachment selection and pagination. Setting posts_per_page to 100 limits how many images each query returns. A value of -1 would load every matching image at once. The original 2019 source is still available for reference.
File extension or MIME type?
If you only need the MIME type stored on the attachment, use get_post_mime_type( $attachment_id ). It returns a value such as image/jpeg, rather than a filename extension such as jpg or jpeg.
wp_check_filetype() checks the filename, not the file's contents. That suits a chart of media-library extensions, but it doesn't validate an upload's contents. WordPress also provides wp_check_filetype_and_ext() for checking a file against its proposed filename.