Set a maximum upload count for users on a specific user role

For users with the Contributor user role, I want to restrict the total amount of images that they are allowed to upload. I found this code posted on an answer here:

add_filter( 'wp_handle_upload', 'wpse47580_update_upload_stats' );
function wpse47580_update_upload_stats( $args ) {

    $user_id = get_current_user_id();

    $upload_count = get_user_meta( $user_id, 'upload_count', $single = true );

    update_user_meta( $user_id, 'upload_count', $upload_count + 1 );
}

add_filter( 'wp_handle_upload_prefilter', 'wpse47580_check_upload_limits' );
function wpse47580_check_upload_limits( $file ) {
    $user_id = get_current_user_id();

    $upload_count = get_user_meta( $user_id, 'upload_count', $single = true );

    $upload_count_limit_reached = apply_filters( 'wpse47580_upload_count_limit_reached', 10 ) > ( $upload_count + 1 );

    if ( $upload_count_limit_reached  )
        $file['error'] = 'Upload limit has been reached for this account!';

    return $file;
}

There are two problems. Firstly, the above code does not function properly, it is supposed to allow 10 uploads but the upload limit message is displayed no matter what. Secondly, it applies to all user roles.

Read More

Upon further research, I found this working answer, but the solution applies for total uploads per post, not user.

How can I set an upload count limit for users on a specific user role? Ideally with a solution that deducts the count if user permanently removes an uploaded image.

Related posts

3 comments

  1. I’m not really sure which is the real problem with code you posted, however I cant understand why use 2 functions when one is enough…

    add_filter( 'wp_handle_upload_prefilter', 'limit_uploads_for_user_roles' );
    
    function limit_uploads_for_user_roles( $file ) {
      $user = wp_get_current_user();
      // add the role you want to limit in the array
      $limit_roles = array('contributor');
      $filtered = apply_filters( 'limit_uploads_for_roles', $limit_roles, $user );
      if ( array_intersect( $limit_roles, $user->roles ) ) {
        $upload_count = get_user_meta( $user->ID, 'upload_count', true ) ? : 0;
        $limit = apply_filters( 'limit_uploads_for_user_roles_limit', 10, $user, $upload_count, $file );
        if ( ( $upload_count + 1 ) > $limit ) {
          $file['error'] = __('Upload limit has been reached for this account!', 'yourtxtdomain');
        } else {
          update_user_meta( $user->ID, 'upload_count', $upload_count + 1 );
        }
      }
      return $file;
    }
    

    Note that the count start when you add the function and the filter: all previous uploaded files are not counted.

    The roles to limit can be altered also via filter.

    The limit can be changed via filter (default 10 in my code) and I also pass to filter the user object and the current number of user uploads, in this way the filter can take into accounts more informations…

    Edit

    To decrease the count when a contributor delete an attachment hook delete_attachment and do some logic:

    add_action('delete_attachment', 'decrease_limit_uploads_for_user');
    
    function decrease_limit_uploads_for_user( $id ) {
       $user = wp_get_current_user();
       // add the role you want to limit in the array
       $limit_roles = array('contributor');
       $filtered = apply_filters( 'limit_uploads_for_roles', $limit_roles, $user );
       if ( array_intersect( $limit_roles, $user->roles ) ) {
         $post = get_post( $id);
         if ( $post->post_author != $user->ID ) return;
         $count = get_user_meta( $user->ID, 'upload_count', true ) ? : 0;
         if ( $count ) update_user_meta( $user->ID, 'upload_count', $count - 1 );
       }
    }
    

    Note that previous code do not prevent attachment being deleted was uploaded by other users, because this should be handled by the functions/plugin/code that allow contributors to upload files (once by default they can’t do that) and because the 'delete_attachment' hook happens after the attachment was already deleted.
    However if the attachment was not uploaded by current user the decrease isn’t performed, just for sure…

  2. Instead of managing an extra meta field in the database per user, you could just keep things simple and count the number of uploads on the fly, like so:

    add_filter( 'wp_handle_upload_prefilter', 'limit_user_uploads' );
    
    function limit_user_uploads( $file ) {
        global $wpdb;
        $user = wp_get_current_user();
        $roles = array( 'contributor' ); // Roles to limit
        if ( array_intersect( $roles, $user->roles ) ) { // User has a restricted role
            // Count user's uploads
            $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_author = " . $user->ID );
            if ( 10 <= $count ) {
                $file['error'] = 'Upload limit has been reached for this account!';
            }
        }
        return $file;
    }
    

    This could be less practical for very large databases, but in many instances it will do just fine. It works out-of-the-box for existing databases and always ensures that the count is correct. It only counts uploads if the user matches a restricted role, so it doesn’t affect unrestricted users.

  3. I have adjusted the later answer to check for the user role, I haven’t tested it but this should work

    The filter wp_handle_upload_prefilter provides you with an opportunity to examine or alter the filename before the file is moved to its final location. so here we would check for the role and upload count.

    add_filter( 'wp_handle_upload_prefilter', 'wp_check_upload_limits' );
    function wp_check_upload_limits( $file ) {
        $current_user = wp_get_current_user();
        $current_user_role = $current_user->roles[0];
    
        if ( $current_user_role != "contributor" )
            return false;
    
        $upload_count = get_user_meta( $current_user->ID, 'upload_count', true );
        $upload_count_limit_reached = apply_filters( 'wpse47580_upload_count_limit_reached', 100 ) > ( $upload_count + 1 );
    
        if ( $upload_count_limit_reached )
            $file['error'] = 'Upload limit has been reached for this user!';
    
        return $file;
    }
    

Comments are closed.