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?
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);
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 FabrySep 9, 2010 at 18:18
I really have to second the ‘View Own Posts Media Only’ plugin, it worked perfectly for me after looking everywhere for a jquery or php/html/css solution.
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;
$is_attachment_request = ($wp_query_obj->get('post_type')=='attachment');
if( !$is_attachment_request )
return;
if( !is_a( $current_user, 'WP_User') )
return;
if( !in_array( $pagenow, array( 'upload.php', 'admin-ajax.php' ) ) )
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.. π
Improve this answerFollow
10344 bronze badges
answered Nov 20, 2010 at 13:11
18.6k33 gold badges5454 silver badges6868 bronze badges
- 1″Not working” isn’t much to go on. β t31os Aug 8, 2013 at 22:03
- I can confirm the same observation. For me “not working” means that the “contributor” role can still see all media items when he goes to upload a jpg. However, when he goes to media library from the menu, it’s empty. (My “contributor” role already has the extra capability to upload files and that’s working.) β Sparky Feb 3, 2014 at 19:27
- So your code just needs to be tweaked for whatever page fills the “Media Library” tab of the upload window. I’m researching this now. β Sparky Feb 3, 2014 at 19:30
- If i recall correctly(and mistakes do happen), there was not any appropriate hooks in place at the time of writing this answer, similarly to how no hooks were in place to fix the media count. There’s been a good 3 new versions of WordPress since the time of writing however, so solutions may now be possible. β t31os Feb 3, 2014 at 19:33
- Additionally, it could just be a matter of updating the
$pagenow
conditional check, as this aims to target the query specifically for the main media page, which is not one and the same as the media tab on the upload popup. β t31os Feb 3, 2014 at 19:35 - I don’t care about the counts being wrong. Otherwise, your code is working from the Media item in the menu (WP v3.8.1). I’m trying to get this working from the upload window that pops up from within the “New Post” page. Yes, I agree… I’m trying to find the correct page for the
$pagenow
check. β Sparky Feb 3, 2014 at 19:45 - Here is the solution: wordpress.stackexchange.com/a/132319/11092 β Sparky Feb 3, 2014 at 22:03
if( !in_array( $pagenow, array( 'upload.php', 'admin-ajax.php' )
This line in your code is missing a closing bracket)
, There should be three)
, but your code has only two. β Ibrahim Dec 10, 2016 at 6:52- This only seems to apply to the grid view. Any recommendations on how to accomplish this for the list view as well? β Dedering Nov 8, 2017 at 20:17
- Solution to my question above:
if( ('upload.php' != $pagenow ) && ( 'admin-ajax.php' != $pagenow || $_REQUEST['action'] != 'query-attachments' ) )
β Dedering Nov 8, 2017 at 22:01
As of WP 3.7 there is a much better way via the ajax_query_attachments_args
filter, as provided in the documentation:
add_filter( 'ajax_query_attachments_args', 'show_current_user_attachments' );
function show_current_user_attachments( $query ) {
$user_id = get_current_user_id();
if ( $user_id ) {
$query['author'] = $user_id;
}
return $query;
}
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="%1$s"%2$s>%4$s <span class="count">(%3$d)</span></a>',
admin_url('edit.php?post_type=post'),
$class,
$result->found_posts,
__('All')
);
elseif( $type['status'] == 'publish' ):
$class = ($wp_query->query_vars['post_status'] == 'publish') ? ' class="current"' : '';
$views['publish'] = sprintf(
'<a href="%1$s"%2$s>%4$s <span class="count">(%3$d)</span></a>',
admin_url('edit.php?post_type=post'),
$class,
$result->found_posts,
__('Publish')
);
elseif( $type['status'] == 'draft' ):
$class = ($wp_query->query_vars['post_status'] == 'draft') ? ' class="current"' : '';
$views['draft'] = sprintf(
'<a href="%1$s"%2$s>%4$s <span class="count">(%3$d)</span></a>',
admin_url('edit.php?post_type=post'),
$class,
$result->found_posts,
__('Draft')
);
elseif( $type['status'] == 'pending' ):
$class = ($wp_query->query_vars['post_status'] == 'pending') ? ' class="current"' : '';
$views['pending'] = sprintf(
'<a href="%1$s"%2$s>%4$s <span class="count">(%3$d)</span></a>',
admin_url('edit.php?post_type=post'),
$class,
$result->found_posts,
__('Pending')
);
elseif( $type['status'] == 'trash' ):
$class = ($wp_query->query_vars['post_status'] == 'trash') ? ' class="current"' : '';
$views['trash'] = sprintf(
'<a href="%1$s"%2$s>%4$s <span class="count">(%3$d)</span></a>',
admin_url('edit.php?post_type=post'),
$class,
$result->found_posts,
__('Trash')
);
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;
}
10344 bronze badges
answered Nov 27, 2011 at 20:00
93899 silver badges13
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
β chrismccoyFeb 25, 2012 at 0:40
You just have to define $_num_posts as an array in the fix_media_counts() function. $_num_posts = array();
The code in this answer works but it also removes any custom fields created by the Advanced Custom Fields plugin.
β SparkyFeb 3, 2014 at 20:26
This is a modified version of the accepted answer. Since the accepted answer only targets the Media menu item on the left, users could still see the whole media library within the modal box when uploading a photo to a post. This slightly modified code fixes that situation. The targeted users will only see their own media items from the Media Library tab of the modal box that pops up within a post.
This is the code from the accepted answer with a comment marking the line to edit…
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 ) // <-- let's work on this line
return;
if( !current_user_can('delete_pages') )
$wp_query_obj->set('author', $current_user->id );
return;
}
For users to only view their own media from Media menu AND Media Library tab of the upload modal, replace the indicated line with this…
if( ( 'upload.php' != $pagenow ) &&
( ( 'admin-ajax.php' != $pagenow ) || ( $_REQUEST['action'] != 'query-attachments' ) ) )
(line-breaks & spacing only inserted for readability here)
The following is the same as above but also restricts them to seeing their own posts from the Posts menu item.
if( ( 'edit.php' != $pagenow ) &&
( 'upload.php' != $pagenow ) &&
( ( 'admin-ajax.php' != $pagenow ) || ( $_REQUEST['action'] != 'query-attachments' ) ) )
(line-breaks & spacing only inserted for readability here)
Notes: as in the accepted answer, the posts and media counters will be wrong. However, there are solutions for this in some other answers on this page. I did not incorporate those simply because I had not tested them.
Improve this answerFollow
CommunityBot
1
answered Feb 3, 2014 at 22:03
24744 silver badges12
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' );
20.5k55 gold badges5959 silver badges9494 bronze badges
answered Nov 26, 2011 at 18:46
2911 bronze badge
- 2You should not use user levels, they are in WordPress still primarily for backwards compatibility(prior to WP 2.0), they are not reliable for determining user capabilities in modern day WordPress(as they will likely disappear from core when that compatibility is no longer required). Use an actual capability to determine user rights. β t31os Jan 28, 2014 at 13:56
2
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!
1
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!
Improve this answerFollow
answered Sep 10, 2010 at 14:56
62311 gold badge66 silver badges88 bronze badges
- 2There 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, 2010 at 0:49
<?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.
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.
Improve this answerFollow
answered Jan 11, 2011 at 11:01
1,07611 gold badge1414 silver badges28
source : https://wordpress.stackexchange.com/questions/1482/restricting-users-to-view-only-media-library-items-they-have-uploaded#comment1903_1482