Skip to content

Instantly share code, notes, and snippets.

@soderlind
Created February 1, 2016 19:33
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soderlind/92593c6fb6d1c633fdb9 to your computer and use it in GitHub Desktop.
Save soderlind/92593c6fb6d1c633fdb9 to your computer and use it in GitHub Desktop.
DropzoneJS & WordPress REST API with Custom Endpoint
About:
The plugin provides drag’n’drop file uploads and uses the wp rest api to upload the file.
This version adds a custom endpoint, has code for handling the upload and uploads the file to uploads/yyyy/mm without
adding the file to the media library.
Installation:
Save dropzonejs-wp-rest-api-custom-endpoint.php in wp-content/plugins/dropzonejs-wp-rest-api-custom-endpoint/
Save dropzonejs-wp-rest-api-custom-endpoint.js in wp-content/plugins/dropzonejs-wp-rest-api-custom-endpoint/js/
Use:
After activating the plugin, add the [dropzonerest] shortcode to a post
Credits:
http://www.dropzonejs.com/
https://github.com/WP-API/WP-API, I learned a lot reading the wp-api source
Copyright:
The plugin is copyright Per Soderlind - per@soderlind.no
License: GPL, please feel free to modify the plugin as long as you make it GPL
// dropzoneWordpressRestApiForm is the configuration for the element that has an id attribute
// with the value dropzone-wordpress-rest-api-form (or dropzoneWordpressRestApiForm)
Dropzone.options.dropzoneWordpressRestApiForm = {
//acceptedFiles: "image/*", // all image mime types
acceptedFiles: ".jpg", // only .jpg files
maxFiles: 1,
uploadMultiple: false,
maxFilesize: 5, // 5 MB
init: function() {
console.group('dropzonejs-wp-rest-api:');
var myDropzone = this; // closure
myDropzone.on("sending", function(file, xhr, data) {
console.log("file: %O", file);
//add nonce, from: http://v2.wp-api.org/guide/authentication/
xhr.setRequestHeader('X-WP-Nonce', WP_API_Settings.nonce);
});
// myDropzone.on("processing", function(file) {
// this.options.url = WP_API_Settings.root + 'wp/v2/media/';
// });
myDropzone.on("error", function(file, error, xhr) {
console.error("ERROR: %o", error);
console.groupEnd();
});
myDropzone.on("success", function(file, response) {
console.log("success: %o", response);
// etc
});
}
};
<?php
/*
Plugin Name: DropzoneJS & WordPress REST API with Custom Endpoint
Version: 0.0.1
Description: Demos how to upload files using DropzoneJS and the WordPress REST API (wp-api v2)
Author: Per Soderlind
Author URI: https://soderlind.no
Plugin URI: https://gist.github.com/soderlind/
License: GPL
*/
define( 'DROPZONEJS_WP_REST_API_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
define( 'DROPZONEJS_WP_REST_API_PLUGIN_VERSION', '0.0.1' );
define( 'DROPZONEJS_WP_REST_API_NAMESPACE', 'dropzonejs/v' . DROPZONEJS_WP_REST_API_PLUGIN_VERSION );
define( 'DROPZONEJS_WP_REST_API_BASE', 'upload' );
add_action( 'plugins_loaded', 'dropzonejs_wp_rest_api_init' );
function dropzonejs_wp_rest_api_init() {
add_action( 'wp_enqueue_scripts', 'dropzonejs_wp_rest_api_enqueue_scripts' );
add_shortcode( 'dropzonerest', 'dropzonejs_wp_rest_api_shortcode' );
}
function dropzonejs_wp_rest_api_enqueue_scripts() {
wp_enqueue_script(
'dropzonejs',
'https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.2.0/min/dropzone.min.js',
array(),
DROPZONEJS_WP_REST_API_PLUGIN_VERSION
);
// Load custom dropzone javascript
wp_enqueue_script(
'dropzone-wp-rest',
DROPZONEJS_WP_REST_API_PLUGIN_URL . '/js/dropzonejs-wp-rest-api-custom-endpoint.js',
array( 'wp-api', 'dropzonejs' ),
DROPZONEJS_WP_REST_API_PLUGIN_VERSION
);
wp_enqueue_style(
'dropzonecss',
'https://cdnjs.cloudflare.com/ajax/libs/dropzone/4.2.0/min/dropzone.min.css',
array(),
DROPZONEJS_WP_REST_API_PLUGIN_VERSION
);
// from: http://v2.wp-api.org/guide/authentication/
wp_enqueue_script( 'wp-api' );
wp_localize_script(
'wp-api',
'WP_API_Settings',
array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'title' => 'Media Title',
'description' => 'Media Description',
'alt_text' => 'Media Alt Text',
'caption' => 'Media Caption'
)
);
}
// Add Shortcode
function dropzonejs_wp_rest_api_shortcode( $atts ) {
//user can ?
if ( ! is_user_logged_in() || !current_user_can( 'upload_files' ) ) {
return;
}
$url = rest_url() . DROPZONEJS_WP_REST_API_NAMESPACE . '/' . DROPZONEJS_WP_REST_API_BASE;
return <<<ENDFORM
<div id="dropzone-wordpress-rest-api"><form action="$url" class="dropzone needsclick dz-clickable" id="dropzone-wordpress-rest-api-form">
<div class="dz-message needsclick">
Drop files here or click to upload.<br>
<span class="note needsclick">(Files are uploaded to uploads/yyyy/mm)</span>
</div>
<input type='hidden' name='action' value='submit_dropzonejs'>
</form></div>
ENDFORM;
}
/**
* register custom endpoint, see http://v2.wp-api.org/extending/adding/
*/
add_action( 'rest_api_init', function () {
register_rest_route( DROPZONEJS_WP_REST_API_NAMESPACE, '/' . DROPZONEJS_WP_REST_API_BASE , array(
'methods' => 'POST',
'callback' => 'dropzonejs_upload',
'permission_callback' => function () {
return current_user_can( 'upload_files' );
}
) );
} );
/**
* dropzonejs_upload hadles the upload, code from https://github.com/WP-API/WP-API/blob/47491996f08a3f51883dbae6f6fd0c94ade90c9f/lib/endpoints/class-wp-rest-attachments-controller.php#L56
*
* @param WP_REST_Request $request The request object has the multipart file parameters and the given header from the request.
* @return WP_HTTP_Response The response has the name, file type and url of the uploaded file
*/
function dropzonejs_upload( WP_REST_Request $request ) {
// Get the file via $_FILES (raw data ignored)
$files = $request->get_file_params();
$headers = $request->get_headers();
$file = dropzonejs_upload_file( $files, $headers );
if ( is_wp_error( $file ) ) {
return $file;
}
// Wrap the data in a response object
$data = array();
$data['name'] = basename( $file['file'] );
$data['url'] = $file['url'];
$data['type'] = $file['type'];
$response = rest_ensure_response( $data );
$response->set_status( 201 );
return $response;
}
/**
* dropzonejs_upload_file does the actual upload, it's a strip down version of https://github.com/WP-API/WP-API/blob/47491996f08a3f51883dbae6f6fd0c94ade90c9f/lib/endpoints/class-wp-rest-attachments-controller.php#L451
*
* @param array $files Data from $_FILES
* @param array $headers HTTP headers from the request
* @return array|WP_Error Data from {@see wp_handle_upload()}
*/
function dropzonejs_upload_file( $files, $headers ) {
if ( empty( $files ) ) {
return new WP_Error( 'rest_upload_no_data', __( 'No data supplied' ), array( 'status' => 400 ) );
}
// Verify hash, if given
if ( ! empty( $headers['content_md5'] ) ) {
$content_md5 = array_shift( $headers['content_md5'] );
$expected = trim( $content_md5 );
$actual = md5_file( $files['file']['tmp_name'] );
if ( $expected !== $actual ) {
return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected' ), array( 'status' => 412 ) );
}
}
// Pass off to WP to handle the actual upload
$overrides = array(
'test_form' => false,
);
// Bypasses is_uploaded_file() when running unit tests
if ( defined( 'DIR_TESTDATA' ) && DIR_TESTDATA ) {
$overrides['action'] = 'wp_handle_mock_upload';
}
/** Include admin functions to get access to wp_handle_upload() */
require_once ABSPATH . 'wp-admin/includes/admin.php';
$file = wp_handle_upload( $files['file'], $overrides );
if ( isset( $file['error'] ) ) {
return new WP_Error( 'rest_upload_unknown_error', $file['error'], array( 'status' => 500 ) );
}
return $file;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment