Tell me more ×
WordPress Answers is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I want users to be able to upload photos using add_cap('upload_files') but in their profile page, the Media Library shows every image that's been uploaded. How can I filter that so that they can only view the images THEY uploaded?

Thanks in advance!

Update:

Here's my solution for the moment... I'm doing a simple WP query, then a Loop on the user's "Profile" page

$querystr = " SELECT wposts.post_date,wposts.post_content,wposts.post_title, guid 
FROM $wpdb->posts wposts
WHERE wposts.post_author = $author 
AND wposts.post_type = 'attachment' 
ORDER BY wposts.post_date DESC";

$pageposts = $wpdb->get_results($querystr, OBJECT);
share|improve this question
That's a nice question. – hakre Sep 7 '10 at 21:40
1  
If you found an answer to your own problem, you better add it as an answer below, not in the question itself. This is better in line with the system, and we can up-vote your answer, which will improve your reputation on this site. – Jan Fabry Sep 9 '10 at 18:18
@Jan Thanks. Will do. – TerryMatula Sep 10 '10 at 14:39

8 Answers

up vote 14 down vote accepted

You could always filter the media list using a pre_get_posts filter that first determines the page, and the capabilities of the user, and sets the author parameter when certain conditions are met..

Example

add_action('pre_get_posts','users_own_attachments');
function users_own_attachments( $wp_query_obj ) {

    global $current_user, $pagenow;

    if( !is_a( $current_user, 'WP_User') )
        return;

    if( 'upload.php' != $pagenow )
        return;

    if( !current_user_can('delete_pages') )
        $wp_query_obj->set('author', $current_user->id );

    return;
}

I used the delete pages cap as a condition so Admins and Editors still see the full media listing.

There is one small side effect, which i can't see any hooks for, and that's with the attachment counts shown above the media list(which will still show the total count of media items, not that of the given user - i'd consider this a minor issue though).

Thought i'd post it up all the same, might be useful.. ;)

share|improve this answer
I have allowed file upload to subscriber level users. tried to use your code but not working. – Sisir May 6 '12 at 17:52

t31os has a great solution up there. The only thing is that the number of all the posts still shows up.

I figured out a way to keep the number count from showing up using jQuery.

Just add this to your function file.

    function jquery_remove_counts()
{
    ?>
    <script type="text/javascript">
    jQuery(function(){
        jQuery("ul.subsubsub").find("span.count").remove();
    });
    </script>
    <?php
}
add_action('admin_head', 'jquery_remove_counts');

It's working for me!

share|improve this answer

Here's a complete solution for both posts and media (this code is specifically for authors, but you can change it for any user role). This also fixes the post/media count without hacking the core files.

// Show only posts and media related to logged in author
add_action('pre_get_posts', 'query_set_only_author' );
function query_set_only_author( $wp_query ) {
    global $current_user;
    if( is_admin() && !current_user_can('edit_others_posts') ) {
        $wp_query->set( 'author', $current_user->ID );
        add_filter('views_edit-post', 'fix_post_counts');
        add_filter('views_upload', 'fix_media_counts');
    }
}

// Fix post counts
function fix_post_counts($views) {
    global $current_user, $wp_query;
    unset($views['mine']);
    $types = array(
        array( 'status' =>  NULL ),
        array( 'status' => 'publish' ),
        array( 'status' => 'draft' ),
        array( 'status' => 'pending' ),
        array( 'status' => 'trash' )
    );
    foreach( $types as $type ) {
        $query = array(
            'author'      => $current_user->ID,
            'post_type'   => 'post',
            'post_status' => $type['status']
        );
        $result = new WP_Query($query);
        if( $type['status'] == NULL ):
            $class = ($wp_query->query_vars['post_status'] == NULL) ? ' class="current"' : '';
            $views['all'] = sprintf(__('<a href="%s"'. $class .'>All <span class="count">(%d)</span></a>', 'all'),
                admin_url('edit.php?post_type=post'),
                $result->found_posts);
        elseif( $type['status'] == 'publish' ):
            $class = ($wp_query->query_vars['post_status'] == 'publish') ? ' class="current"' : '';
            $views['publish'] = sprintf(__('<a href="%s"'. $class .'>Published <span class="count">(%d)</span></a>', 'publish'),
                admin_url('edit.php?post_status=publish&post_type=post'),
                $result->found_posts);
        elseif( $type['status'] == 'draft' ):
            $class = ($wp_query->query_vars['post_status'] == 'draft') ? ' class="current"' : '';
            $views['draft'] = sprintf(__('<a href="%s"'. $class .'>Draft'. ((sizeof($result->posts) > 1) ? "s" : "") .' <span class="count">(%d)</span></a>', 'draft'),
                admin_url('edit.php?post_status=draft&post_type=post'),
                $result->found_posts);
        elseif( $type['status'] == 'pending' ):
            $class = ($wp_query->query_vars['post_status'] == 'pending') ? ' class="current"' : '';
            $views['pending'] = sprintf(__('<a href="%s"'. $class .'>Pending <span class="count">(%d)</span></a>', 'pending'),
                admin_url('edit.php?post_status=pending&post_type=post'),
                $result->found_posts);
        elseif( $type['status'] == 'trash' ):
            $class = ($wp_query->query_vars['post_status'] == 'trash') ? ' class="current"' : '';
            $views['trash'] = sprintf(__('<a href="%s"'. $class .'>Trash <span class="count">(%d)</span></a>', 'trash'),
                admin_url('edit.php?post_status=trash&post_type=post'),
                $result->found_posts);
        endif;
    }
    return $views;
}

// Fix media counts
function fix_media_counts($views) {
    global $wpdb, $current_user, $post_mime_types, $avail_post_mime_types;
    $views = array();
    $count = $wpdb->get_results( "
        SELECT post_mime_type, COUNT( * ) AS num_posts 
        FROM $wpdb->posts 
        WHERE post_type = 'attachment' 
        AND post_author = $current_user->ID 
        AND post_status != 'trash' 
        GROUP BY post_mime_type
    ", ARRAY_A );
    foreach( $count as $row )
        $_num_posts[$row['post_mime_type']] = $row['num_posts'];
    $_total_posts = array_sum($_num_posts);
    $detached = isset( $_REQUEST['detached'] ) || isset( $_REQUEST['find_detached'] );
    if ( !isset( $total_orphans ) )
        $total_orphans = $wpdb->get_var("
            SELECT COUNT( * ) 
            FROM $wpdb->posts 
            WHERE post_type = 'attachment'
            AND post_author = $current_user->ID 
            AND post_status != 'trash' 
            AND post_parent < 1
        ");
    $matches = wp_match_mime_types(array_keys($post_mime_types), array_keys($_num_posts));
    foreach ( $matches as $type => $reals )
        foreach ( $reals as $real )
            $num_posts[$type] = ( isset( $num_posts[$type] ) ) ? $num_posts[$type] + $_num_posts[$real] : $_num_posts[$real];
    $class = ( empty($_GET['post_mime_type']) && !$detached && !isset($_GET['status']) ) ? ' class="current"' : '';
    $views['all'] = "<a href='upload.php'$class>" . sprintf( __('All <span class="count">(%s)</span>', 'uploaded files' ), number_format_i18n( $_total_posts )) . '</a>';
    foreach ( $post_mime_types as $mime_type => $label ) {
        $class = '';
        if ( !wp_match_mime_types($mime_type, $avail_post_mime_types) )
            continue;
        if ( !empty($_GET['post_mime_type']) && wp_match_mime_types($mime_type, $_GET['post_mime_type']) )
            $class = ' class="current"';
        if ( !empty( $num_posts[$mime_type] ) )
            $views[$mime_type] = "<a href='upload.php?post_mime_type=$mime_type'$class>" . sprintf( translate_nooped_plural( $label[2], $num_posts[$mime_type] ), $num_posts[$mime_type] ) . '</a>';
    }
    $views['detached'] = '<a href="upload.php?detached=1"' . ( $detached ? ' class="current"' : '' ) . '>' . sprintf( __( 'Unattached <span class="count">(%s)</span>', 'detached files' ), $total_orphans ) . '</a>';
    return $views;
}
share|improve this answer
great snippet but if no items are in the media library, it spits out errors, Warning: array_sum() expects parameter 1 to be array, null given, and Warning: array_keys() expects parameter 1 to be array, null given – chrismccoy Feb 25 '12 at 0:40
You just have to define $_num_posts as an array in the fix_media_counts() function. $_num_posts = array(); – Paul Sep 8 '12 at 23:37

Complete working code.. Only issue is, getting wrong count of images in media library on Add Post page.

function my_files_only( $wp_query ) {
if ( strpos( $_SERVER[ 'REQUEST_URI' ], '/wp-admin/upload.php' ) !== false ) {
    if ( !current_user_can( 'level_5' ) ) {
        global $current_user;
        $wp_query->set( 'author', $current_user->id );
    }
}
else if ( strpos( $_SERVER[ 'REQUEST_URI' ], '/wp-admin/media-upload.php' ) !== false ) {
    if ( !current_user_can( 'level_5' ) ) {
        global $current_user;
        $wp_query->set( 'author', $current_user->id );
    }
}
}
add_filter('parse_query', 'my_files_only' );
share|improve this answer

I used Philip's plugin and made some modifications to plugin and WP files to solve the issue with totals of items. See details at http://junvo.com/blog/2011/restrict-users-to-view-only-their-own-media-library-items-in-wordpress.html

share|improve this answer
You are better off posting relevant code here if possible than just posting a link to what looks like your site. – s_ha_dum Nov 24 '12 at 6:16

One way of doing this is to use the Role Scoper plugin, it is great for managing very specific roles and capabilities too. You can actually lock access to images in the Media Library to only those uploaded by each user. I've been using it for a project that I'm working on at the moment and it works well.

share|improve this answer
<?php
/*
Plugin Name: Manage Your Media Only
Version: 0.1
*/

//Manage Your Media Only
function mymo_parse_query_useronly( $wp_query ) {
    if ( strpos( $_SERVER[ 'REQUEST_URI' ], '/wp-admin/upload.php' ) !== false ) {
        if ( !current_user_can( 'level_5' ) ) {
            global $current_user;
            $wp_query->set( 'author', $current_user->id );
        }
    }
}

add_filter('parse_query', 'mymo_parse_query_useronly' );
?>

Save code above as manage_your_media_only.php, zip it, upload as plugin to your WP and activate it, that's all.

share|improve this answer

I solved my problem with a pretty rough, but workable solution.

1) I installed the WP Hide Dashboard plugin, so the User would only see a link to their profile edit form.

2) In author.php template file, I inserted the code I used above.

3) Then, for logged in users, I displayed a direct link to the Upload page "wp-admin/media-new.php"

4) The next issue I noticed, was after they uploaded the photo, it would redirect them to upload.php... and they could see all the other pictures. I haven't found a hook into the media-new.php page, so I ended up hacking into the core "media-upload.php" and redirecting them to their profile page:

    global $current_user;
    get_currentuserinfo();
    $userredirect =  get_bloginfo('home') . "/author/" .$current_user->user_nicename;

Then replaced wp_redirect( admin_url($location) ); with wp_redirect($userredirect);

A couple of issues, though. First, the logged in user can still go to "upload.php", if they know it exists. They can't do anything except LOOK at the files, and 99% of people won't even know about it, but it's still not optimal. Second, it also redirect the Admin to the profile page after uploading. These can have a fairly simple fix by checking user roles, and only redirecting Subscribers.

If anyone has ideas about hooking into the Media page without going into the core files, I'd appreciate it. Thanks!

share|improve this answer
2  
There is an admin_init hook that runs on every admin request. In case a user requests upload.php and you want to prevent that you could either block that request (e.g. wp_die('Access Denied')) or redirect to some valid place per hook. – hakre Sep 11 '10 at 0:49

protected by toscho Jul 2 '12 at 21:48

This question is protected to prevent "thanks!", "me too!", or spam answers by new users. To answer it, you must have earned at least 10 reputation on this site.

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