How to add file upload to meta box in WordPress

For a project I’m working on, I had to create a file upload in a post meta. I wanted to utilize the WordPress media uploader so I cut down the manual labor, however all code snippets I found either did not work or broke the “Add media” button for the editor.

In order to accomplish the task at hand I’ll follow the following plan:
1. Register the meta box
2. En-queue the needed JavaScript
3. Write the JavaScript
4. Handle the meta box saving

 

1. Register the meta box

add_action( 'add_meta_boxes', 'wb_220517_register_meta_boxes' );
function wb_220517_register_meta_boxes($post) {
    //Register Metabox
    add_meta_box( 'additional-file' , __( 'Additional File', 'textdomain' ), 'wb_220517_file_callback', ['page', 'post'], 'side', 'low' );
}

function wb_220517_file_callback($post) {
    //Meta box content
    wp_nonce_field( 'wb_220517_nonce', 'meta_box_nonce' );
    $fileLink = get_post_meta($post->ID, "wb_additional_file", true);
?>
<label for="wb_additional_file">Additional File</label>
<input id="wb_additional_file" name="wb_additional_file" type="text" value="<?= $fileLink ?>" />
<input id="upload_button" type="button" value="Upload File" />
<?php
}

 

2. En-queue the needed JavaScript

add_action('admin_enqueue_scripts', 'wb_220517_add_admin_scripts');
function wb_220517_add_admin_scripts($hook) {
    if($hook !== 'post-new.php' && $hook !== 'post.php')
    {
        return;
    }
    wp_enqueue_script('media-upload');
    wp_enqueue_script('thickbox');
    wp_enqueue_script('WB_JS_Admin', get_template_directory_uri() . '/js/admin.js', array('jquery','media-upload','thickbox'), 1.1, true);
    wp_enqueue_style('thickbox');
}

 

3. Write the JavaScript

jQuery(document).ready(function ($) {
    var frame;
    $('#upload_button').click(function() {
        
        event.preventDefault();

        // If the media frame already exists, reopen it.
        if ( frame ) {
          frame.open();
          return;
        }

        // Create a new media frame
        frame = wp.media({
          title: 'Select or Upload Image',
          button: {
            text: 'Use this Image'
          },
          multiple: false  // Set to true to allow multiple files to be selected
        });


        // When an image is selected in the media frame...
        frame.on( 'select', function() {

          // Get media attachment details from the frame state
          var attachment = frame.state().get('selection').first().toJSON();

          // Send the attachment id to our input field
          $('#wb_additional_file').val( attachment.url );
        });
    });

});

 

4. Handle the meta box saving

add_action( 'save_post', 'wb_220517_save_meta_box' );
function wb_220517_save_meta_box( $post_id ){
    // Bail if we're doing an auto save
    if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;

    // if our nonce isn't there, or we can't verify it, bail
    if( !isset( $_POST['meta_box_nonce'] ) || !wp_verify_nonce( $_POST['meta_box_nonce'], 'wb_220517_nonce' ) ) return;

    // if our current user can't edit this post, bail
    if( !current_user_can( 'edit_post' ) ) return;

    $fields = [
        'wb_additional_file'
    ];
    foreach($fields as $field)
    {
        if( isset( $_POST[$field] ) )
        {
            update_post_meta( $post_id, $field, $_POST[$field] );
        }
    }
}

 

You can download the code for this how-to in
About Pavel Petrov 2 Articles |  21 How-tos
Pavel is a senior developer for the last 7 years, with extended interest in Linux administration, WordPress and Symfony.