WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to serve a dynamically-generated PDF with a "File Transfer" header

header('Content-Description: File Transfer');

However, before I generate the document I need to verify the user's login and credentials.

     $currentUser = wp_get_current_user();
     $userLogin = $currentUser->user_login;
     if(userAllowedAccess($requestID, $userLogin)){
         header('Content-Description: File Transfer') 
         ....... file content
         //Do nothing... get off my lawn


Where do I put this so I don't get any headers or output from my wordpress page? I need to load enough of the API to get my is_user_logged_in() and wp_get_current_user() function but don't want to load anything that prints to the page...


Thanks- J

share|improve this question

I think you mean the Content-Disposition header.

I recently did a very similar thing for a client. My weapon of choice: custom rewrite rules.

First, add the rewrite:

add_action( 'init', 'wpse27232_add_rewrite' );
 * Adds the rewrite rule for the download.
 * @uses add_rewrite_rule
function wpse27232_add_rewrite()

When someone visits yoursite.com/download they will catch this rewrite. Notice the index.php?file_download=true bit. WordPress has no clue that file_download should be a recognized query variable. So let's make that recognizable by filtering query_vars.

add_filter( 'query_vars', 'wpse27232_query_vars' );
 * Filter our query vars so WordPress recognizes 'file_download'
function wpse27232_query_vars( $vars )
    $vars[] = 'file_download';
    return $vars;

Now the fun part: catch the file_download query variable and send the file.

add_action( 'template_redirect', 'wpse27232_catch_file_dl' );
 * Catches when the file_download query variable is present.  Sends the content
 * header, the file, and then exits.
function wpse27232_catch_file_dl()
    // No query var?  bail.
    if( ! get_query_var( 'file_download' ) ) return;

    // change this, obviously. Should be a path to the pdf file
    // I wrote this as a plugin, hence `plugin_dir_path`
    $f = plugin_dir_path( __FILE__ ) . 'your-file.pdf';
    if( file_exists( $f ) && is_user_logged_in() )
        // Do your additional checks and setup here

        // Send the headers
        header('Content-Type: application/pdf');
        header('Content-Disposition: attachment; filename=' . basename( $f ) );
        header( 'Content-Length: ' . filesize($f));
        // You may want to make sure the content buffer is clear here

        // read the pdf output
        global $wp_query;
        $wp_query->is_404 = true;

Finally to get this little plugin to work, an activation hook to flush the rewrite rules.

register_activation_hook( __FILE__, 'wpse27232_activation' );
function wpse27232_activation()
share|improve this answer

There are multiple approaches to do such:

  • page template
  • Ajax action
  • custom handler that loads core
  • early hook (such as template_redirect)
  • and so on...

Personally I'd go with Ajax action. It's pretty clean way to get full environment without any output and not overly complex to implement. See AJAX in Plugins in Codex.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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