How to: Display Post Attachments in WordPress

File attachments are not new to WordPress — you can attach almost any kind of file to your posts, pages and custom post types. There’s also the Media Manager where you can upload files without attaching them to a certain post or page. Attachments are most commonly used to display images in the post content, but sometimes also used to link to files that are relevant to the post. For example, you might want to attach the complete source code for a tutorial post for readers to download, or an icon set giveaway with a download link to an archive.

WordPress allows to link to attached files from within the post content which is the most common scenario, but today I’ll show you a different approach. In this post I’ll create a child theme based on Twenty Eleven (again) and have it display all the attached files to each post in a nice looking list at the end of the post content. I’ll be using a few simple actions and filters to hook to the post content, as well as attach a stylesheet which will make the list visually appealing by providing different icons for different file types.

Why Child Theme? And Why Twenty Eleven?

I’m afraid I don’t have a good enough reason for this. Child themes are relatively new so practicing this kind of stuff on child themes instead of plugins will give you some good experience, experience you didn’t have with plugins. I also think that any editions to visual side of your website should be done using child themes and let plugins have the rest. Why Twenty Eleven? You might have noticed that I’m obsessed with Twenty Eleven, starting with a Twenty Eleven review and following up by a tutorial on how to add a color scheme to Twenty Eleven.

In this tutorial I’ll be using the same child theme techniques (as in the color scheme tutorial), and in fact, I’ll be using my same old functions.php file and simply adding some more code to that.

Understanding Post Attachments

Behind the scenes, post attachments are very like posts and pages themselves. They’ve got a title, description (or content) and a permalink. In addition post attachments come with a file mime type and an absolute link to the file itself (don’t confuse with permalink). The attachment post parent is set to the post or page to which the file was uploaded, or set to 0 if it wasn’t attached to one. The post status is inherited from the parent post, meaning if the parent post is a draft, the attachment post is considered to be a draft as well. And if it’s published then the attachment post is published too.

Hopefully you’ve got a local WordPress installation running with the Twenty Eleven theme, so go ahead and create a new post with some lorem ipsum text, and attach a few files to that post, of different mime types. In this tutorial I’ll use an image, a word document, a flash file, a PDF file and a zip archive. Give each of the attachments to your post a relevant name, try to describe the contents of the file, while I’ll describe the type of the file for illustration purposes.

Post Attachments Uploader

After you’ve done that, don’t insert any of the uploaded files in your post. Simply close the file manager dialog box and publish your post. Nothing strange so far, right?

Displaying the Post Attachments

Now comes the fun part, open up that functions.php file of your child theme. We’re going to use a filter called the_content and before returning the post content, we’ll append our attachments list to it. Here’s the code snippet:

add_filter( 'the_content', 'my_the_content_filter' );
function my_the_content_filter( $content ) {
	global $post;

	if ( is_single() && $post->post_type == 'post' && $post->post_status == 'publish' ) {
		$attachments = get_posts( array(
			'post_type' => 'attachment',
			'posts_per_page' => 0,
			'post_parent' => $post->ID
		) );

		if ( $attachments ) {
			$content .= '<h3>Attachments</h3>';
			$content .= '<ul class="post-attachments">';
			foreach ( $attachments as $attachment ) {
				$class = "post-attachment mime-" . sanitize_title( $attachment->post_mime_type );
				$title = wp_get_attachment_link( $attachment->ID, false );
				$content .= '<li class="' . $class . '">' . $title . '</li>';
			}
			$content .= '</ul>';
		}
	}

	return $content;
}

It’s pretty easy to understand this. The filter is executed when the Twenty Eleven template files use the function called the_content which, just like it sounds, displays the post contents, so we’re hooking to that. We’re declaring $post as a global variable and that’s where the current post is stored when we’re in the loop. After some checks to make sure we’re acting on a single post which is published, we use the get_posts functions to give us all the attachments (posts per page set to zero means unlimited) that are attached (children of) the current post ID, which is their parent.

Then goes a check to make sure the attachments array is not empty — we don’t want to print the attachments heading if there are no files, right? We’re appending the new stuff to the $content variable which is returned at the end, starting with the attachments heading, the opening unordered list tag and followed by a foreach loop that walks through each attachment and creates a list item.

The $class variable is generated based on the current attachment’s mime type, we’ll use these classes later in CSS to style file types differently. The wp_get_attachment_link returns a hyper link to the attached file. After the foreach loop ends, don’t forget to close the unordered list tag. And as I said, the $content variable is returned at the end, don’t forget that, otherwise you’ll end up with an empty content for each post.

Following the code above, this should generate a simple heading and a list of file attachments for each post that has any. Here’s what my post now looks like:

Post Attachments Plain

Adding Icons to the Post Attachments

So far so good, but we’re all used to seeing the icons for every file type in attachment lists, right? So that’s what we’re going to do in this step, with the help of those classes from mime types that we set in the list earlier. So create a new file in your child theme’s directory, call it attachments.css. Use the wp_print_styles action and add your stylesheet using wp_enqueue_style, like this:

add_action( 'wp_print_styles', 'my_enqueue_style' );
function my_enqueue_style() {
	wp_enqueue_style( 'post-attachemnts', get_stylesheet_directory_uri() . '/attachments.css', array(), null );
}

Pretty straightforward, right? Now comes the really fun part. Go out there and find a nice looking icon set with file types. You can use ones used in your operating system or you can use the icons that Apache provides. A good place to look for free icons is gnome-look.org but today I’ll be using a great icon set I stumbled across a few days ago — Fugue Icons, a set of over 3000 nice looking icons, including ones for different file types. Licensed under Creative Commons Attribution 3.0, so read carefully before using them in your projects.

So download the icons and place them in your child theme somewhere (I used the icons folder). Fire up your stylesheet and create a few rules for your attachments list. I started by styling the unordered list itself, and then the list items with a “one rule for all”. This is done for fallback, in case there’s no suitable entry for the attachement’s mime type, it will not come without an image.

ul.post-attachments {
	list-style: none;
	margin-left: 0;
}

li.post-attachment {
	background: url(icons/document.png) 0 4px no-repeat;
	padding-left: 24px;
}

This gave each of my list entries a nice looking document icon, like this:

WordPress File Attachments Identical

Now, use your inspector to figure out the extra class name that’s been given to each of your attachment files, you’ll see that mime types are sanitized there, ready for use in your stylesheets, for example mime-imagejpeg for JPEG images and mime-applicationzip for Zip archives. Here’s how I structured my CSS to display the correct icons for my file types.

.post-attachment.mime-imagejpeg,
.post-attachment.mime-imagepng {
	background-image: url(icons/document-image.png);
}

.post-attachment.mime-applicationzip {
	background-image: url(icons/document-zipper.png);
}

.post-attachment.mime-applicationpdf {
	background-image: url(icons/document-pdf.png);
}

.post-attachment.mime-applicationx-shockwave-flash {
	background-image: url(icons/document-flash-movie.png);
}

.post-attachment.mime-applicationmsword {
	background-image: url(icons/document-word.png);
}

As you can see, I took JPEG and PNG images, Zip, PDF, SWF and Microsoft Word files. Go ahead and extend the list to all the suitable icons available in your set and don’t worry if you miss one, since there’s always the fallback to the default icon if an entry for the mime type doesn’t exist. Here’s how my new list looks:

WordPress Post Attachments

Wrapping Up

That’s all folks. Your posts now have sweet looking attachments in them with links to the attachment files and descriptive icons. First question I’d ask myself is how would I remove an attachment from the list without deleting the attachment file. Well this is not about removing but about hiding, since an attached file is an attached file, and if you’re displaying attached files you’re displaying every attached file (did this make sense?).

If you don’t want your files to show up as attachments don’t attach them. But if you want to use them in your post (like images for instance) content, use the Media Library to upload the files without attaching them to posts. This is the simplest solution I can think of ;)

Anyways, hope you’ve learned something new today and tell us how you’re dealing with post attachments. Should you have any questions or suggestions, the comments section below is available. Thanks for being with us and don’t forget that we’re on Facebook too!