【WordPress】一覧ページに特定の投稿を表示しない方法|カスタムフィールド+pre_get_postsで除外

WordPress

WordPressで特定の投稿だけをトップページ・一覧ページから隠したいことがあります。投稿に「一覧に表示しない」チェックボックスを用意し、pre_get_postsmeta_query でクエリ段階から除外すれば、ページネーションを崩さずに非表示にできます。カスタムフィールドは Custom Field Suite・ACF・標準機能のいずれでも実装できます。

この記事でわかること

  • 「一覧に表示しない」チェック用のカスタムフィールドを用意する
  • pre_get_postsmeta_query でクエリ段階から除外する(推奨)
  • ループ内で隠すとページネーションが崩れる理由
  • CFS・ACF・標準カスタムフィールドのいずれでも使える実装
スポンサーリンク

「表示しない」チェック用のカスタムフィールドを用意する

投稿に真偽(チェックボックス)のカスタムフィールドを追加します。キー名は英数字(例:hide_from_homeにしておくと、コードで扱いやすく安全です。ここでは Custom Field Suite(CFS)での作成例を示します。

CFSでなくてもOK
Custom Field Suite は手軽ですが更新が停滞しています。新規なら定番の ACF(Advanced Custom Fields) や、プラグイン無しの標準カスタムフィールドでも同じことができます。キー(hide_from_home)を合わせれば、後述のコードはそのまま使えます。

Custom Field Suiteでチェックボックスのフィールドを作成

管理画面の「Custom Field Suite」→「新規追加」で、フィールド名(ラベル)と名前(キー)を hide_from_home、タイプを「真/偽(簡易チェックボックス)」にして保存します。

投稿で「表示しない」をオンにする

作成したフィールドは投稿の編集画面に表示されます。一覧から隠したい投稿でチェックをオンにして更新します。

投稿編集画面のチェックボックス

クエリ段階で除外する(pre_get_posts・推奨)

functions.php に次のコードを追加し、チェックがオンの投稿をクエリ自体から除外します。NOT EXISTS の条件で、フィールド未設定の投稿(=従来の投稿)も表示されるようにします。

functions.php:pre_get_posts + meta_query で除外
function exclude_hidden_from_home($query) {
  if (is_admin() || !$query->is_main_query()) {
    return;
  }
  // トップページ・一覧で除外(必要に応じて条件を調整)
  if ($query->is_home() || $query->is_archive()) {
    $query->set('meta_query', array(
      'relation' => 'OR',
      array(
        'key'     => 'hide_from_home',
        'value'   => '1',
        'compare' => '!=',   // 1(チェックオン)以外
      ),
      array(
        'key'     => 'hide_from_home',
        'compare' => 'NOT EXISTS', // フィールド未設定の投稿も表示
      ),
    ));
  }
}
add_action('pre_get_posts', 'exclude_hidden_from_home');
NOT EXISTS を入れないと従来の投稿が消える
meta_querykey を条件にすると、そのフィールドを持たない投稿は除外されてしまいます。チェックを付けていない既存投稿を表示し続けるには、NOT EXISTS の条件を OR で必ず加えてください。カテゴリでの除外は記事一覧から特定のカテゴリーを除外する方法、カスタムフィールドが空の投稿を隠す例は特定のカスタムフィールドが空の投稿を一覧に非表示にする方法も参考になります。

(非推奨)ループ内で隠すとページネーションが崩れる

下のようにループの中で表示/非表示を分岐する書き方も見かけますが、注意が必要です。

PHP:ループ内で分岐(ページネーションが崩れる)
<?php while (have_posts()) : the_post(); ?>
  <?php if (get_post_meta(get_the_ID(), 'hide_from_home', true) !== '1') : ?>
    <h2><?php the_title(); ?></h2>
    <div><?php the_content(); ?></div>
  <?php endif; ?>
<?php endwhile; ?>
件数とページ送りがずれる
この方法は隠す投稿もクエリで取得済みで、posts_per_page の件数にカウントされます。「10件表示」でも非表示が3件あれば実際の表示は7件になり、ページごとの件数がバラバラ・ページ番号がずれる不具合が起きます。一覧から確実に除外したいなら、前章の pre_get_posts 方式を使ってください。

応用:逆に「特定の投稿だけ」表示する/期間で出し分ける

compare'=' にすれば、逆にチェックした投稿だけを表示できます。日付で自動的に表示・非表示を切り替えたい場合は指定期間だけ記事を表示・非表示にする方法、AND/OR/NOTを組み合わせた複雑な条件はWP_Queryで複雑な条件検索を実装する方法を参照してください。

よくある質問(FAQ)

QCustom Field Suiteはもう更新されていません。代替は?
AAdvanced Custom Fields(ACF)が最も人気で、無料版でも豊富なフィールドに対応します。ほかに Carbon Fields(開発者向け・無料)、Meta Box(基本無料)もあります。プラグイン無しの標準カスタムフィールドでもこの記事の方法は使えます。CFSからACFへはデータ形式が異なるため移行時は注意してください。
Qループ内で隠すのとpre_get_postsで除外するのは何が違いますか?
Aループ内で隠すとクエリは隠す投稿も取得済みのため、表示件数やページネーションがずれます。pre_get_postsmeta_query ならクエリ段階で除外するので、件数もページ送りも正しく保たれます。基本はこちらを使ってください。
Qチェックを付けていない既存の投稿が消えてしまいます。
Ameta_querykey 条件だけだと、フィールドを持たない投稿が除外されます。NOT EXISTS の条件を OR で加えると、未設定の投稿も表示され続けます。

まとめ

  • 準備:真偽のカスタムフィールド(キー hide_from_home)を用意(CFS/ACF/標準いずれでも可)
  • 除外pre_get_postsmeta_query!= 1NOT EXISTS
  • ループ内で隠さない:件数・ページネーションが崩れるため
  • 応用= で「特定投稿だけ表示」、日付条件で期間出し分け

クエリ段階で除外すれば、見た目もページ送りも自然なまま、投稿の表示・非表示をチェックひとつで管理できます。