Im trying to hide protected posts in WP from loop:

function hideProtectedPosts( $where = '' ) {
    if (!is_single() && !is_admin()) {
        $where .= " AND post_password = ''";
    return $where;
add_filter( 'posts_where', 'hideProtectedPosts' );

works fine, but except archive. For eg. I have one post in June. In calendar widget I still can see that is post at this date, but when I get there, then I get 404.

1 Answer 1


There are 2 answers depending on where you want to do this. One has good news, the other has bad news

Anywhere That Uses Post Queries

Modifying the SQL is rarely necessary here and usually a sign that something was overlooked. In this case, WP_Query already provides a simple parameter to do this named has_password.

With this in mind, we can modify the main loop to hide passworded/protected posts easily via pre_get_posts:

add_action( 'pre_get_posts', function ( \WP_Query $q ) {
    if ( is_admin() || $q->is_singular() ) {
    $q->set( 'has_password', false );
} );

Anywhere That uses the get_calendar function

This includes the calendar widget and block, I'm afraid the news is not great.

get_calendar doesn't use WP_Query, but instead uses raw SQL queries to count posts ( it doesn't retrieve the posts ). It doesn't provide filters for the SQL either.

It does provide 2 opportunities however:

  • The get_calendar filter gives you the final HTML, allowing you to make some modifications to the final string. With this you could completely replace the HTML by re-implementing get_calendar and returning new HTML that excludes private posts in the SQL
  • The query filter. Because get_calendar calls WPDB query directly, you could filter on this, however, this filter runs on all queries WP makes, not just those for the calendar. You will need to figure out if a query is coming from get_calendar or not, which may be difficult or impossible. If you modify a query that isn't from get_calendar you could cause problems that lead to instability. There is also a potential bug, get_calendar does a check if there are any posts and returns an empty string if none are found, if that post is a passworded post then this could lead to a calendar that has no posts. Be careful to make any filter on this run as fast as possible or you'll slow down WP a lot, this means no new DB queries in the filter, no fetching data, no making http requests or loading files. There's also the danger of recursive loops.

Note that get_calendar caches by both month and year, so you need to flush caches to see updated output

Why Didn't posts_where work?

It didn't work because that filter is a part of WP_Query, which isn't used by get_calendar. I would advise against using this though as it breaks the post_password parameter of WP_Query and the functions that depend on it ( e.g get_posts or areas of the admin )

  • Still, problem is the same. I have one post in August, this post is hidden in loop, but still I see in calendar that month, but with 404...
    – D_P
    Commented Oct 5, 2020 at 12:27
  • hmmm I think you've caused some confusion, an archive is an archive of posts, but a calendar widget is not an archive, you might want to amend your question to use the appropriate terminology to avoid misunderstandings. Can you verify if you meant just the calendar widget, post archives, or both? And can you verify if you're talking about the calendar widget, the calendar block, or a calendar function that isn't from standard WP, such as from a plugin or theme?
    – Tom J Nowell
    Commented Oct 5, 2020 at 15:03
  • Also can you verify that you flushed all caches after making the change? Calendar output is cached
    – Tom J Nowell
    Commented Oct 5, 2020 at 15:05
  • I've updated my answer to account for both
    – Tom J Nowell
    Commented Oct 5, 2020 at 15:14
  • I'm talking about calendar widget, definitely. When I choose any month from calendar, archive file is displayed. If I have only one and protected post in August, and I choose August in calendar, and if protected posts are hidden in loop, then I get 404 error.
    – D_P
    Commented Oct 5, 2020 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.