Including only current user’s posts in search

I am a new WP plugin developer. I want the search page to include only the current user’s posts.

I first added a new capability read_others_posts to only administrators and editors. Then I tried the following code, placing it in a function and hooking it to the pre_get_posts action:

if( !current_user_can('read_others_posts') )
    $query->set( 'author', get_current_user_id() );

For all other queries (including in admin and in home), this “filter” works but search doesn’t. It still shows all posts on the result page.

Is there something that I did wrong? Is there a way to achieve what I described?

EDIT:

Just in case anyone wants to use this hook, let me provide a more general purpose version of the function, although I do think there is a better way to achieve this:

function exclude_other_users_posts( $query ) {
    if( !is_user_logged_in() ) {
        // guests cannot read private posts
        // and we exclude all public posts here
        // so guests can read nothing :-)
        $query->set( 'post_status', 'private' );
        $query->set( 'perm', 'readable' );
    } elseif( !current_user_can('read_others_posts') )
        $query->set( 'author', get_current_user_id() );
}
add_action( 'pre_get_posts', 'exclude_other_users_posts' );

1 Answer
1

After further testing, the problem was found to be caused by another filter, posts_where, which was registered to support searching also in custom fields, and that’s why only searching is affected.

Originally it generates something like this, so if the OR statement returns true (when one of the custom fields includes foo), that post will appear on the result page:

AND wp_posts.post_author IN (2) AND (
    (
        (wp_posts.post_title LIKE '%foo%') OR (wp_posts.post_content LIKE '%foo%')
    )
) AND ( /* wordpress stuff... */ ) OR ( /* section the filter generates... */ )

I have modified so that this filter returns:

AND wp_posts.post_author IN (2) AND (
    (
        (wp_posts.post_title LIKE '%foo%') OR (wp_posts.post_content LIKE '%foo%')
        OR ( /* section the filter generates... */ )
    )
) AND ( /* wordpress stuff */ )

Thanks to Johannes for giving me ideas that the original code should work 🙂

Leave a Comment