5

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

3

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 );
                }

            } );
        }

    } );
1

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="#" 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.

  • This propably not working for most implementions if you not wrap the javascript inside jQuery(document).ready(function(){ ... }); The button is doing nothing... Adding the wrap, this answer is working, but it loads up the media modal, not as the question as embedded inline drop area. But I think this is a good idea to present this alternative here. – Jonas Lundman Oct 27 '18 at 7:11
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.