Advertisement
Plugins

Attaching Files To Your Posts Using WordPress Custom Meta Boxes, Part 1

by

Over the course of the next two posts, we'll take a look at how we can leverage the WordPress API to define our own custom meta boxes for attaching a document (such as a PDF) to our WordPress pages. We'll also take a look at how to properly remove files should we choose to delete them from our posts.

A few months ago, Christopher Davis demonstrated how to create Custom WordPress Write/Meta Boxes (http://wp.tutsplus.com/tutorials/plugins/how-to-create-custom-wordpress-writemeta-boxes/). As mentioned in his article, custom meta boxes are incredibly powerful features that allow us to add various pieces of additional information to our WordPress posts and pages.

Of course, we're not limited to text or options such as radio buttons or checkboxes. We can also attach images and files to posts, pages, and other post types by taking advantage of custom meta boxes; however, dealing with file types requires a bit more code to properly handle uploads and deletions of the file.

Before getting started, it's important to note that this series assumes that we're working with the Twentyeleven Theme. Although the code will work with any WordPress Theme, this ensures that we're all working with the same codebase and should make it easier to follow along with the tutorial.


Defining The Custom Meta Box

First, let's create the post meta box. Specifically, the meta box should…

  • Be available on both posts and pages
  • Appear beside the post editor
  • Accept an input file

At this point, locate functions.php in the root of the Twentyeleven Theme directory. We'll be making all of our changes to the bottom of the file. We'll start by defining a function called add_custom_meta_boxes and it will be registered with the add_meta_boxes hook.

function add_custom_meta_boxes() {

} // end add_custom_meta_boxes
add_action('add_meta_boxes', 'add_custom_meta_boxes');

Next, let's define our custom meta box. First, we'll write the code after which I'll explain what the code is doing:

function add_custom_meta_boxes() {

	// Define the custom attachment for posts
	add_meta_box(
		'wp_custom_attachment',
		'Custom Attachment',
		'wp_custom_attachment',
		'post',
		'side'
	);
	
	// Define the custom attachment for pages
	add_meta_box(
		'wp_custom_attachment',
		'Custom Attachment',
		'wp_custom_attachment',
		'page',
		'side'
	);

} // end add_custom_meta_boxes
add_action('add_meta_boxes', 'add_custom_meta_boxes');

Notice that the following two calls to add_meta_box are nearly identical.

  • The first parameter is the ID of the meta box. This is used when saving the value.
  • The second parameter is the label. This value appears in the caption above the post meta box
  • The third value is the callback function that is used to actually define the markup that appears in the meta box. We'll get to this momentarily.
  • The fourth value tells WordPress the post type on which this custom meta box should appear. Since we want it on both posts and pages, we've defined it twice.
  • The final parameter defines where we want the meta box to appear. It can be either side, advanced, or normal. We've select side so that it appears beside the post editor

Setting Up The Callback

At this point, the custom meta box doesn't do anything. In fact, it doesn't even display anything:

This is because we haven't defined the callback function that is used generate the markup for the meta box. In order to do that, we need to define the function with the name that we listed it above. Specifically: 'wp_custom_attachment.'

The input should accept a PDF so we'll give a short description and the proper input element for accepting files:

function wp_custom_attachment() {

	wp_nonce_field(plugin_basename(__FILE__), 'wp_custom_attachment_nonce');
	
	$html = '

'; $html .= 'Upload your PDF here.'; $html .= '

'; $html .= ''; echo $html; } // end wp_custom_attachment

The first line of the code defines a nonce value in order to properly validate and secure our upload.

Next, we're simply setting up the markup for displaying the input field.

At this point, we've got a custom meta box that looks decent but doesn't actually work.


Saving The File

Now we're ready to save the file. First, we need to create a function that hooks into the save_post hook. Let's define that now:

function save_custom_meta_data($id) {

	/* --- security verification --- */
	if(!wp_verify_nonce($_POST['wp_custom_attachment_nonce'], plugin_basename(__FILE__))) {
	  return $id;
	} // end if
	  
	if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
	  return $id;
	} // end if
	  
	if('page' == $_POST['post_type']) {
	  if(!current_user_can('edit_page', $id)) {
	    return $id;
	  } // end if
	} else {
   		if(!current_user_can('edit_page', $id)) {
	    	return $id;
	   	} // end if
	} // end if
	/* - end security verification - */
	
} // end save_custom_meta_data
add_action('save_post', 'save_custom_meta_data');

Although this function doesn't actually save the value - not yet, at least - it includes a bit of code that ensures we're ready to save the file. Specifically, the function makes sure that the expected nonce value is present, that an automatic save is not occurring, and that the user attempting to save data has permissions to do so.

Now we're ready to begin validating and saving the file. When it comes to saving file-based custom meta data, additional code has to be introduced to properly handle indiosynchrocies of uploading files. First, we'll define the code then we'll explain it. The function should look like this:

function save_custom_meta_data($id) {

	/* --- security verification --- */
	if(!wp_verify_nonce($_POST['wp_custom_attachment_nonce'], plugin_basename(__FILE__))) {
	  return $id;
	} // end if
	  
	if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
	  return $id;
	} // end if
	  
	if('page' == $_POST['post_type']) {
	  if(!current_user_can('edit_page', $id)) {
	    return $id;
	  } // end if
	} else {
   		if(!current_user_can('edit_page', $id)) {
	    	return $id;
	   	} // end if
	} // end if
	/* - end security verification - */
	
	// Make sure the file array isn't empty
	if(!empty($_FILES['wp_custom_attachment']['name'])) {
		
		// Setup the array of supported file types. In this case, it's just PDF.
		$supported_types = array('application/pdf');
		
		// Get the file type of the upload
		$arr_file_type = wp_check_filetype(basename($_FILES['wp_custom_attachment']['name']));
		$uploaded_type = $arr_file_type['type'];
		
		// Check if the type is supported. If not, throw an error.
		if(in_array($uploaded_type, $supported_types)) {

			// Use the WordPress API to upload the file
			$upload = wp_upload_bits($_FILES['wp_custom_attachment']['name'], null, file_get_contents($_FILES['wp_custom_attachment']['tmp_name']));
	
			if(isset($upload['error']) && $upload['error'] != 0) {
				wp_die('There was an error uploading your file. The error is: ' . $upload['error']);
			} else {
				add_post_meta($id, 'wp_custom_attachment', $upload);
				update_post_meta($id, 'wp_custom_attachment', $upload);		
			} // end if/else

		} else {
			wp_die("The file type that you've uploaded is not a PDF.");
		} // end if/else
		
	} // end if
	
} // end save_custom_meta_data
add_action('save_post', 'save_custom_meta_data');

The new block of code does several things. Comments have been provided in order to give clarity, but here's what's happening:

  • First, we make sure the file array isn't empty
  • Next, we setup an array for the supported file types and verify that the uploaded file is of that type
  • Next, we use wp_upload_bits to copy the file to the server
  • Finally, if there are any errors, we'll halt execution and display them to the user.

A note on wp_upload_bits(http://codex.wordpress.org/Function_Reference/wp_upload_bits). This function is an alternative to wp_handle_upload(http://codex.wordpress.org/Function_Reference/wp_handle_upload). In my experience, wp_handle_upload has yielded some problems with certain server configurations such that it gives a false negative. By that, I mean that it claims that it has a problem uploading the file when, in reality, the file was actually uploaded.


Linking Up the File

At this point, we should be ready to provide a link to the file on our posts and our pages. In the Twentyeleven Theme directory, locate the two files single.php and page.php. Each file contains a line of code that looks like this:

get_template_part( 'content', 'single' );

Just below that line, we'll need to request the custom post meta information by doing this:

echo get_post_meta(get_the_ID(), 'wp_custom_attachment', true);

Specifically, this function is requesting the post meta data identified by 'wp_custom_attachment' associated with this post ID. Clear, right? The last parameter is telling WordPress that we want the result back in a string format (the alternative is in the format of an array and that's beyond the scope of this tutorial).

The final block of code should look like this:

get_template_part( 'content', 'single' );
echo get_post_meta(get_the_ID(), 'wp_custom_attachment', true);

Now, attempt to upload a file for a page or post. Load up the post and page in your browser. Permitting everything has gone correctly, you'll notice that ... oops ... you don't actually have the path to a file.


Update The Post Form

The problem is that, by default, the form element used to save all of the post information and its associated data doesn't accept file types. This can be fixed with adding one more function that hooks into the WordPress page life cycle:

function update_edit_form() {
    echo ' enctype="multipart/form-data"';
} // end update_edit_form
add_action('post_edit_form_tag', 'update_edit_form');

This will append the enctype attribute to the post editor form element so that file uploads will not be supported.

Now, let's try to upload a file a again. Locate your post or page with the custom post meta box and attempt to upload a PDF. If all goes well, you should be able to navigate to the post and/or page and see the URL to the file.


Linking It Up

The last step is the easiest. Next up, revisit the single.php and page.php files and wrap the call to the custom meta data request in an anchor such that it looks like this:



	Download PDF Here

At this point, you should be able to attach a custom PDF to your page and have a link appear at the bottom of the page content providing a link to the download. In the next post, we'll take a look at how we can provide some better styling for the download anchor as well as delete the file from the page using the WordPress API.

In the meantime, try experimenting with customizing the meta box even further. For example, attempt to include a custom label to provide content for the link.

Related Posts
  • Code
    WordPress
    Mastering WordPress Meta Data: Understanding and Using ArraysMetadata
    In the first part of this series, we covered what WordPress meta data is, how it can be retrieved, and the various data types (such as objects or arrays) in which it can be returned. Now it's time to learn about the different types of arrays. When you write an array manually you know what its structure is an what the name of each index is. But when you are building arrays by querying a database, you are going to need to do some detective work to determine the structure of the data returned and the names of the indexes.Read More…
  • Code
    Plugins
    Integrating Multiple Choice Quizzes in WordPress - Creating the BackendIntegrating multiple choice quizzes in wordpress
    Multiple choice questions are something that most of us have faced at least once in our life. We love them because we can provide correct answers by logically thinking about provided possibilities, even if we don't exactly know the correct answer. Also answering takes less time which makes it so popular. Creating a multiple choice quiz in WordPress can be a very exciting and profitable task. You can use it in your personal blog to attract more visitors, or you can create a premium section with advanced quizzes, or you can create quizzes focusing on popular certification exams. There are numerous possibilities for making it profitable.Read More…
  • Code
    Creative Coding
    Using Backbone Within the WordPress Admin: The Back EndThumbnai02l
    The rumours are true! The WordPress Admin Panel is now using Underscore and Backbone! This means that with minimal effort, we can begin to utilise these fantastic JavaScript libraries in our own plugins. This tutorial will show you exactly how you can do that. We'll create the Admin part of a Quiz plugin. We'll use a simple Custom Post Type to save Questions, and then within each question we'll add a meta box that will allow us to enter up to 4 answers and select which is the correct one. We'll be going through how to use templates, how to hook into click and key-up events, how to save data back to the WordPress database and most importantly, how to 'get your truth out of the Dom', as the creator Jeremy Ashkenas likes to put it.Read More…
  • Code
    Plugins
    Incorporating the jQuery Date Picker Into the Post Editor: Preparing the PluginDatepicker
    We cover a lot of topics on this blog - anything ranging from something as simple as how to include and require template files in WordPress projects to something such as an entire series on the Settings API, but I think there's always room to cover a straightforward How-To that covers a single, specific task within the context of WordPress. So, in this two-part series, we're going to take a look at how to introduce a jQuery date picker into our post editor so that we can associate a date with a given post.Read More…
  • Code
    Plugins
    How to Create a WordPress Avatar Management Plugin from Scratch: Finishing TouchesPreview
    Avatar Manager for WordPress is a sweet and simple plugin for storing avatars locally and more. Easily. Enhance your WordPress website by letting your users choose between using Gravatar or a self-hosted avatar image right from their profile screen. Improved workflow, on-demand image generation and custom user permissions under a native interface. Say hello to the Avatar Manager plugin.Read More…
  • Code
    Creative Coding
    Posting via the Front End: Advanced SubmissionPreview advanced submission
    Today, we will be continuing with our mini-series on inserting posts via the front end, but in this part we will be exclusively looking into how to manage custom meta fields which we may have within our post type. So, let's get ready and begin!Read More…