How To Upload Files in WordPress Frontend using AJAX

As a WordPress developer, I often face issues while creating file upload functionality in frontend as WordPress doesn’t support it natively. WordPress Frontend AJAX Upload mechanism is fairly simple if you know where to hook and what files to call. In this tutorial, I am going to show you how you can add file upload functionality in frontend without using any plugin. Please note that we will be using simple HTML file upload field and NOT the WordPress native media upload functionality.

First, let’s create a simple HTML form with a file upload field and submit button.

Since we will be using AJAX to upload the file, we need to define the ajaxurl variable for the AJAX call before anything else. The variable ajaxurl is defined in WordPress admin by default, but not in frontend. To do this, we need to add a simple piece of code in functions.php file (or, in the plugin file if you are implementing it on a plugin)

/**
 * Add AJAX URL in head
 */
function pn_ajaxurl_head() {
	echo '<script type="text/javascript">var ajaxurl = "' . admin_url('admin-ajax.php') . '";</script>';
}
add_action( 'wp_head', 'pn_ajaxurl_head', 99 );

Now the variable ajaxurl is available to all the JavaScript code that appears after this in DOM.

Single File Upload

First, we need to create a HTML form which will go in frontend template file.

<form id="myform" class="form" method="post" action="" enctype="multipart/form-data">
	<input type="file" name="myfilefield" class="form-control" value="">
	<?php wp_nonce_field( 'myuploadnonce', 'mynonce' );?>
	<button type="submit" class="btn btn-primary">Submit</button>
</form>

Now, we need to prepare the AJAX call and send the data to our handler function in backend.

jQuery(document).ready(function($) {
	var myForm = $('#myform');
	
	$(myForm).submit(function(e) {
		//Prevent normal form submission
		e.preventDefault();
		
		//Get the form data and store in a variable
		var myformData = new FormData(myForm[0]);
		
		//Add our own action to the data
		//action is where we will be hooking our php function
		myformData.append('action', 'pn_wp_frontend_ajax_upload');
		
		//Prepare and send the call
		$.ajax({
			type: "POST",
			data: myformData,
			dataType: "json",
			url: ajaxurl,
			cache: false,
			processData: false,
			contentType: false,
			enctype: 'multipart/form-data',
			success: function(data, textStatus, jqXHR) {
				//Success codes goes here
			},
			error: function(jqXHR, textStatus, errorThrown){
				//if fails     
				console.log(jqXHR);
			}
		});
	});
});

Place this code after jQuery script in the template file. It is safe to hardcode it in template file, but the proper way to add JavaScript code in WordPress is a better option.

Now we need to process the form submission. To do that, add this code in your functions.php file. The code snippet is well commented to help you understand the function.

function pn_upload_files() {
	
	//Do the nonce security check
	if ( !isset($_POST['mynonce']) || !wp_verify_nonce( $_POST['mynonce'], 'myuploadnonce' ) ) {
		//Send the security check failed message
		_e( 'Security Check Failed', 'pixelnet' ); 
	} else {
		//Security check cleared, let's proceed
		//If your form has other fields, process them here.
		
		if ( isset($_FILES) && !empty($_FILES) ) {
			
			//Include the required files from backend
			require_once( ABSPATH . 'wp-admin/includes/image.php' );
			require_once( ABSPATH . 'wp-admin/includes/file.php' );
			require_once( ABSPATH . 'wp-admin/includes/media.php' );
			
			//Check if uploaded file doesn't contain any error
			if ( isset($_FILES['myfilefield']['error']) && $_FILES['myfilefield']['error'] == 0 ) {
				/*
				 * 'myfilefield' is the name of the file upload field.
				 * Replace the second parameter (0) with the post id
				 * you want your file to be attached to
				 */
				$file_id = media_handle_upload( 'myfilefield', 0 );
				
				if ( !is_wp_error( $file_id ) ) {
					/*
					 * File uploaded successfully and you have the attachment id
					 * Do your stuff with the attachment id here
					*/
				}
			}
		}
		
		//Send the sucess message
		_e( 'Success', 'pixelnet');
	}
	wp_die();
}

//Hook our function to the action we set at jQuery code
add_action( 'wp_ajax_pn_wp_frontend_ajax_upload', 'pn_upload_files');
add_action( 'wp_ajax_nopriv_pn_wp_frontend_ajax_upload', 'pn_upload_files');

Now we are done with WordPress frontend AJAX Upload for a single file. What about allowing users to upload multiple files? Well, we can easily do that by modifying the codes above.

Multiple File Upload

To enable multiple file uploads, we first have to edit the HTML code to allow selection of multiple files in the file upload field. Just add the multiple attribute to the field’s html.

<form id="myform" class="form" method="post" action="" enctype="multipart/form-data">
	<input type="file" name="myfilefield[]" class="form-control" value="" multiple>
	<?php wp_nonce_field( 'myuploadnonce', 'mynonce' );?>
	<button type="submit" class="btn btn-primary">Submit</button>
</form>

The JavaScript code will be same as single file upload.

Now we need to modify our function to handle the multiple files upload. The $_FILES global variable will now contain a multidimensional array for file data. We need to loop through the array and upload each file at once. Here is the code for that.

function pn_upload_multiple_files() {
	
	//Do the nonce security check
	if ( !isset($_POST['mynonce']) || !wp_verify_nonce( $_POST['mynonce'], 'myuploadnonce' ) ) {
		//Send the security check failed message
		_e( 'Security Check Failed', 'pixelnet' ); 
	} else {
		//Security check cleared, let's proceed
		//If your form has other fields, process them here.
		
		if ( isset($_FILES) && !empty($_FILES) ) {
			
			//Include the required files from backend
			require_once( ABSPATH . 'wp-admin/includes/image.php' );
			require_once( ABSPATH . 'wp-admin/includes/file.php' );
			require_once( ABSPATH . 'wp-admin/includes/media.php' );
			
			
			$files = $_FILES['myfilefield'];
			
			//Loop through all the uploaded files
			foreach ($files['name'] as $key => $value) {
				if ($files['name'][$key]) {
					$file = array(
						'name' => $files['name'][$key],
						'type' => $files['type'][$key],
						'tmp_name' => $files['tmp_name'][$key],
						'error' => $files['error'][$key],
						'size' => $files['size'][$key]
					);
					$_FILES = array( 'uploaded_file' => $file);
					$file_id = media_handle_upload('uploaded_file', 0);

					if ( !is_wp_error( $file_id ) ) {
						/*
						 * File uploaded successfully and you have the attacment id
						 * Do your stuff with the attachment id here
						*/
					}
				}
			}
		}
		
		//Send the sucess message
		_e( 'Success', 'pixelnet');
	}
	wp_die();
}

//Hook our function to the action we set at jQuery code
add_action( 'wp_ajax_pn_wp_frontend_ajax_upload', 'pn_upload_multiple_files');
add_action( 'wp_ajax_nopriv_pn_wp_frontend_ajax_upload', 'pn_upload_multiple_files');

That’s it. Now we can easily implement WordPress frontend AJAX upload feature in our themes/plugins. However, a few points to note:

  1. If you want to attach the files to a post, replace 0 with the post id.
  2. Only the file types allowed by WordPress can be uploaded. However, you can allow additional file type to the allowed list.
  3. Always sanitize user inputs before saving it database.

Do let me know if this tutorial is still working for you. If you liked this tutorial, please give us a like on Facebook and Follow PixelNet on Twitter.


Warning: Attempt to read property "ID" on null in /home3/pixeltbn/public_html/wp-content/themes/pnet/sidebar.php on line 14