When building applications with the WordPress REST API, we often need to upload images and files into the WordPress media library. The official documentation does not explain this workflow very clearly. We ran into the same problem while building a React-based WordPress theme, and it took several hours of trial and error before we found a working approach. In this article I am writing it down for anyone who runs into the same issue.
In that project, the submission form needed to send the post title, content, several custom fields, and an image that would become the post’s featured image. The React implementation involved quite a bit of code, so to keep the example easier to follow, the article below demonstrates the upload flow with jQuery Ajax instead.
The WP REST API endpoint used for image uploads
The WordPress REST API includes a /media endpoint. As long as we send data in the correct format to that endpoint, we can upload files successfully. The frustrating part is that the API docs do not clearly show what that payload should look like, and that was exactly where we got stuck for a long time.
Set the HTML5 form enctype attribute
First, the form itself must be marked as a file-upload form. That means adding enctype="multipart/form-data" to the form tag.
<form id="imageUpload" enctype="multipart/form-data">
<input type="file" id="file" />
<input type="submit" value="save file" />
</form>
The default value of enctype is text/plain. If you need to upload an image, this attribute must be changed to multipart/form-data, otherwise the upload cannot even get off the ground.
Submit the form data with jQuery Ajax
Next, we use jQuery’s Ajax method to send the file data to the WordPress REST API. One thing to pay attention to here is authentication. We need to send the X-WP-Nonce value so WordPress will accept the request. The authentication method can be cookie-based authentication or application-password authentication depending on your setup.
Create a FormData() object to simulate a form submission
FormData is a JavaScript object that lets us build a virtual form payload in code and send it to the server as if the browser had submitted a normal form. In the following example, we create a FormData instance named imageData and append the selected file to it.
// Get the file object.
var fileObject = $('input#file')[0].files[0] // Or use the native method: document.getElementById("photo").files[0];
var filename = fileObject.name;
// Create a virtual form and add the file to it.
var imageData = new FormData();
imageData.append( "file", fileObject);
Set the right HTTP headers so the API accepts the upload
Even after creating the FormData object, a direct upload can still fail, because the API may treat the request as plain text unless we tell it explicitly that a file is being uploaded. The important part is setting a proper Content-Disposition header.
$.ajax({
url: ajaxInfo.json_url + 'media?X-WP-Nonce' + ajaxInfo.nonce,
type: 'POST',
data: imageData, // The FormData object created above
cache: false,
contentType: false,
processData: false,
headers: { 'Content-Disposition': 'attachment;filename=test.jpg' },
success: succes(res) // After upload, get the attachment ID and submit it as featured_media with the post
});
In the example above, the upload name is hard-coded as test.jpg. In a real project, you should use the original file name chosen by the user.
After the upload succeeds, the REST API returns the created attachment object. We can read the attachment ID from that response and then submit it to the post endpoint as the featured_media parameter so the uploaded file becomes the post’s featured image. If you do not want to use it as the featured image, you can also save the image ID or image URL into a custom field instead.
And this technique is not limited to WordPress themes. The same REST API upload flow can be used in mobile apps, desktop applications, or any other front-end client that needs to send files to WordPress.
