Use ‘parse_query’ filter to show posts that from multiple criteria

I am trying to filter the Posts page in the WordPress admin to show posts that meet the criteria for “A” -or- the criteria for “B”. I’ve scoured documentation and can’t find a good way to do this.

Details:
I’ve scoped user roles so that authors can only edit their own posts. However, I’ve added a custom field so that authors may select other authors to enable them to edit the post as well. This functionality works perfectly if I use one or the other in my ‘parse_query’ filter, but if I try to enable both the query thinks I want to show posts that fit ALL criteria (which is none).

For reference, here is my code (this is in functions.php):

add_filter('parse_query', 'show_appropriate_posts');
function show_appropriate_posts($query) {
    if ( strpos($_SERVER[ 'REQUEST_URI' ], '/wp-admin/edit.php') !== false ) {
        if ( !current_user_can('manage_options') ) {
            global $current_user;

            //Only list posts by this user (A).
            $query->set('author', $current_user->id);

            //List posts this user is "tagged" in (B).
            $query->set('meta_key', 'add_editing_permission_for');
            $query->set('meta_value', $current_user->id);
            $query->set('meta_compare', 'LIKE');

            //@TODO: Need to show posts that meet (A) -or- (B).
        }
    }
}

Again, both (A) and (B) are working when run alone.

1 Answer
1

Ignore my comment about meta_query. Not only does it not work with $query->set(), you wouldn’t be able to control the critical “A OR B” requirement of the query.

Instead, I believe what you require is possible via a combination of both the pre_get_posts action hook and posts_where filter hook as follows.

add_action('pre_get_posts', 'my_show_appropriate_posts');
function my_show_appropriate_posts($query){

    if(strpos($_SERVER[ 'REQUEST_URI' ], '/wp-admin/edit.php') !== false) :

        if(!current_user_can('manage_options')) :

            /** Unset so that we can control exactly where this part of the query is included */
            $query->set('author', null);

            /** Ensure that the relevant tables required for a meta query are included */
            $query->set('meta_query', array(
                array(
                    'key'       => 'add_editing_permission_for',
                    'value'     => 'dummy', // This cannot be empty because of a bug in WordPress
                    'compare'   => '='
                )
            ));

            /** Call the filter to amend the '$where' portion of the query */
            add_filter('posts_where', 'my_custom_posts_where');

        endif;

    endif;

}

function my_custom_posts_where( $where="" ){

    global $wpdb;

    /** Add our required conditions to the '$where' portion of the query */
    $where.= sprintf(
        ' AND ( %1$s.post_author = %2$s OR ( %3$s.meta_key = "add_editing_permission_for" AND %3$s.meta_value = %2$s ) )',
        $wpdb->posts,
        get_current_user_id(),
        $wpdb->postmeta
    );

    /** Remove the filter to call this function, as we don't want it any more */
    remove_filter('posts_where', 'my_custom_posts_where');

    return $where;

}

Recommended reading

  • The pre_get_posts action hook – http://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts

  • The posts_where filter hook – http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where

Leave a Comment