Display only the posts authored by the current WP user on the ‘Posts’ page in the back-end

2 Jan

First, Wish you all a Happy New Year! :)
Now lets get down to the nerd stuff!
This is a very commonly faced problem by many WP devs. When logged in as a user with a role that is allowed to create / edit posts such as Author, Editor, Contributor or a custom role with the ‘edit_posts’ capability, the posts list on the ‘Posts’ page in the back-end shows all the published posts, even those by other users. The current user can see and edit his own posts, which is fine, but can see user’s posts which seems to be killing the sense of privacy in a multi-user system and is undesired by many developers. Doesn’t it look more secure and sophisticated when the posts list shows only the current users posts? In fact in a system where users are given accounts and privileges to create / edit posts, this fact is very important that they get to see only their work and not others. Also, it will reduce the posts list!

Unfortunately this is not possible with ‘edit_posts’ capability, as it displays all the published posts, and hence this hack can be used.

We’ll use the very well known action hook, ‘pre_get_posts’ for achieving this. If this sounds strange for you, then I suggest you read more on WP Actions and ‘pre_get_posts’ before reading down.

This is the code that’ll do our job:

add_action('pre_get_posts', 'filter_posts_list');
function filter_posts_list($query)
{
	//$pagenow holds the name of the current page being viewed
	 global $pagenow;

	//$current_user uses the get_currentuserinfo() method to get the currently logged in user's data
	 global $current_user;
	 get_currentuserinfo();
    
    	//Shouldn't happen for the admin, but for any role with the edit_posts capability and only on the posts list page, that is edit.php
    	if(!current_user_can('administrator') && current_user_can('edit_posts') && ('edit.php' == $pagenow))
   	 {
		//global $query's set() method for setting the author as the current user's id
		$query->set('author', $current_user->ID); 
    	}
}

That’s it! The code is pretty simple. We hook into ‘pre_get_posts’ which runs before the query for retrieving the posts list is run. Then we check that the current user is not the Admin but has a role with ‘edit_posts’ capability, and use $pagenow global variable to make sure our code is run only on the ‘Posts’ page in the back-end, which is actually named ‘edit.php’. Variable $query is an object of the WP_Query class, and holds the current query for getting the posts. It has a method ‘set’ that allows you to change the arguments of the query. All the parameters that can be used with WP_Query, are valid over here. Hence we set the current user’s id as the ‘Author’, which means the query will now retrieve only the current user’s posts.

Note: You can filter the posts list with any criteria you want using the same method!

Now, if you log in with the role you did this for (not the Admin!), and view the posts list page, you’ll see that it no more displays all the published posts, but only the current users posts.

There’s one more place that will reveal to the current user that there are other posts in this system as well, that is the 3 links that show the posts counts, ‘All’, ‘Published’ and ‘Mine’. As we’re showing the only the current user’s posts, we are interested in ‘Mine’, hence want to hide the other two.

Let’s do it right away. Edit the above code, and add the following lines to it, right after the line ‘$query->set…’:

$screen = get_current_screen();
 add_filter('views_'.$screen->id, 'remove_post_counts');

We’re using an undocumented filter ‘views_’.{screen_id}, which needs the current screen’s id. Hence we use the ‘get_current_screen()’ method for getting the current screen’s id, and append it to ‘view’. The function ‘remove_post_counts’ is as follows:

function remove_post_counts($posts_count_disp)
{
	//$posts_count_disp contains the 3 links, we keep 'Mine' and remove the other two.
	unset($posts_count_disp['all']);
    	unset($posts_count_disp['publish']);
    
    	return $posts_count_disp;
}

Visit the ‘Posts’ page again, and you should see only the current user’s posts count displayed there.

I assume this tutorial will help you achieve a better level of privacy and thus security, if you’re extensively using custom user roles in your system and allowing unknown users to edit posts. You can use the same trick and filter the posts list in the back-end ‘Posts’ page using any criteria you want!

Doubts, comments, criticism… always welcome!

28 Responses to “Display only the posts authored by the current WP user on the ‘Posts’ page in the back-end”

  1. Lollo January 29, 2012 at 9:47 am #

    Thanks for the article.

    if I leave current_user_can(‘edit_posts’) in the if statement it doesn’t work and everybody can see everything. I don’t know why, probably something with my capabilities.

    I would like to suggest to put unset($posts_count_disp['draft']); in remove_post_counts too.

    bye

    • rutwick April 6, 2012 at 3:41 pm #

      Great! I’ll try this one.

  2. Lollo January 29, 2012 at 10:02 am #

    Another thing… for the trash label.

    If i put unset($posts_count_disp['trash']); this hide to the user his trash too :(
    and for the draft it hide the draft label, but anyway a user can see draft article under mine label.

    bye

    • rutwick March 3, 2012 at 11:32 am #

      You can put another check as $query->set(‘post_status’, ‘publish’) although it should happen by default.

  3. mita March 4, 2012 at 8:10 am #

    thank you,i wish to use these code for my site. but i donot know where should i paste these code? please in form the wp file name.

    • rutwick April 6, 2012 at 3:41 pm #

      The functions.php file is the place to put it!

  4. Daniel March 18, 2012 at 3:18 am #

    Great solution !! I had done this before by adding some custom CSS with “display:none;” for these things.

    Also remember that the add new link, the check boxes, the search box and the bulk action boxes need to be removed as they are useless or unnecessary to the eyes of some users. Also by clicking them the user will get a error message.

    • rutwick April 6, 2012 at 3:38 pm #

      Thanks!
      Yes you’re right about those sections, I should give it a try.
      Do you have a solution to do that? Please let me know it too!

  5. tc April 16, 2012 at 10:34 am #

    Great Post!!

    However, I would like to know is there a way to change the number in the () to reflect the number only associated to the author? Instead of removed all the section like “Published”or “Draft”.

    Thanks

    • rutwick April 24, 2012 at 10:08 am #

      Yep, just use the filter used for changing the number. That is, `add_filter(‘views_’.$screen->id, ‘remove_post_counts’)` is what you’ll need.

  6. Ana Ban May 15, 2012 at 2:34 am #

    sweet post. is there a way to filter on the counts for all/published instead and still leave the links there? tia :D

    • rutwick May 17, 2012 at 5:29 am #

      You mean change the counts?

  7. Luis June 17, 2012 at 12:31 am #

    Thank you for this post, I have been looking for a similar code snippet to display posts by current author on the front end of a buddypress site. Specifically the author’s activity page. I am using a plugin that adds a “posts()” count display and when clicked it displays the most recent post, I want to display the excerpt of all posts by the current author, or the ability to display the last 3 post excerpts with the ability to navigate to the next 3 if any exist. When I first created the site this was a default setting which I lost at some point through an update. Here’s an example of how it used to look “http://www.petownerworld.com/members/cherieasmith/activity/” and here’s how it now displays “http://www.petownerworld.com/members/cherieasmith/” Thank you for your help.

    • rutwick July 16, 2012 at 5:12 am #

      Hi,
      Sorry, I’m unable to understand where you are (or were!) stuck exactly! Could you please explain what the problem was?

  8. Luis June 17, 2012 at 12:34 am #

    Correction on my last, this is how it used to display “http://www.petownerworld.com/members/socabag6/”

  9. tc June 26, 2012 at 12:08 pm #

    Your codes works! However, I received this error message: Notice: Undefined index: post_status in……
    Seem post_status is not recognized, but still work though..any idea why?

    • rutwick July 16, 2012 at 5:10 am #

      Sorry for the delay in reply.
      Please try printing the contents of the array, you’ll know if the status is set or not.
      - rutwick

  10. cara buat web December 19, 2012 at 9:30 am #

    Thanks for the tip.
    It inspires me to query based on meta_query

  11. bharath January 8, 2013 at 4:20 pm #

    Thank your Very Much.

    Worked Great

    • rutwick March 2, 2013 at 9:02 pm #

      You’re welcome! :)

  12. Stephanie January 17, 2013 at 1:46 am #

    Hi, how come this doesn’t work in my site?
    Does this work in Multisite?
    My non-admin users has Contributor Role.

    Thanks.

    • rutwick March 2, 2013 at 9:02 pm #

      Hi,
      Haven’t tried for a multisite yet!

  13. Ken January 17, 2013 at 2:46 pm #

    Hi, is it possible to use this on a custom post/page type instead of the actual blog posts? Thanks

    • rutwick March 2, 2013 at 9:01 pm #

      Pretty much yes, as WP uses the same method for displaying the posts on the front end. The WP_Query!

  14. Sash February 3, 2013 at 1:02 pm #

    Thank you for tip . One more question , I have “Author” page on my site where all posts are listed from that particular author . Is it possible to allow logged in authors to edit/delete their own posts from that page ?

    • rutwick March 2, 2013 at 9:01 pm #

      I think you should check the current user’s role on that page, and list his posts if its an Author. For edit, you may have to display a custom form.

  15. aditi August 19, 2013 at 6:42 am #

    Thanks a ton for your help :)

    • rutwick September 28, 2013 at 1:34 pm #

      Apologies, but I don’t seem to recollect helping you! Any reminders?

Leave a Reply