Before jumping right into the code for this, I wanted to mention two things:

  1. Yes, I’ve covered this in some detail a while back,
  2. And this is the second part of a two-part series.

If you’ve not read the first part, do it first. The idea is that the code will work in conjunction with what I’m going to cover in this post to make sure that both the client-side and the server-side are covered.

Ultimately, the reason for breaking it down like this is not just to make sure that things are done correctly, but also to make sure that the user has the most positive experience possible.

With that said, here’s how to go about uploading files in WordPress on the server-side.

Uploading Files in WordPress on the Server-Side

Note that even though there are some security checks that can – and should – be done, I’ve yet to find a way that’s completely foolproof in detecting that the file being uploaded is of the proper type.

That means there’s still a chance that an incorrect file type can be uploaded. Whether or not this is malicious is obviously up to the end user. I share just this to be clear that the code I’m going to show is as good as I can make provide, but that there’s still a level of discretion you should use.

Perhaps it’s worth even looking for a third-party library to validate the binary data once it’s received. But I digress.

1. Verify User Permissions

Remember that whenever we’ve created the front-end, we have WordPress generate a nonce so that we can use this to make sure the user has permission to upload the file.

In addition to checking the nonce, there are several other things I like to check all of which are wrapped up in a method called userCanSave.

First, recall the front-end:

Then take a look how I use it in the code. First, I define the userCanSave function:

And then I simply call this at the beginning of the process. If it fails, then I return.

I recommend showing an error message, but I digress on this point as there are some ways to do this within the post.

2. Upload the File

Assuming the user has permission to check the file, then it’s safe to upload the file. The process for doing this is straightforward but still requires a little bit of work with the WordPress API (namely with the wp_upload_bits function).

Uploading Files in WordPress Revisited: wp_upload_bits

First, the file needs to be grabbed from PHP’s $_FILES global and then uploaded. When doing that, though, it’s important to make sure that you’re uploading a file with the correct file extension (at the very least).

If the file type is not a PDF, then you can throw an error, simply return (though I’m not a fan of this), or give user’s some feedback (which I’m a fan of doing).

The last step, though, is getting the file into the media uploader.

3. Loading It Into the Media Uploader

The last step in all of this is getting the file into the media uploader. To do this, you need several things from WordPress core:

  1. the file.php library,
  2. an attachment array necessary to tell WordPress what’s being added,
  3. a WordPress API function, wp_insert_attachment
  4. redirecting back to the calling page

Sounds like a lot, right? It’s not too bad.

I usually group the inclusion of the WordPress file library and the wp_insert_attachment into a single block.

You’ll notice that I do set the MIME type to pdf and I make sure that the title doesn’t include anything except the file name. After that, I use wp_insert_attachment to load the file into the Media Library.

Uploading Files in WordPress Revisited: wp_insert_attachment

The full code for that is as follows:

After that, I redirect back to the page that started all of this (which is usually the admin page we saw in the previous post. To this, I  grab the _wp_http_referer from PHP’s $_REQUEST array.

And that will redirect the user back to the page from whence they came.

And The File Is Uploaded

At this point, we’ve set out what we want to do:

  1. Give a decent client-side experience,
  2. Uploaded the file to the media library (with opportunities to offer feedback)
  3. And redirected back to the page that started it all.

Granted, there’s a lot of room for feedback in this, and I urge you to adapt this as needed for your code, but the basis of what you need should be provided both in the previous post and in this post.