Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I know that plupload is going to be the new upload engine for WordPress 3.3 but I was wondering if there is any documentation yet on how it integrates with WordPress.

My specifically how to collect a response from the plUpload jQuery object once it has uploaded the media that you want and how one would use the same functionality in a meta box to create a gallery?

Has anyone played around with it, yet?

share|improve this question
    
Thanks for the bounty, though there is a good chance an answer won't come until WordPress 3.3 has an official release –  Manny Fleurmond Nov 22 '11 at 22:23
3  
There's also a good chance I'll take a look at it this weekend :-) I've been using 3.3 for months now, and need to write up this exact thing before the first RC drops ... –  EAMann Nov 22 '11 at 23:39
    
Here is a link to the jQuery plugin the new uploader uses, plupload (plupload.com). I have the gist of how they implement it but can't tell how the new implementation receives responses when a file is successfully uploaded. –  Manny Fleurmond Nov 22 '11 at 23:51
    
+1 I'm also very interested in a solution, but haven't time to look around in the code myself. –  rofflox Nov 23 '11 at 10:49

4 Answers 4

up vote 12 down vote accepted
+400

My specifically how to collect a response from the plUpload jQuery object once it has uploaded the media that you want and how one would use the same functionality in a meta box to create a gallery?

There's a specific file that handles this functionality: /wp-includes/js/plupload/handlers.dev.js. This file contains all of the hooks and triggers that tie Plupload (the third-party drag/drop multi-file system) to the uploader.

There are two events you might want to look at: "FileUploaded" and "Upload Complete"

FileUploaded

Remember, the new uploader is capable of uploading multiple files at once. So if there's something you want to do after each file in the queue is uploaded, you'll use jQuery to bind to this event.

WordPress, for example, binds the following:

uploader.bind('FileUploaded', function(up, file, response) {
    uploadSuccess(file, response.response);
});'

The uploadSuccess function here handles image thumbnails, fetches attachment meta from the server, and binds edit/delete buttons to the right object.

UploadComplete

The UploadComplete event will fire after everything in the queue is finished uploading. If you want to fire a general cleanup operation after the entire download is finished, this is what you'll want to bind to.

WordPress, for example, binds the following:

uploader.bind('UploadComplete', function(up, files) {
    uploadComplete();
});

The uploadComplete function here just enables the "Insert gallery" button on the page.

Unfortunately ...

... there doesn't seem to be a way for us to bind to these events. The uploader object exists within a closure in the handlers.js file, and Plupload itself doesn't have a way to reference existing instances. You can't use a simple jQuery selector to sniff it out and add a custom event ... so we're out of luck there.

On the one hand, you can use these custom events at-will in your own systems. Just spin up your own version of the handlers.js file with your own events and you can do whatever you want. But for the existing uploader, you're stuck with the existing API.

Keep in mind, that the new Pluploader calls the same methods at the same times as the old Flash uploader did. So my best guess is that any existing hacks or integrations you have should continue to work.

Testing that assumption

I have a plugin that uses the existing uploader to upload file attachments and display the URL in a custom meta field. It worked like magic with the old uploader, so I fired it up in WP 3.3 to see if it worked with the new uploader as well.

And it does!

So if you're already integrating with the media uploader, your system should still work with the new system without any changes.

share|improve this answer

I extended One Trick Pony's answer a little bit. I built an uploader with the following features:

  • It can be placed multiple times in the same page.
  • It shows upload progress.
  • It shows thumbnails of the images user has uploaded (and existing data).
  • It allows user to change the order of images by dragging around the thumbnails.

Check it out at http://www.krishnakantsharma.com/2012/01/image-uploads-on-wordpress-admin-screens-using-jquery-and-new-plupload/

share|improve this answer

(this is just a practical example based on EAMann's answer)

// include js
add_action('admin_enqueue_scripts', function($page){

  // check if this your page here with the upload form!
  if(($page !== 'post.php') || (get_post_type() !== 'post'))
    return;

  wp_enqueue_script('plupload-all');
});



// this adds a simple metabox with the upload form on the edit-post page
add_action('add_meta_boxes', function(){
  add_meta_box('gallery_photos', __('Photos'), 'upload_meta_box', 'post', 'normal', 'high');

});                                               



// so here's the actual uploader
// most of the code comes from media.php and handlers.js
function upload_meta_box(){ ?>
   <div id="plupload-upload-ui" class="hide-if-no-js">
     <div id="drag-drop-area">
       <div class="drag-drop-inside">
        <p class="drag-drop-info"><?php _e('Drop files here'); ?></p>
        <p><?php _ex('or', 'Uploader: Drop files here - or - Select Files'); ?></p>
        <p class="drag-drop-buttons"><input id="plupload-browse-button" type="button" value="<?php esc_attr_e('Select Files'); ?>" class="button" /></p>
      </div>
     </div>
  </div>

  <?php

  $plupload_init = array(
    'runtimes'            => 'html5,silverlight,flash,html4',
    'browse_button'       => 'plupload-browse-button',
    'container'           => 'plupload-upload-ui',
    'drop_element'        => 'drag-drop-area',
    '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,

    // additional post data to send to our ajax hook
    'multipart_params'    => array(
      '_ajax_nonce' => wp_create_nonce('photo-upload'),
      'action'      => 'photo_gallery_upload',            // the ajax action name
    ),
  );

  // we should probably not apply this filter, plugins may expect wp's media uploader...
  $plupload_init = apply_filters('plupload_init', $plupload_init); ?>

  <script type="text/javascript">

    jQuery(document).ready(function($){

      // create the uploader and pass the config from above
      var uploader = new plupload.Uploader(<?php echo json_encode($plupload_init); ?>);

      // checks if browser supports drag and drop upload, makes some css adjustments if necessary
      uploader.bind('Init', function(up){
        var uploaddiv = $('#plupload-upload-ui');

        if(up.features.dragdrop){
          uploaddiv.addClass('drag-drop');
            $('#drag-drop-area')
              .bind('dragover.wp-uploader', function(){ uploaddiv.addClass('drag-over'); })
              .bind('dragleave.wp-uploader, drop.wp-uploader', function(){ uploaddiv.removeClass('drag-over'); });

        }else{
          uploaddiv.removeClass('drag-drop');
          $('#drag-drop-area').unbind('.wp-uploader');
        }
      });

      uploader.init();

      // a file was added in the queue
      uploader.bind('FilesAdded', function(up, files){
        var hundredmb = 100 * 1024 * 1024, max = parseInt(up.settings.max_file_size, 10);

        plupload.each(files, function(file){
          if (max > hundredmb && file.size > hundredmb && up.runtime != 'html5'){
            // file size error?

          }else{

            // a file was added, you may want to update your DOM here...
            console.log(file);
          }
        });

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

      // a file was uploaded 
      uploader.bind('FileUploaded', function(up, file, response) {

        // this is your ajax response, update the DOM with it or something...
        console.log(response);

      });

    });   

  </script>
  <?php
}


// handle uploaded file here
add_action('wp_ajax_photo_gallery_upload', function(){

  check_ajax_referer('photo-upload');

  // you can use WP's wp_handle_upload() function:
  $status = wp_handle_upload($_FILES['async-upload'], array('test_form'=>true, 'action' => 'photo_gallery_upload'));

  // and output the results or something...
  echo 'Uploaded to: '.$status['url'];

  exit;
});

There are more plupload events you can use, check out its documentation....

share|improve this answer
    
I've tried this code as is and so far it doesn't do anything. The image seems to upload but I don't know where and I get no response from the console –  Manny Fleurmond Dec 9 '11 at 6:41
1  
Okay, found the problem: for some reason the $_FILES['async-upload'] you sent to wp_handle_upload doesn't seem to pass a check in said function. If you pass array('test_form'=>false) as a second argument into wp_handle_upload, it uploads the file without a problem. There is also an extra parentheses in the call to add_meta_box. I added edits to your answer which should make it work. –  Manny Fleurmond Dec 9 '11 at 7:21
    
As an implementation note - can set action to upload-attachment which will trigger native wp_ajax_upload_attachment() handler and with some tweaking don't need custom upload handler altogether, just the form and script parts. –  Rarst Feb 12 at 15:33

Here is an expansion to @One Trick Pony's answer. This, in addition to uploading the file to the proper, will also save said file as an attachment:

<?php
// include js
add_action('admin_enqueue_scripts', function($page){

  // check if this your page here with the upload form!
  if(($page !== 'post.php') || (get_post_type() !== 'post'))
    return;

  wp_enqueue_script('plupload-all');
});



// this adds a simple metabox with the upload form on the edit-post page
add_action('add_meta_boxes', function(){
  add_meta_box('gallery_photos', __('Photos'), 'upload_meta_box', 'post', 'normal', 'high');

});                                               



// so here's the actual uploader
// most of the code comes from media.php and handlers.js
function upload_meta_box(){ ?>
   <div id="plupload-upload-ui" class="hide-if-no-js">
     <div id="drag-drop-area">
       <div class="drag-drop-inside">
        <p class="drag-drop-info"><?php _e('Drop files here'); ?></p>
        <p><?php _ex('or', 'Uploader: Drop files here - or - Select Files'); ?></p>
        <p class="drag-drop-buttons"><input id="plupload-browse-button" type="button" value="<?php esc_attr_e('Select Files'); ?>" class="button" /></p>
      </div>
     </div>
  </div>

  <?php

  $plupload_init = array(
    'runtimes'            => 'html5,silverlight,flash,html4',
    'browse_button'       => 'plupload-browse-button',
    'container'           => 'plupload-upload-ui',
    'drop_element'        => 'drag-drop-area',
    '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,

    // additional post data to send to our ajax hook
    'multipart_params'    => array(
      '_ajax_nonce' => wp_create_nonce('photo-upload'),
      'action'      => 'photo_gallery_upload',            // the ajax action name
    ),
  );

  // we should probably not apply this filter, plugins may expect wp's media uploader...
  $plupload_init = apply_filters('plupload_init', $plupload_init); ?>

  <script type="text/javascript">

    jQuery(document).ready(function($){

      // create the uploader and pass the config from above
      var uploader = new plupload.Uploader(<?php echo json_encode($plupload_init); ?>);

      // checks if browser supports drag and drop upload, makes some css adjustments if necessary
      uploader.bind('Init', function(up){
        var uploaddiv = $('#plupload-upload-ui');

        if(up.features.dragdrop){
          uploaddiv.addClass('drag-drop');
            $('#drag-drop-area')
              .bind('dragover.wp-uploader', function(){ uploaddiv.addClass('drag-over'); })
              .bind('dragleave.wp-uploader, drop.wp-uploader', function(){ uploaddiv.removeClass('drag-over'); });

        }else{
          uploaddiv.removeClass('drag-drop');
          $('#drag-drop-area').unbind('.wp-uploader');
        }
      });

      uploader.init();

      // a file was added in the queue
      uploader.bind('FilesAdded', function(up, files){
        var hundredmb = 100 * 1024 * 1024, max = parseInt(up.settings.max_file_size, 10);

        plupload.each(files, function(file){
          if (max > hundredmb && file.size > hundredmb && up.runtime != 'html5'){
            // file size error?

          }else{

            // a file was added, you may want to update your DOM here...
            console.log(file);
          }
        });

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

      // a file was uploaded 
      uploader.bind('FileUploaded', function(up, file, response) {

        // this is your ajax response, update the DOM with it or something...
        console.log(response);

      });

    });   

  </script>
  <?php
}


// handle uploaded file here
add_action('wp_ajax_photo_gallery_upload', function(){

  check_ajax_referer('photo-upload');

  // you can use WP's wp_handle_upload() function:
  $file = $_FILES['async-upload'];
  $status = wp_handle_upload($file, array('test_form'=>true, 'action' => 'photo_gallery_upload'));

  // and output the results or something...
  echo 'Uploaded to: '.$status['url'];

  //Adds file as attachment to WordPress
  echo "\n Attachment ID: " .wp_insert_attachment( array(
     'post_mime_type' => $status['type'],
     'post_title' => preg_replace('/\.[^.]+$/', '', basename($file['name'])),
     'post_content' => '',
     'post_status' => 'inherit'
  ), $status['file']);

  exit;
});
?>
share|improve this answer
1  
Think there's a small mistake here--the last param of the wp_insert_attachment call should be $status['file'] rather than $status['url']. Pretty sure it needs to be the local path. –  MathSmath Dec 14 '11 at 19:23
    
@MathSmath thanks for the catch –  Manny Fleurmond Dec 15 '11 at 1:53

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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