WordPress file upload with AJAX

In this tutorial we will see how we can achieve wordpress file upload with ajax.

The use case is that we want to have a form in frontend that will be accessed by visitors. These visitors will not be authenticated. The form will send all the form data along with the files that are uploaded, to server. The key fact to be noted is that if we use standard wordpress method for ajax, we will need to pass action as a field in post request. This will create complications in properly sending post data along with $_FILE as well as $_POST[‘action’] variables using via AJAX.

To overcome this, we will send our ajax post request to a custom handler php file and not to admin-ajax.php

Before we begin, please note that this code is for demo purpose only with bare minimum functionality. To use it in production, please ensure adding required security and validation logic

Lets begin by creating a HTML form

<form id="myform" method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<button type="button" id="submit-button">Submit</button>
</form>

This will render a simple form with a file upload input field – nothing special about it.

Next, let us add javascript to make this form functional. The script below must be enqueued/loaded after jQuery.

jQuery(document).ready(function(){
  jQuery('#submit-button').click(function(){
    // create a FormData object and append all files to it
    var formData = new FormData();
    var inputName, file;
    var urlToPhpFile = 'server.php';
    jQuery.each(jQuery('input[type="file"]'), function (index, value) 
    { 
      inputName = jQuery(value).attr('name');
      file = jQuery(value).prop('files')[0];
      if (file) {
	formData.append(inputName, file);
      }		
     jQuery.ajax(urlToPhpFile, {
			data: formData,
			type: 'post',
			processData: false,
			contentType: false
		}).fail(function (errObj, errText, errThrown) {
				alert('Error!');
			}).done(function(data){
				if (data.status == 0){
						alert('Success!');
				}else{
					alert('Failed!');
				}
			});
		});
	});
});

At this stage we have a HTML form that will send the uploaded file to a php file at the root of wordpress installation using AJAX, when submit button is clicked.

Next, lets create a file server.php at root of our wordpress installation. Since this file will be executed outside of normal wordpress load sequence, we need an extra step to make wordpress functions available here.

<?php 
//adjust path of "wp-load.php" and "file.php" based on location of this code. Here we are assuming
//this code is written in a file at root of wordpress installation.
require( './wp-load.php' );
require_once(ABSPATH . 'wp-admin/includes/file.php');

//@todo: add security and validations
$file = $_FILES['myfile'];
$uploaded_file = wp_handle_upload($file, array('test_form' => false));

if ( $uploaded_file && ! isset( $uploaded_file['error'] ) ) {
    wp_send_json(array(
        'status' => '0', 
        'message' => 'Success!',
        'uploadedFile' => $uploaded_file['url']
    ));
} else {
    wp_send_json(array(
        'status' => '-1', 
        'message' => 'Failed!'
    ));
}

The above php file will receive incoming post data and upload the file in wordpress upload directory and will give the url of uploaded file. If other file details are needed, we can use different values of $uploaded_file array