I am using WP user front end plugin to let users submit posts to my site that includes a file on that post that other users can download.

The problem is I want user-a to only be able to download a file from that post once forever on the site.

Something along the lines of - if current logged in user - is viewing a post that includes a file he has already downloaded - change download button to - already downloaded!

Hope you can help..


  • Is this for a self hosted site or for a WordPress.com site? If it's for a .com site then it's a completely different question to if it's a self hosted site
    – Tom J Nowell
    Commented Apr 7, 2016 at 14:55
  • Hi It's self hosted Commented Apr 7, 2016 at 14:58

2 Answers 2


If your attachment is handled via the WP media library, each one has unique ID, just like Posts. When your users download the attachment by clicking the button, store a reference to that attachment ID in a user_meta setting and then update the button accordingly.

Another option: https://easydigitaldownloads.com/

  • This is a great idea - and is what I was trying to achieve! Being a bit of a newbie - can you explain step by step how I would achieve this. Basically as the post id's and the file attachment within it is unknown and generated a by a user submission I'm a little unsure how to achieve this. Commented Apr 7, 2016 at 15:03
  • Any help would be greatly appreciated!! I would very much like to store a reference to attachment id clicked to user_meta - Do you know how I can acheive this? Commented Apr 9, 2016 at 11:18

Perhaps your question no so much clear regarding your issue.I give the solution which i have understand the above question.

1. Define a query variable that indicates the requested file

function add_get_file_query_var( $vars ) {
    $vars[] = 'get_file';
    return $vars;
add_filter( 'query_vars', 'add_get_file_query_var' );

2. Update .htaccess to forward requests for restricted files to WordPress

This will capture requests to the files you want to restrict and send them back to WordPress using the custom query variable above. Insert the following rule before the RewriteCond lines.

RewriteRule ^wp-content/uploads/(.*\.docx)$ /index.php?get_file=$1

3. Capture the requested file name in custom query variable; and verify access to the file:

function intercept_file_request( $wp ) {
    if( !isset( $wp->query_vars['get_file'] ) )

    global $wpdb, $current_user;

    // Find attachment entry for this file in the database:
    $query = $wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE guid='%s'", $_SERVER['REQUEST_URI'] );
    $attachment_id = $wpdb->get_var( $query );

    // No attachment found. 404 error.  
    if( !$attachment_id ) {
        $wp->query_vars['error'] = '404';

    // Get post from database 
    $file_post = get_post( $attachment_id );
    $file_path = get_attached_file( $attachment_id );

    if( !$file_post || !$file_path || !file_exists( $file_path ) ) {
        $wp->query_vars['error'] = '404';

    // Logic for validating current user's access to this file...
    // Option A: check for user capability
    if( !current_user_can( 'required_capability' ) ) {
        $wp->query_vars['error'] = '404';

    // Option B: check against current user
    if( $current_user->user_login == "authorized_user" ) {
        $wp->query_vars['error'] = '404';

    // Everything checks out, user can see this file. Simulate headers and go:
    header( 'Content-Type: ' . $file_post->post_mime_type );
    header( 'Content-Dispositon: attachment; filename="'. basename( $file_path ) .'"' );
    header( 'Content-Length: ' . filesize( $file_path ) );

    echo file_get_contents( $file_path );
add_action( 'wp', 'intercept_file_request' );

NB This solution works for single-site installs only! This is because WordPress MU already forwards uploaded file requests in sub-sites through wp-includes/ms-files.php. There is a solution for WordPress MU as well, but it's a bit more involved.

  • Nice answer, some notes: 1: Consider using user meta to track if a user has already downloaded a file or not. This would also let you store a counter rather than a yes or no so they can download it 2 or 3 times. 2: Use WP_Query rather than a wpdb direct SQL query, it'll allow you to make use of caching mechanisms, and other optimisations 3: Consider adding some browser cache directives to the headers 4: You misspelt Content-Disposition 5: For security reasons I would add a whitelist of document types in the intercept_file_request hook
    – Tom J Nowell
    Commented Apr 7, 2016 at 14:55
  • Hi Thanks for your response - Can you explain a little further and in more detail how I would implement this into my site. For example step one - Define a query variable, would that go into my functions. php file or put in place in single post template page?For step two would it be a case of copying the above code exactly? And for step 3 is that to be placed in functions.php or in my single post template file? Commented Apr 7, 2016 at 14:58
  • @TomJNowell thanks for your detailed response! Basically I am newbie to wp but am okay with costuming php files etc etc. Would it be possible for you to break down the steps I would have to do exactly in order to achieve this? Commented Apr 7, 2016 at 15:00
  • @joelybristol to fully understand where these pieces of code go, you will need to look up what hooks and filters are, as well as some basics about what functions.php does in a theme, and how to create a plugin ( it sounds hard but it's actually super trivial ). Start with what @owais-alam has written, which will give you a functional implementation ( but make the spelling change Dispositon -> Disposition ), then ask new questions on the site for the rest
    – Tom J Nowell
    Commented Apr 7, 2016 at 15:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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