Adding Custom Meta Boxes to Upload Media

Example of meta box created with file uploaded and file path listed on WP dashboardIn this post, we’ll go through the steps of adding a custom meta box to upload PDF media files. In this example, I’m attaching it to an “Events” Custom Post Type.

Note: for the purposes of this tutorial, I haven’t done my due diligence as far as escaping all my data or making it look tidy as far as what emerges on your dashboard. I’ll leave that in your very capable hands. 🤓

Adding a custom meta box to upload media

Using add_meta_box, we’re adding several parameters. The first parameter is the ID of the box. This is used when we save the value. The second parameter is the label which is what will appear in the text above the meta box. The third value is the callback function that is used to define the markup for the box (more on this further below). The fourth value is what tells WordPress the post type where this customization should be added (ie: posts, pages, or a custom post type). The final parameter used defines where we want the box to appear (side, advanced or normal).

/**
 * Add custom attachment metabox.
 */
function add_custom_meta_boxes() {
	add_meta_box( 
		'wp_custom_attachment',
		'PDF File',
		'wp_custom_attachment',
		'events',
		'side'
	) ;
}
add_action( 'add_meta_boxes', 'add_custom_meta_boxes' );

Markup for Custom Meta box

Nothing will happen at this point because we haven’t defined wp_custom_attachment (the third parameter from above). Below is where we write the function that creates that markup for the custom meta box. Setting up the nonce field prior to our markup is what properly validates and secures the uploaded file.

/**
 * Custom attachment metabox markup.
 */
function wp_custom_attachment() {
	wp_nonce_field( plugin_basename(__FILE__), 'wp_custom_attachment_nonce' );
	$html = '<p class="description">Upload your PDF here.</p>';
	$html .= '<input id="wp_custom_attachment" name="wp_custom_attachment" size="25" type="file" value="" />';

	$filearray = get_post_meta( get_the_ID(), 'wp_custom_attachment', true );
	$this_file = $filearray['url'];
	
	if ( $this_file != '' ) { 
	     $html .= '<div><p>Current file: ' . $this_file . '</p></div>'; 
	}
	echo $html; 
}

Saving Info from Attachment

Now we need to create something that will deal with saving the information from the chosen attachment by hooking into save_post. I’ve seen this done a few different ways so if you have any suggestions for additional checks, please let me know if there are fidgets or improvements that can be added.

In this version, we first make sure the array isn’t empty. Then we set up an array for the supported file type (in this case, a PDF). We copy the file to the server but if there are any errors, the process will be stopped and they’ll be displayed to the user.

/**
 * Save custom attachment metabox info.
 */
function save_custom_meta_data( $id ) {
	if ( ! empty( $_FILES['wp_custom_attachment']['name'] ) ) {
		$supported_types = array( 'application/pdf' );
		$arr_file_type = wp_check_filetype( basename( $_FILES['wp_custom_attachment']['name'] ) );
		$uploaded_type = $arr_file_type['type'];

		if ( in_array( $uploaded_type, $supported_types ) ) {
			$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 );
			}
		}
		else {
			wp_die( "The file type that you've uploaded is not a PDF." );
		}
	}
}
add_action( 'save_post', 'save_custom_meta_data' );

Add File Upload Functionality for Form

The following is what adapts the form element on post information to support file types within its connected data.

/**
 * Add functionality for file upload.
 */
function update_edit_form() {
	echo ' enctype="multipart/form-data"';
}
add_action( 'post_edit_form_tag', 'update_edit_form' );

How To Retrieve Data from Uploaded File

In this case, to get the URL from your file upload, make sure that you’re within the Loop on the appropriate page (perhaps the single-CPT.php file). From this point, add the desired formatting within your page markup & give yourself a high five. Way to go!

<?php
     $custom_attach = get_post_meta( $post->ID, 'wp_custom_attachment', true );
     echo $custom_attach['url'];
?>

Bonus: How to Get Your Custom Attachment’s Title Attribute

To get the title of your uploaded media, we have to go via a different route of grabbing that from the media library rather than your existing $custom_attach variable. Below, I passed an array to get_posts to get the title of my attachment and put it within an anchor tag. Again, this would be placed within the Loop on the appropriate page where you’re placing the data.

$args = array(
	'post_type'   => 'attachment',
	'post_parent' => $post->ID,
);

$attachments = get_posts( $args );
if ( $attachments ) {
	foreach ( $attachments as $attachment ) {
		$title = apply_filters( 'the_title', $attachment->post_title );
		echo '<a href="' . esc_url( $custom_attach['url'] ) . '">' . $title . '</a>';
}
Additional Reading:

10 thoughts on “Adding Custom Meta Boxes to Upload Media

  1. Thank you so much! I’ve been looking for a way to attach mp3s to CPTs and this worked perfectly. 🙂

  2. If you want to prevent from creating a lot of unnecessary files when uploading multiple times for the same post. Implement a some SHA1 solution, like this below:

    function dts_save_post_downloads ( $post_id ) {
    if ( ! empty( $_FILES[‘dts_downloads_attachment’][‘name’] ) ) {
    $sha1 = sha1_file ( $_FILES[‘dts_downloads_attachment’][‘tmp_name’] );

    // Check if is uploading the same file again to prevent duplicated files
    $current_meta_data = get_post_meta ( $post_id, ‘dts_downloads_attachment’ );
    if ( ! empty ( $current_meta_data ) ) {
    if ($sha1 === $current_meta_data[0][‘sha1’]) {
    return;
    }

    unlink ( $current_meta_data[0][‘file’] );
    }

    $upload = wp_upload_bits($_FILES[‘dts_downloads_attachment’][‘name’], null, file_get_contents($_FILES[‘dts_downloads_attachment’][‘tmp_name’]));
    if ( isset( $upload[‘error’] ) && $upload[‘error’] != 0 ) {
    wp_die( __( ‘There was an error uploading your file. The error is: ‘, ‘doists’ ) . $upload[‘error’] );
    } else {
    update_post_meta( $post_id, ‘dts_downloads_attachment’, array_merge($upload, [ ‘sha1’ => $sha1 ] ) );
    }
    }
    }

  3. the box itself throws an error

    Warning: Illegal string offset ‘url’ in (…)/functions.php on line 133

    Notice: Uninitialized string offset: 0 in (…)/functions.php on line 133

      1. Thank you for the tutorial!

        I have the same issue when debug mode is activated. The warning is for the following code:

        $this_file = $filearray[‘url’];

    1. Hey, If you want fix this issue just replace the your code as follows..

      /**
      * Custom attachment metabox markup.
      */
      function wp_custom_attachment() {
      $html = ”;
      wp_nonce_field( plugin_basename(__FILE__), ‘wp_custom_attachment_nonce’ );
      $html = ‘Upload your PDF here.’;
      $html .= ”;

      $filearray = get_post_meta( get_the_ID(), ‘wp_custom_attachment’, true );

      if($filearray){
      $this_file = $filearray[‘url’];

      if ( $this_file != ” ) {
      $html .= ‘Current file: ‘ . $this_file . ”;
      }
      }
      echo $html;
      }

  4. Hello, how to add functionality of remove uploaded PDF file and also prevent from creating a lot of unnecessary files when uploading multiple times for the same post???…. IF you give provide full code it will helpful for me…… Thanks in advance.

Leave a Reply

Your email address will not be published. Required fields are marked *