While WordPress easily displays images attached to your pages and posts (even without an attachment.php file), the other allowed media types (audio, video, document, text, archive, code, interactive) don't get the same love – save a direct link to the attachment file. But, you don't have to resort to uploading your audio, video, or other non-image media attachments elsewhere (like YouTube) in order to display them on your WordPress site. Using the default Twenty Eleven theme as an example, I'll show you WordPress' built-in functions for sharing the love with non-image media attachments.
How WordPress Handles Attachments by Default
Under the hood, media items are just WordPress posts, therefore, they are displayed according to the WordPress template hierarchy. The template loader does a check to see if the post is an attachment and has an attachment template. If an attachment template does not exist, WordPress will fall back to the single post template or the default index.php template (if the single post template does not exist).
Template Check
In the single post or index.php templates, WordPress themes will likely display the content using the_content
. This function has a default filter attached to it – prepend_attachment
– that will automatically add an attachment link to the page (using the wp_get_attachment_link
function) if it determines that this is an attachment post. However, the arguments used here in the call to wp_get_attachment_link
will only provide actual display for image attachments – non-image attachment files only get a direct link to the attachment file. (Where's the love?) We could potentially display more than just a link for non-image attachments with a simple change of arguments to wp_get_attachment_link
, but unfortunately we don't have a way to change the arguments before the function is called.
Default Image Attachment Display vs. Default Non-Image Attachment Display
So let's take a look at what we can do to show our non-image attachments some love.
Taking Control of Non-Image Media Attachment Display
Step 1 Determine the File Type
The first thing we'll do is determine the file type of the attachment. WordPress allows uploading of several file types, found in the get_allowed_mime_types
function shown below.
Default Allowed File Types
Although the Media Library admin screen only shows filters for the three default file types, the Edit page for each media item shows the exact file type. The file type is in the MIME format (MIME is a long-standing standard for classifying file types on the Internet) which has two parts: type and subtype separated by the /. In the image below, the type is "video" and the subtype is "mp4." This knowledge will come in handy for step 2.
Default File Types Shown in Media Library
File Types Shown on Edit Media Page
Built-In WordPress Function
WordPress has a built-in function for determining the file type of an attachment using the attachment post ID.
get_post_mime_type($ID)
This function will return the file type in MIME format, just as it's shown on the media item's edit page in the admin.
Now we're ready to take control of displaying non-image attachments in our theme template files.
Step 2 Create Theme Template File
Template Hierarchy
As shown in the image, the WordPress template hierarchy has four possible attachment templates it will look for after it determines that we are displaying an attachment post. We can either handle the display of each file type in the attachment.php file or we can create separate template files for each MIME type and/or MIME subtype. Let's take a look at these options.
Option 1. attachment.php File
We can handle the display of each file type in attachment.php using our handy get_post_mime_type
function.
First, we'll get the file type of the attachment (while inside the loop):
<?php $type = get_post_mime_type( $post->ID ); ?>
Then, we can do a switch statement on the file type to provide the code to display each type:
<?php switch ( $type ) { case '{mimetype}/{mimesubtype}': // code to display file type break; default: // default code ?>
So if we'd like to display audio (mp3) and video (mp4) attachments, our switch statement would look like this:
<?php switch ( $type ) { case 'audio/mpeg': // code to display file type break; case 'video/mp4': // code to display file type break; default: // default code ?>
Using attachment.php is great if you only have a few file types to display (or your display for each file type will follow the same basic layout) as it allows us to keep our code in one file. If we have several file types and/or you plan to customize the display layout for each file type, you'll want to take a look at option 2.
Option 2. $mimetype
.php, $mimesubtype
.php, or $mimetype
_$mimesubtype
.php
attachment.php
is actually the fallback template for template files with the name of the MIME type or MIME subtype of the current attachment post. WordPress will look for files with names like $mimetype
.php, $mimesubtype
.php, or $mimetype
_$mimesubtype
.php before falling back to attachment.php.
So instead of calling get_post_mime_type
and using a switch statement, we can just create a template file with the name of the MIME type or subtype:
- audio.php
- mpeg.php
- audio_mpeg.php
and place the code to display that file type.
Note: The file names are listed in the order in which WordPress will call them. So $mimetype
.php first, then fallback to $mimesubtype
.php, then fallback to $mimetype
_$mimesubtype
.php.
Now let's look at some examples.
Examples
Displaying Documents
I don't know about you, but I personally dislike having to download a document to my computer just to view it. Let's enlist the help of the embeddable Google Docs Viewer. It can display PDFs, spreadsheets, presentations and many other file types listed in Google Help. There's no requirement for your documents to be hosted on Google Docs as it will embed a viewer right in the page by passing it a file URL and setting the embedded parameter to true.
Here's how we would handle displaying documents using the Google Docs Viewer in attachment.php after getting the file type:
switch( $type ) { case 'application/pdf': case 'application/msword': ?> <iframe src="http://docs.google.com/viewer?url=<?php echo wp_get_attachment_url( $post->ID ) ?>&embedded=true" width="591" height="600" style="border: none;"></iframe> <?php break; default: // default code break; }
Or, we could create one of the following template files:
- application.php
- pdf.php
- application_pdf.php
and place the following code where you'd like to display the content inside the loop:
<iframe src="http://docs.google.com/viewer?url=<?php echo wp_get_attachment_url( $post->ID ) ?>&embedded=true" width="591" height="600" style="border: none;"></iframe>
Notice that we are passing the URL of the attachment file to the Google Docs viewer using the wp_get_attachment_url
function.
Final Result:
Audio
To display (play) audio files uploaded to WordPress and provide a consistent cross-browser experience, we're going to enlist the help of the lightweight audio.js library that allows us to use the HTML5 audio
tag anywhere, falling back to flash in browsers that don't support HTML5 audio yet.
First, download and place the audio.js files in your theme. Then, in your functions.php file, add the code to enqueue the audio.js javascript on attachment pages only (following best practices). I'm sure there are other ways to do this – including using the recommended wp_enqueue_scripts
action and some conditional statements – however, I'm going to illustrate the method in this article: Quick Tip: Including JavaScript and CSS Only On Certain Site Pages
add_filter( 'attachment_template', 'ncb_attachment_template' ); function ncb_attachment_template( $template_path ) { wp_enqueue_script( 'audio-js', get_template_directory_uri() . '/js/audiojs/audiojs/audio.min.js' ); add_action( 'wp_head', 'ncb_audio_js' ); return $template_path; } function ncb_audio_js() { echo '<script>audiojs.events.ready(function() { var as = audiojs.createAll(); }); </script>'; }
Then, we can add the following code to our attachment.php file:
<?php case 'audio/mpeg': ?> <audio controls><source src="<?php echo wp_get_attachment_url( $post->ID ); ?>" type="audio/mpeg" /></audio> <?php break; ?>
Here's our full switch statement up to this point:
<?php switch( $type ) { case 'application/pdf': case 'application/msword': ?> <iframe src="http://docs.google.com/viewer?url=<?php echo wp_get_attachment_url( $post->ID ) ?>&embedded=true" width="591" height="600" style="border: none;"></iframe> <?php break; case 'audio/mpeg': ?> <audio><source src="<?php echo wp_get_attachment_url( $post->ID ); ?>" type="audio/mpeg" /></audio> <?php break; default: // default code break; }
Or, we could create one of the following template files:
- audio.php
- mpeg.php
- audio_mpeg.php
and add our audio code inside the loop where we'd like to display the content:
<audio><source src="<?php echo wp_get_attachment_url( $post->ID ); ?>" type="audio/mpeg" /></audio>
Note: If you use file type template files, the JavaScript needs to be enqueued on those pages only.
Final Result:
Video
We can display (play) video files uploaded to WordPress much the same as audio, except we're going to enlist the help of the video.js library that allows us to use the HTML5 video
tag anywhere, falling back to flash in browsers that don't support HTML5 video yet.
Just as with audio, we'll download the files, add them to our theme directory, and enqueue the video.js javascript on attachment pages only, save for the addition of a CSS file:
wp_enqueue_script( 'video-js', get_template_directory_uri() . '/js/video-js/video.min.js' ); wp_enqueue_style( 'video-js-css', get_template_directory_uri() . '/js/video-js/video-js.min.css' );
Here's the full functions.php snippet:
add_filter( 'attachment_template', 'ncb_attachment_template' ); function ncb_attachment_template( $template_path ) { wp_enqueue_script( 'audio-js', get_template_directory_uri() . '/js/audiojs/audiojs/audio.min.js' ); add_action( 'wp_head', 'ncb_audio_js' ); wp_enqueue_script( 'video-js', get_template_directory_uri() . '/js/video-js/video.min.js' ); wp_enqueue_style( 'video-js-css', get_template_directory_uri() . '/js/video-js/video-js.min.css' ); return $template_path; } function ncb_audio_js() { echo '<script>audiojs.events.ready(function() { var as = audiojs.createAll(); }); </script>'; }
Then, we can add the following code to our attachment.php file:
<?php case 'video/mp4': ?> <video class="video-js vjs-default-skin" controls data-setup="{}"><source src="<?php echo wp_get_attachment_url( $post->ID ) ?>" type='video/mp4' /></video>'; <?php break;
Here's our full switch statement:
<?php switch( $type ) { case 'application/pdf': case 'application/msword': ?> <iframe src="http://docs.google.com/viewer?url=<?php echo wp_get_attachment_url( $post->ID ) ?>&embedded=true" width="591" height="600" style="border: none;"></iframe> <?php break; case 'audio/mpeg': ?> <audio controls><source src="<?php echo wp_get_attachment_url( $post->ID ); ?>" type="audio/mpeg" /></audio> <?php break; case 'video/mp4': ?> <video class="video-js vjs-default-skin" controls data-setup="{}"><source src="<?php echo wp_get_attachment_url( $post->ID ) ?>" type='video/mp4' /></video>'; <?php break; default: // default code break; }
Or, we could create one of the following template files:
- video.php
- mp4.php
- video_mp4.php
and add our video code inside the loop where we'd like to display the content:
<video class="video-js vjs-default-skin" controls data-setup="{}"><source src="<?php echo wp_get_attachment_url( $post->ID ) ?>" type='video/mp4' /></video>
Remember: When using file type template files instead of attachment.php, you will need to change the name of the filter used to call the function that enqueues your JavaScript.
Final Result:
Summary
Non-image media attachments in WordPress need love, too! Using only two WordPress functions, you can keep your media files on your site and customize the display and layout of any of the allowed file types.
Download and/or fork the working code on Github.
References in This Article
WordPress functions
the_content
prepend_attachment
wp_get_attachment_link
get_allowed_mime_types
get_post_mime_type
wp_get_attachment_url
WordPress template files
- attachment.php
- index.php
- single.php
$mimetype
.php$mimesubtype
.php$mimetype
_$mimesubtype
.php
Comments