Add inline uploader to plugin option page

The question:

I would like to implement an inline file uploader to my plugin’s option page as introduced in new media grid view of the WP media library:

enter image description here

I imagine having this drag & drop uploader in the page and getting an JSON object of either errors or attachment data back in JS when used.

As far as I know there is a wp.media.view.UploaderInline class present in
wp-includes/js/media-views.js but I have no idea of how to implement that in combination with the given markup.

The only resources I found are on how to use the media modal (introduced in v3.5) to upload and add files to a page. But having the uploader inline would be much better for my case since I don’t want the media library to show up in the process.

Has anyone experience implementing this to get me on track?

Thx

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Okay, here is what I came up with: It’s all about using the plupload library that comes shipped with WP.

1. Add a <div> to your plugin’s option page that later becomes the drag’n’drop area

    <div class="your-plugin-uploader multiple">
        <input id="your-plugin-uploader-button" type="button" value="<?php esc_attr_e( 'Select Files' ); ?>" class="your-plugin-uploader-button button">
        <span class="ajaxnonce" id="<?php echo wp_create_nonce( __FILE__ ); ?>"></span>
    </div>

2. Register your plugin JS and make sure you define plupload-all as a dependency for your script

    function se179618_admin_js() {
        wp_register_script( 'your-plugin', WP_PLUGIN_URL . '/your-plugin/js/your-plugin.js', array( 'jquery', 'plupload-all' ) );
    }
    add_action( 'admin_enqueue_scripts', 'se179618_admin_js' );

3. Write some plupload settings to the page’s <head>

    function se179618_admin_head() {
        $uploader_options = array(
            'runtimes'          => 'html5,silverlight,flash,html4',
            'browse_button'     => 'my-plugin-uploader-button', 
            'container'         => 'my-plugin-uploader', 
            'drop_element'      => 'my-plugin-uploader', 
            'file_data_name'    => 'async-upload', 
            'multiple_queues'   => true,
            'max_file_size'     => wp_max_upload_size() . 'b',
            'url'               => admin_url( 'admin-ajax.php' ),
            'flash_swf_url'     => includes_url( 'js/plupload/plupload.flash.swf' ),
            'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
            'filters'           => array( 
               array( 
                  'title' => __( 'Allowed Files' ), 
                  'extensions' => '*'
               ) 
            ),
            'multipart'         => true,
            'urlstream_upload'  => true,
            'multi_selection'   => true, 
            'multipart_params' => array(
                '_ajax_nonce' => '',            
                'action'      => 'my-plugin-upload-action'          
            )
        );
    ?>
    <script type="text/javascript">
        var global_uploader_options=<?php echo json_encode( $uploader_options ); ?>;
    </script>
    <?php
    }
    add_action( 'admin_head', 'se179618_admin_head' );

4. Add the action called by the AJAX uploader

    function se179618_ajax_action() {
        // check ajax nonce
        check_ajax_referer( __FILE__ );

        if( current_user_can( 'upload_files' ) ) {
            $response = array();

            // handle file upload
            $id = media_handle_upload( 
               'async-upload',
               0, 
               array( 
                  'test_form' => true, 
                  'action' => 'my-plugin-upload-action' 
               )
            );

            // send the file' url as response
            if( is_wp_error( $id ) ) {
                $response['status'] = 'error';
                $response['error'] = $id->get_error_messages();
            } else {
                $response['status'] = 'success';

                $src = wp_get_attachment_image_src( $id, 'thumbnail' );
                $response['attachment'] = array();
                $response['attachment']['id'] = $id;
                $response['attachment']['src'] = $src[0];
            }

        }

        echo json_encode( $response );
        exit;
    }

    add_action( 'wp_ajax_my-plugin-upload-action', 'se179618_ajax_action' ); 

5. Initiate the uploader in your plugin’s JS

    jQuery( document ).ready( function() {

        if( jQuery( '.your-plugin-uploader' ).length > 0 ) {
            var options = false;
            var container = jQuery( '.your-plugin-uploader' );
            options = JSON.parse( JSON.stringify( global_uploader_options ) );
            options['multipart_params']['_ajax_nonce'] = container.find( '.ajaxnonce' ).attr( 'id' );

            if( container.hasClass( 'multiple' ) ) {
                  options['multi_selection'] = true;
             }

            var uploader = new plupload.Uploader( options );
            uploader.init();

            // EVENTS
            // init
            uploader.bind( 'Init', function( up ) {
                console.log( 'Init', up );
            } );

            // file added
            uploader.bind( 'FilesAdded', function( up, files ) {
                jQuery.each( files, function( i, file ) {
                    console.log( 'File Added', i, file );
                } );

               up.refresh();
               up.start();
            } );

            // upload progress
            uploader.bind( 'UploadProgress', function( up, file ) {
                console.log( 'Progress', up, file )
            } );

            // file uploaded
            uploader.bind( 'FileUploaded', function( up, file, response ) {
                response = jQuery.parseJSON( response.response );

                if( response['status'] == 'success' ) {
                    console.log( 'Success', up, file, response );
                } else {
                    console.log( 'Error', up, file, response );
                }

            } );
        }

    } );

Method 2

Here is an example for wp version 4.7 and above. The task is simple. This code is directly cloned script taken from the default WordPress Add new page (media-new.php).

function my_admin_enqueue_scripts() {
    wp_enqueue_script('plupload-handlers');
}
add_action('admin_enqueue_scripts', 'my_admin_enqueue_scripts');

Add this html on your options page. Make shure you keep this outside your own <form> element. To keep the variables out of global scope, I recommend to wrap the html output inside a function. This example is lending the top admin notices container to show the area on every admin page… so you can test it without option page.

function my_upload_new_media_html(){

    /* everything is copied from media-new.php */
    /* translated, and old browser option is there as well */

    $title = __('Upload New Media');

    $post_id = 0;
    if(isset($_REQUEST['post_id'])){
        $post_id = absint($_REQUEST['post_id']);
        if(!get_post($post_id) || !current_user_can('edit_post', $post_id)) $post_id = 0;
    }

    if($_POST){
        if(isset($_POST['html-upload']) && !empty($_FILES)){
            check_admin_referer('media-form');
            // Upload File button was clicked
            $upload_id = media_handle_upload('async-upload', $post_id);
            if(is_wp_error($upload_id)){
                wp_die($upload_id);
            }
        }
        wp_redirect(admin_url('upload.php'));
        exit;
    }

    $form_class = 'media-upload-form type-form validate';
    if(get_user_setting('uploader') || isset( $_GET['browser-uploader']))
        $form_class .= ' html-uploader';

?>

<div class="wrap">
    <h1><?php echo esc_html( $title ); ?></h1>

    <form enctype="multipart/form-data" method="post" action="<?php echo admin_url('media-new.php'); ?>" class="<?php echo esc_attr( $form_class ); ?>" id="file-form">

    <?php media_upload_form(); ?>

    <script type="text/javascript">
    var post_id = <?php echo $post_id; ?>, shortform = 3;
    </script>
    <input type="hidden" name="post_id" id="post_id" value="<?php echo $post_id; ?>" />
    <?php wp_nonce_field('media-form'); ?>
    <div id="media-items" class="hide-if-no-js"></div>
    </form>
</div>

<?php
}
add_action('all_admin_notices', 'my_upload_new_media_html');

And Boom, its there.

Method 3

The first thing you’ll need to do is call wp_enqueue_media. A safe place for this might be in the admin_init action with some conditional around it.

add_action( 'admin_init', function() {
    $screen = get_current_screen();

    if ( ! $screen || 'my-admin-page-slug' !== $screen->id ) {
        return;
    }

    wp_enqueue_media();
} );

Then in your admin page code you’d add some inline javascript (or enqueue it if you want to do it cleanly)

function my_admin_page_callback() {

    ...
?>
    <a href="#" rel="nofollow noreferrer noopener" class="primary button upload">Upload</a>
    <script type="text/javascript">
        $('.upload.button').click(function(e) {
            e.preventDefault();

            var custom_uploader = wp.media({
                title: 'Custom Title',
                button: {
                    text: 'Custom Button Text'
                },
                multiple: false  // Set this to true to allow multiple files to be selected
            })
            .on('select', function() {
                var attachment = custom_uploader.state().get('selection').first().toJSON();
                // Do something with attachment.url;
                // Do something with attachment.id;
            })
            .open();
        });
    </script>
<?php
    ...
}

Getting the drag and drop box might prove a little difficult but if you do a little digging of your own you might be able to find it.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment