独自検索ではsとpagedを入力値へつなぎます
固定ページに独自の検索フォームを置く場合は、検索語を文字列に限定してsanitize_text_field()で処理し、$args[‘s’]へ渡します。ページ番号はget_query_var( ‘paged’ )から取得して、$args[‘paged’]へつなぎます。
標準検索のsearch.phpには検索用のメインクエリがあります。新しいWP_Queryは重ねません。「資料だけ」「事例だけ」と対象を分けるときは、この記事の独自検索が向いています。
標準検索と独自検索のどちらを作るか決める
同じ「検索結果ページ」でも、標準検索を整える作業と、特定用途の検索ページを新設する作業では入口が違います。標準検索は通常の検索フォームから?s=検索語で開くサイト全体の検索です。独自検索は「資料検索」のような固定ページを新しく作り、対象の投稿タイプ、入力欄、URL、0件表示を用途に合わせて用意します。
| 作りたいページ | 使うクエリ | 主なファイル・URL |
|---|---|---|
| サイト全体の標準検索 | 既存のメインクエリ | search.php・?s=検索語 |
| 標準検索の対象を変更 | pre_get_postsでメインクエリを調整 | functions.phpまたは機能プラグイン |
| 資料・事例などの専用検索 | 新しいWP_Query | page-resource-search.php・固定ページURL |
この記事は3つ目の独自検索を作る例です。標準検索で別のWP_Queryを作ると、URLのページ番号、総件数、テーマの検索表示と二重管理になりやすいため避けます。
なお、sの標準検索対象はタイトル・抜粋・本文です。タイトルだけに絞りたい場合は、WordPress 6.2以降のsearch_columnsを使います。対象列を先に決めたい場合は、記事のタイトルだけを検索する方法で対応バージョンと指定値を確認してから、この記事の完成例へ戻ってください。
WP Query Builderで検索語・件数・ページ番号を入力する
公開中のWP Query Builderで「詳細設定(全項目)」を選びます。確認用のデータには「ブロックテーマ」を含む通常投稿を6件用意し、1ページ3件の2ページ目を取得しました。
| 入力欄 | 値 | 意味 |
|---|---|---|
| 投稿タイプ | post | 通常投稿だけを検索する |
| 公開状態 | publish | 公開済みだけにする |
| 取得件数 | 3 | 1ページ3件 |
| キーワード / s | ブロックテーマ | タイトル・抜粋・本文を検索する |
| ページ番号 / paged | 2 | 2ページ目を取得する |
| 並び方向 / order | DESC | 新しい日付から並べる |
| 並べ替えの基準 / orderby | date | 投稿日を基準にする |
自動高速化はOFFにしました。ページネーションで総ページ数を使うため、no_found_rows => trueを自動追加しない状態にしておく必要があります。

固定値で取得結果を確認したあと、検索語とページ番号をリクエスト値へ置き換えます。
次は、WP Query Builderがこの画面で生成したコードです。入力値、配列の順序、書式を変更せずに掲載しています。
引数や処理の一部分だけを示した例です。このまま単独で貼らず、テンプレート内のWP_Queryとループへ組み込んでください。
$args = array( 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => 3, 's' => 'ブロックテーマ', 'paged' => 2, 'order' => 'DESC', 'orderby' => 'date');sは検索語、posts_per_pageは1ページの件数、pagedは現在ページです。画面の2ページ目を固定値のまま貼ると、どのURLでも同じ結果になるため、完成例では動的な値へ置き換えます。
page-resource-search.phpへフォームと検索結果を実装する
クラシックテーマの子テーマへpage-resource-search.phpを作り、固定ページ「資料検索」に割り当てます。フォームはqという独自パラメーターを使い、空欄ではWP_Queryを実行しません。
<?php/* Template Name: 資料検索 */get_header(); $raw_search_term = isset( $_GET['q'] ) && is_string( $_GET['q'] ) ? wp_unslash( $_GET['q'] ) : '';$search_term = sanitize_text_field( $raw_search_term );$paged = max( 1, (int) get_query_var( 'paged' ) );?> <main id="primary"> <h1><?php echo esc_html( get_the_title() ); ?></h1> <form method="get" action="<?php echo esc_url( get_permalink() ); ?>" role="search"> <label for="resource-search">記事を検索</label> <input id="resource-search" name="q" type="search" value="<?php echo esc_attr( $search_term ); ?>" > <button type="submit">検索</button> </form> <?php if ( $search_term === '' ) : ?> <p>検索語を入力してください。</p> <?php else : ?> <?php $args = array( 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => 3, 's' => $search_term, 'paged' => $paged, 'order' => 'DESC', 'orderby' => 'date' ); $search_query = new WP_Query( $args ); ?> <h2>「<?php echo esc_html( $search_term ); ?>」の検索結果</h2> <?php if ( $search_query->have_posts() ) : ?> <p><?php echo esc_html( number_format_i18n( $search_query->found_posts ) ); ?>件見つかりました。</p> <ul> <?php while ( $search_query->have_posts() ) : ?> <?php $search_query->the_post(); ?> <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li> <?php endwhile; ?> </ul> <?php echo wp_kses_post( paginate_links( array( 'current' => $paged, 'total' => (int) $search_query->max_num_pages, ) ) ); ?> <?php else : ?> <p>一致する記事はありません。別の言葉でも検索してみてください。</p> <?php endif; ?> <?php wp_reset_postdata(); ?> <?php endif; ?></main> <?php get_footer(); ?>qは文字列の場合だけ受け付け、配列など想定外の値は未入力として扱います。検索語をHTMLへ戻す箇所ではesc_attr()またはesc_html()、URLではesc_url()を使っています。SQLを自作して検索語を埋め込む例ではありません。
空文字をsへ渡すと検索条件が付かず、対象投稿を広く取得します。フォームは常に表示し、その下で検索結果を出す前に、検索語が空かどうかを分けてください。検索結果は入力値、0件、複数ページで挙動が変わります。本番へ置く前にローカルまたはステージングで確認し、検証環境のバックアップとPHP条件も公式情報で確かめてください。
検索結果・0件・未入力を実データで確認する
分離したWordPress環境へ「ブロックテーマ」をタイトルに含む投稿を6件、含まない投稿を1件用意しました。投稿日降順で1ページ3件にすると、2ページ目はID100、101、102です。

同じ投稿データへs、posts_per_page、paged、日付降順を適用した結果です。
ページ番号だけでなく、found_postsが6、max_num_pagesが2であることも記録します。no_found_rows => trueを入れると総件数計算を省くため、このページネーション用途では使用していません。
0件と未入力を別の状態として表示する
存在しない検索語では0件案内を表示します。検索語が空の場合は、0件ではなく「検索語を入力してください」と案内し、WP_Query自体を実行しません。

未入力では検索を実行せず、一致しない検索語だけを0件として扱います。
タイトルだけを検索したい場合はsearch_columnsを検討する
WordPress 6.2以降では、search_columnsでpost_title、post_excerpt、post_contentから検索対象列を選べます。タイトルだけへ限定すると、本文にだけ検索語がある投稿は対象外になります。
バージョン条件と、タイトル・抜粋・本文のどこで一致したかを確認する手順は、次の記事で実データを使って説明しています。対象列を狭める必要がある場合だけ、ここで確認してから完成例へ追加してください。
検索対象の列を選ぶ記事のタイトルだけを検索する方法|WP_Queryのsearch_columnsWordPress 6.2以降のsearch_columnsと、旧バージョン向けの判断を整理する記事です。
記事を読む2ページ目が同じ・404になる場合はURLとpagedを確認する
固定ページのページネーションでは、パーマリンク構造やpagedの取得元によって2ページ目が404になる場合があります。まず生成コードのpagedを固定値から動的値へ変えたか、ページリンクが同じ固定ページを向いているかを確認します。
症状が「2ページ目も1ページ目と同じ」「2ページ目だけ404」の場合は、原因が検索条件ではなくページ番号やパーマリンクの書き換え設定にあります。次の記事の切り分け順に沿うと、paged、page、max_num_pagesを順番に確認できます。
ページ送りの原因を調べるWP_Queryでページネーションが動かない原因検索結果の中身ではなく、2ページ目の取得とURLを直すためのトラブルシュートです。
記事を読む標準のsearch.phpではメインクエリを重ねない
WordPress標準検索では、search.phpへ到達した時点で検索語とページ番号を持つメインクエリがあります。ここで同じ検索語のWP_Queryを新しく作ると、総件数やページ番号が二重になります。
標準検索の対象投稿タイプだけを変えたい場合は、pre_get_postsでis_main_query()とis_search()を確認して条件を変更します。独自ループとメインクエリのどちらを変えるべきか迷う場合は、次の記事で画面ごとの判断を先に確認してください。
メインクエリとの境界を確認するpre_get_postsとWP_Queryの違い標準検索やアーカイブを変更するときに、新しいWP_Queryを作るべきでない理由を整理します。
記事を読む検索語・件数・ページ番号を$argsへまとめる
固定値でコードを生成し、実データで検索結果と2ページ目を確認できます。完成時は入力された検索語と現在ページへ置き換えてください。
WP Query Builderの検索欄、ページ番号、Search Columnsをどの順で操作するかを画面付きで確認したい場合は、詳細設定の記事を先に読むと迷いません。生成コードをどのファイルへ置くかまで通して説明します。
詳細設定の操作を確認するWP Query Builderの詳細設定の使い方検索やページングを含む複数項目を入力し、実際の取得結果へつなぐための操作ガイドです。
記事を読む検索語・件数・ページ・0件を順番に確認する
検索結果の1件だけを見るのではなく、複数ページ、0件、未入力を同じデータで確認します。
独自検索ページの確認順
- 1対象投稿タイプと公開状態を決める
- 2固定した検索語で期待する投稿IDを確認する
- 3posts_per_pageより1件多い投稿を用意する
- 41ページ目と2ページ目で重複・欠落がないか確認する
- 5found_postsとmax_num_pagesを確認する
- 6一致0件の案内を確認する
- 7空欄でWP_Queryを実行しないことを確認する
- 8検索語を画面へ戻す箇所のエスケープを確認する
検索結果ページの最終チェック
- 標準検索か独自検索かを決めた
- 検索語を文字列に限定し、wp_unslashとsanitize_text_fieldで処理した
- 空検索語ではクエリを実行しない
- pagedを現在ページへつないだ
- 総ページ数を使うためno_found_rowsをtrueにしていない
- 1・2ページ目の取得IDを確認した
- 0件案内を用意した
- 出力時のエスケープとwp_reset_postdataを確認した
検索とページネーションの公式資料を確認する
検索条件はWP_Query、入力値の処理とページリンクはそれぞれの公式関数で確認します。標準検索を変える場合はpre_get_postsの注意点も読んでください。
検索結果ページのよくある質問
独自検索で混同しやすいURL、空欄、並び順、対象列について短く整理します。
この記事の検証情報
検証環境
- WordPress
- 7.1.4
- PHP
- 8.3.36
- テーマ
- wpq-media + DDEV
- 対象
- カスタム投稿 / taxonomy / meta_query
更新履歴
- 2026年10月5日 初回公開
この記事を活用する
あとで見返す・共有する
お気に入りに保存できます。役に立ったポイントは、いいねや共有で教えてください。


