【WordPress】記事一覧のループでログインユーザー以外にパスワード保護された投稿を非表示にする方法|is_singular()の除外必須

WordPressでパスワード保護した投稿は、通常の記事一覧にもタイトルが表示されてしまいます。この記事では、ログインしていない訪問者の記事一覧からだけパスワード保護された投稿を非表示にする方法を解説します。

この記事でわかること

  • pre_get_postshas_password で一覧から除外する方法
  • is_singular() の除外を忘れると起きる致命的な副作用
スポンサーリンク

functions.phpにコードを追加する

テーマの functions.php に以下のコードを追加します。

functions.php:一覧からのみパスワード保護投稿を除外
function exclude_protected_posts( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }

    // 一覧・アーカイブページのみが対象。個別ページ(is_singular)は除外しない
    if ( $query->is_singular() ) {
        return;
    }

    if ( ! is_user_logged_in() ) {
        $query->set( 'has_password', false );
    }
}
add_action( 'pre_get_posts', 'exclude_protected_posts' );
is_singular()を除外しないと記事自身が404になる
is_admin()is_main_query() のチェックだけでは不十分です。この2つだけの条件で has_password => false を適用すると、パスワード保護された投稿自身の個別ページに直接アクセスしたときのメインクエリにも適用されてしまいます。そうなると「対象の投稿」×「パスワードが無い」という条件が同時に成立せず、WordPressはその投稿を見つけられずに404を返します。本来、パスワード保護は「知っている人がパスワードを入力すれば読める」仕組みのはずが、これでは誰にとってもアクセス不能になってしまいます。is_singular() の場合は必ず処理をスキップし、個別ページの動作に影響しないようにしてください。

動作確認のポイント

  • ログインしていない状態で記事一覧・アーカイブページを開き、パスワード保護された投稿が表示されないこと
  • パスワード保護された投稿のURLに直接アクセスし、通常どおり「パスワードを入力してください」フォームが表示されること(ここが404になっていたらis_singular()の除外漏れです)
  • ログイン済みの状態では、一覧にもパスワード保護された投稿が表示されること

関連するパスワード保護・一覧除外の実装

よくある質問(FAQ)

Qパスワード保護された記事をループでログインユーザーのみ表示するには?
Ais_user_logged_in()でログイン確認し、post_password_required()でパスワード要求チェックをして表示を切り替えます。post_password_required($post)は、その投稿がパスワード保護されていてまだ認証されていない場合にtrueを返します。
Qpost_password_required()関数の使い方を教えてください
Aループ内でif ( ! post_password_required() ) { ... }のように使うと、パスワード未認証の投稿だけ表示・非表示を切り替えられます。pre_get_postsでクエリ自体から除外する今回の方法とは異なり、ループ内で個別に判定したい場合に使います。
Qパスワード保護記事の一覧でタイトルのみ表示してコンテンツは隠す方法は?
Apost_password_required()trueの場合は「パスワードで保護されています」などのメッセージを表示し、falseの場合はthe_content()で本文を表示します。get_the_excerpt()はWordPress側でパスワード保護時に自動的に保護メッセージを返します。

まとめ

  • 基本pre_get_postshas_password => false
  • 必須is_singular()の場合は処理をスキップする
  • 確認:保護記事自身のページで通常どおりパスワード入力フォームが出ること

「一覧からは隠すが、直接アクセスした人はパスワードで読める」という本来のパスワード保護の趣旨を壊さないよう、影響範囲を一覧・アーカイブページに限定してください。