Creating a button or a link to download a file from WordPress in text is pretty simple: add an image and point it to an URL of the file. In this tutorial you will learn how to programmatically download a file.

To follow this tutorial you should have some basic knowledge about WordPress, WordPress themes and plugins. I will show you snippets of code that you could use inside a plugin or even a specific theme. We will not create a plugin here, but you can start your own code with the PHP comments to start a WordPress plugin.

The scenario

Before we get to the code part we must first understand how a file will be downloaded. We will need to create a button or a link with the URL that will contain some information about the file we want to download. This will be a link to the file with a Query string that will have the ID of our file.

File with an ID is an attachment in WordPress that was uploaded using the Media Uploader in WordPress or uploaded programmatically using the WordPress API.

We will then check if this Query String is set and if it contains an ID. If that statement is true, we will get the file and send headers and the content from the server using the information from the file.

Usage Scenario

This could be used in different situations. Here are some of them:

  • a site with photos where users or visitors can download the photo
  • a portfolio site where you want your visitors to download your portfolio book or something similar
  • a knowledge base with various PDF file or files in other formats
  • a wallpaper site

The Download button

Now that we understand how to build a button to download a file from WordPress we can start to code. We will create a function that will output a link with the URL to the file alongside with the Query Strings. This function can be used and called to your own liking.

By passing an ID of the file to this function we will create a link that will get the permalink from the ID and also the title of the file. At this moment we would only send the user of this button to the attachment page of this file. By using the next two functions we will change that behavior into a download rather than a visit to a page.

Checking the Query Strings

In the previous function we have set two Query Strings with the permalink to the file and they are the indicator that a download should start. We will check them before the rendering of the page starts. This is done by using the WordPress action init:

This function is added to the action array of the name init and it will be called before the rendering starts. By doing it like that we can send a different header from the server and stop the rendering of the page.

In this example we are not checking the value of the keys in the query strings but only checking if they are set. You can strengthen your function by checking the values and also checking the wpnonce that would be set also in the previous function where we have created the link.

If everything is set then this function will call another function that will create the actual download.

Downloading the file

This is the final function that will create the download. Here we are getting the file from the ID using the WordPress API and if there is a file with the ID that was provided, then we will create the download.

On the lines after we checked that the file exists, we are cleaning the result, getting the filename and the extension. The extension is important because we can then check if this extension is allowed for download. We are also using the extension to set the right headers to send from the server.
After that we are creating a variable called whitelist. This variable will be used to define an array with all the extensions that are available for download. We are also applying a filter which can be used to extend this array or not. How to use WordPress filter can be learned here.
After that we are checking if the file is allowed and also to check if the file is not a php file just to be sure. If those checks pass we are setting the content type for the headers we will send from the server. We are also applying a filter to this variable and we are also passing an additional parameter which is the extension. By using this filter together with the filter before we can extend this functionality and enable other files for download.
When everything is set we are sending to our user different headers with the file for download.

Conclusion

By using some WordPress API and simple PHP functions we can create a great plugin or a theme functionality to download a file from WordPress. This examples can be extended as you wish and can be used for any application you are building upon WordPress.

Have you ever programmatically downloaded a file from WordPress? Do you have other techniques for this? Please share your tips in the comments below or just post what is on your mind 😉

Become a Sponsor

Posted by Igor Benic

Web Developer who mainly uses WordPress for projects. Working on various project through Codeable & Toptal. Author of several ebooks at https://leanpub.com/u/igorbenic.

15 Comments

  1. Great post thanks! Just a small change needed to line 8 of the function ibenic_the_file_link( $attachment_id ),

    edited: '<a href="' . get_permalink( $attachment_id ) . '?attachment_id='.$attachment_id.'&download_file=1" rel="nofollow">';

    Note the removal of get_the_id() and replacing with $attachment_id to make this work outside the loop, and also removal of the double quote after $attachment_id= as that would end the href parameter prematurely.

    After that this code worked as treat, so, many thanks!

    Reply

    1. Thank you very much for that! I saw the errors in the code and corrected them.:)

      Reply

  2. With the file type (lines 34 – 52 on the “checked_and_download.php” script), I believe you could just replace that entire block with `$content_type = get_post_mime_type( $attID );`, which would pass the same value through based on whatever WordPress sets the type to. From what I’ve tried, that seems to do the trick just as well and saves you having to add cases for each file type. (Although I am on Windows so I could be entirely wrong on that front.)

    Fantastic code though. Now I need to work out how to add GA Event Tracking onto the `ibenic_the_file_link` link and whether I need to do this for each file in GA or whether I can just expand on the function and use variables.

    Reply

    1. Hi Nathan, thank you for the comment. That might be a much better way of handling it, I agree!

      Regarding the GA Event Tracking, you could maybe add a filter in that function such as $atts = apply_filters( 'ibenic_the_file_link_atts', array(), $attachment_id );

      And then, have another function, hooked in it with add_filter, to check on it and add specific attributes to the link based on the attachment ID.

      After that, just go through the items in that array and apply those attributes to the link. Hope that helped or gave you an idea on how you could handle that:)

      Reply

  3. I’ve added the code of all files in my functions.php – is that right?
    There ist nothinh happening when the url changes—

    Reply

    1. That should be enough, correct. So you are changing the URL to url_to_your_attachment?attachment_id=ID_OF_ATTACHMENT&download_file=1?

      Reply

  4. i am unable to download pdf file from this code.

    Reply

    1. Hi Arun, I’ll have to try the code once more. Maybe something changed in WordPress.

      Reply

  5. I have a question, I know that “Content-Type: application/force-download” is a hack supported by some browsers. What will happen to browsers that do not support it?

    Reply

    1. It this it should work as well since the browser/server will try to send you the file. I would suggest trying using the application/[CORRECT_TYPE] for your file and you should be fine.

      I’ve tried the same with CSV files and it worked out as supposed.

      Reply

  6. It works, great scripts, thanks

    Reply

  7. This was just what I needed. I’m building a site where users can only download material within a subscription or that they have bought. This code was the perfect starting place to get this functionality built in. Thank you!!!

    Reply

    1. Hello,
      sorry if I ask to much, but could you please help out with protection with wp_nonce?
      I work on subscription just like Arjen, and I need to give my subscribers link to PDFs to download, I don’t want them to share links to people without account, and with your code that works, no matter if logged in or not, link downloads file.

      Reply

  8. work fine, thanks!!!!!!!!!

    Reply

  9. Hi,

    The download code working fine but my downloaded PDF file is always zero bytes and not opening with a pdf reader. Any suggestion?

    Reply

Leave a reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.