How to exclude password protected posts in WordPress loop
I have a custom post type that supports password protected entries. In a custom loop using a new WP_Query obje开发者_运维知识库ct, I want to exclude those password protected posts from the results. What arguments do I need set in order to do this? I am using the latest trunk version of WordPress 3.2.1.
I come up to this question where I was looking for the same. However, I read WP_Query document line by line then found very simple solution and that is just to add 'has_password' => false
argument to the query $args
So the code will be as below...
$args = [
'post_type' => [ 'post', 'page' ],
'posts_per_page' => 3,
'post__not_in' => get_option( 'sticky_posts' ),
'has_password' => FALSE
];
Here you can see I have excluded Sticky
and Password Protected
posts.
I really like Kevin's approach, but I adjusted it slightly:
// Create a new filtering function that will add our where clause to the query
function my_password_post_filter( $where = '' ) {
// Make sure this only applies to loops / feeds on the frontend
if (!is_single() && !is_admin()) {
// exclude password protected
$where .= " AND post_password = ''";
}
return $where;
}
add_filter( 'posts_where', 'my_password_post_filter' );
Did you take a look at the post_status argument of WP_Query?
"Protected" seems like a good candidate to exclude.
Edit: Okay, it seems like you'll have to modify the where clause to achieve what you want:
// Create a new filtering function that will add our where clause to the query
function filter_where( $where = '' ) {
// exclude password protected
$where .= " AND post_password = ''";
return $where;
}
if (!is_single()) { add_filter( 'posts_where', 'filter_where' ); }
$query = new WP_Query( $query_string );
remove_filter( 'posts_where', 'filter_where' );
After a bit of playing about, I found the posts_where filter a bit too intrusive for what I wanted to do, so I came up with an alternative. As part of the 'save_post' action that I attached for my custom post type, I added the following logic;
$visibility = isset($_POST['visibility']) ? $_POST['visibility'] : '';
$protected = get_option('__protected_posts', array());
if ($visibility === 'password' && !in_array($post->ID, $protected)) {
array_push($protected, $post->ID);
}
if ($visibility === 'public' && in_array($post->ID, $protected)) {
$i = array_search($post->ID, $protected);
unset($protected[$i]);
}
update_option('__protected_posts', $protected);
What this does is hold an array of post id's in the options table where the post is protected by a password. Then in a custom query I simply passed this array as part of the post__not_in
option e.g.
$query = new WP_Query(array(
'post_type' => 'my_custom_post_type',
'post__not_in' => get_option('__protected_posts'),
));
This way I could exclude the protected posts from an archive page but still allow a user to land on the password protected page to enter the password.
In addition to @Peter Chester's answer:
You may also want to exclude password-protected posts from the Previous Post
and Next Post
links, if you have those at the bottom of your post page.
To do so you can add the exclusion to the get_previous_post_where
and get_next_post_where
hooks.
add_filter( 'get_previous_post_where', 'my_theme_mod_adjacent' );
add_filter( 'get_next_post_where', 'my_theme_mod_adjacent' );
function my_theme_mod_adjacent( $where ) {
return $where . " AND p.post_password = ''";
}
精彩评论