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
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