I would like to make XML files downloadable, instead of allowing the browser to displaying them inline.

I know I can use the Content-Disposition: attachment HTTP header (of course, better solutions are welcome!). I want to add this header in all HTTP responses when a user tries to download an XML file.

I can use the following PHP code:

header('Content-Disposition: attachment; filename="the_filename.xml"');

The problem is: when I can call this instruction? What hook should I use and how?

  • 2
    If your files are stored on the FS in wp-content, then you can do this via htaccess, no WordPress involvement is necessary. If this is not the case, you'll need to provide more information
    – Tom J Nowell
    Oct 3 '12 at 13:26
  • Hello Tom! Yes, files are saved in wp-content\uploads and I can modify the htaccess. Do you have suggestions on how I could do?
    – User
    Oct 3 '12 at 13:47
  • add a htaccess in your uploads folder, this is clearly an Apache HTAccess question now, and is offtopic, it belongs on StackOverflow, not wordpress answers
    – Tom J Nowell
    Oct 3 '12 at 14:23
  • Thanks. I solved putting a .htaccessfile inside wp-content\uploads with this content <FilesMatch "\.(xml)$"> ForceType application/octet-stream Header set Content-Disposition attachment </FilesMatch>
    – User
    Oct 3 '12 at 14:31
  • @User Does my proposed solution answer your original question, regarding the proper hook to use? Oct 3 '12 at 18:11

Actually, my recommendation would be to do things a bit differently. You can add a custom rewrite endpoint to WordPress to handle these files specifically.

For example, the URL http://site.com/download-xml/the_filename would automatically download the specified file as an attachment.

First, you need to add a custom rewrite endpoint to set this up:

function add_endpoint() {
    add_rewrite_endpoint( 'download-xml', EP_ALL );
add_action( 'init', 'add_endpoint' );

This conveniently also adds a query variable so we can check to see if this endpoint is being used during a standard template redirect.

function download_redirect() {
    global $wp_query;

    // If this isn't the right kind of request, bail.
    if ( ! isset( $wp_query->query_vars['download-xml'] ) || empty( $wp_query->query_vars['download-xml'] ) )

    // Download the file.

add_action( 'template_redirect', 'download_redirect' );

In the function above, you can do whatever you need to download the file. Load it from the /wp-content/uploads directory as a stream, set the file headers (with content-disposition set to "attachment"), dynamically generate content based on something in the database, whatever you want.

Just be sure to have the exit() call at the end, otherwise WordPress will try to execute its regular template redirection calls and you'll get some ugly "headers already sent" errors later down the road.


You will need to take a look at Plugin API/Action Reference/send headers


add_action( 'send_headers', 'add_header_xua' );
function add_header_xua() {
     header( 'X-UA-Compatible: IE=edge,chrome=1' );

I think you can use the parse_request action hook parse_request

add_action('parse_request', 'handleDownload', 10, 1);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.