2026年9月1日

2026年9月1日

WordPressのsearch.phpをカスタマイズする方法:検索結果ページと検索フォーム

WordPress の検索結果ページは、クラシックテーマでは search.php というテンプレートで表示されます。「検索キーワードと件数を見出しに出したい」「固定ページを検索結果から外したい」「検索フォームのデザインを変えたい」といった変更は、search.php・searchform.php・functions.php の3つで行います。

この記事のコードは、WordPress 6.9.4・PHP 8.3 のクラシックテーマで表示を確かめています(2026年10月時点)。ブロックテーマ(Twenty Twenty-Five など)では、検索結果は「外観 → エディター」で編集する検索結果用テンプレートが担当するため、ここで説明するファイルは使いません。

search.php が使われる条件

検索結果を表示するとき、WordPress は search.php を探し、無ければ index.php を使います(公式ドキュメント)。search.php が無くてもエラーにはならず、index.php で一覧が表示されるだけです。検索結果だけ見た目を変えたい場合に search.php を作ります。

配布テーマを変更する場合は、テーマの更新で上書きされないよう、子テーマに search.php を置きます。親テーマに search.php があればそれを子テーマにコピーして編集し、無ければ新しく作ります。子テーマの作り方は「WordPress子テーマの作り方」を参照してください。

cd /path/to/wordpress/wp-content/themes
cp parent-theme/search.php my-child-theme/search.php

ファイルはエディターで開いて編集します。echo などのコマンドでコードを1行ずつ追記する方法は、引用符の扱いで PHP が壊れやすく、HTML の順序も崩れるので避けてください。

手順1: search.php の基本形を書く

検索キーワードと件数を見出しに出し、結果を一覧にしてページ送りを付けた例です。

<?php
/**
 * 検索結果ページ(search.php)
 */
get_header();
?>
<main id="primary" class="site-main">
	<header class="page-header">
		<h1 class="page-title">
			<?php
			printf(
				'「%s」の検索結果',
				'<span class="search-query">' . esc_html( get_search_query( false ) ) . '</span>'
			);
			?>
		</h1>
		<?php if ( have_posts() ) : ?>
			<p class="search-count"><?php echo esc_html( number_format_i18n( $wp_query->found_posts ) ); ?>件見つかりました。</p>
		<?php endif; ?>
		<?php get_search_form(); ?>
	</header>

	<?php if ( have_posts() ) : ?>
		<ul class="search-results">
			<?php
			while ( have_posts() ) :
				the_post();
				?>
				<li <?php post_class( 'search-result' ); ?>>
					<h2 class="entry-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
					<p class="entry-meta">
						<?php echo esc_html( get_the_date() ); ?>
						<?php
						$type = get_post_type_object( get_post_type() );
						if ( $type ) {
							echo ' / ' . esc_html( $type->labels->singular_name );
						}
						?>
					</p>
					<?php the_excerpt(); ?>
				</li>
			<?php endwhile; ?>
		</ul>

		<?php
		the_posts_pagination(
			array(
				'mid_size'  => 1,
				'prev_text' => '前へ',
				'next_text' => '次へ',
			)
		);
		?>
	<?php else : ?>
		<p>キーワードに一致する記事は見つかりませんでした。別の言葉で検索してみてください。</p>
	<?php endif; ?>
</main>
<?php
get_sidebar();
get_footer();

ポイントは次のとおりです。

  • キーワードのエスケープ: 検索キーワードは訪問者が自由に入力できる値です。get_search_query( false ) でエスケープ前の値を取り、esc_html() を通してから表示しています。検証環境で <script> を含む語を検索しても、文字として表示されることを確認しました。
  • 件数: $wp_query->found_posts に、ページ送りを含めた全体の件数が入っています。number_format_i18n() で桁区切りを付けています。
  • 結果が0件のとき: have_posts() が偽になるので、else 側のメッセージを出します。検索フォームを見出しの下に置いておくと、そのまま検索し直せます。
  • ページ送り: the_posts_pagination() が「前へ」「次へ」とページ番号のリンクを出します。1ページの件数は「設定 → 表示設定」の「1ページに表示する最大投稿数」か、手順3の posts_per_page で決まります。

キーワードを空のまま検索した場合も search.php が使われ、すべての記事が一覧になります(検証環境で確認)。

手順2: 検索フォームを searchform.php で変える

get_search_form() は、テーマに searchform.php があればそれを読み込み、無ければ WordPress 標準のフォームを出します。検索結果ページだけでなく、get_search_form() を呼んでいる場所(クラシックの検索ウィジェットを含む)すべてに反映されます。ブロックエディターの「検索」ブロックは独自の HTML を出すため、searchform.php の影響を受けません。

<?php $mytheme_field_id = wp_unique_id( 'search-field-' ); ?>
<form role="search" method="get" class="search-form" action="<?php echo esc_url( home_url( '/' ) ); ?>">
	<label for="<?php echo esc_attr( $mytheme_field_id ); ?>" class="screen-reader-text">サイト内検索</label>
	<input type="search" id="<?php echo esc_attr( $mytheme_field_id ); ?>" class="search-field" name="s"
		value="<?php echo get_search_query(); ?>" placeholder="キーワードを入力">
	<button type="submit" class="search-submit">検索</button>
</form>
  • 入力欄の name は s にします。WordPress は ?s=キーワード を検索として扱います。
  • action はサイトのトップ(home_url( '/' ))です。
  • get_search_query() は引数を省くとエスケープ済みの値を返すので、value にそのまま入れられます。
  • 1ページにフォームが2つ以上あっても id が重ならないよう、wp_unique_id() で番号付きの ID を作っています。
  • screen-reader-text は多くのテーマで「画面には出さず読み上げには使う」ためのクラスです。テーマに無い場合は CSS で定義するか、ラベルを表示してください。

手順3: 検索対象を絞る(pre_get_posts)

「固定ページを検索結果に出したくない」「特定のカテゴリーだけを検索したい」といった変更は、search.php の中で query_posts() を使って取り直すのではなく、子テーマの functions.php で pre_get_posts フックを使います。query_posts() はメインクエリを置き換えるため、ページ送りや件数がずれる原因になり、公式リファレンスでも使わないよう案内されています。

<?php
/**
 * 検索結果を「投稿」だけにし、1ページ10件にする。
 */
add_action( 'pre_get_posts', function ( $query ) {
	if ( is_admin() || ! $query->is_main_query() || ! $query->is_search() ) {
		return;
	}
	$query->set( 'post_type', array( 'post' ) );
	$query->set( 'posts_per_page', 10 );
} );
  • is_admin() で管理画面の検索を、is_main_query() でサイドバーなどのサブクエリを対象外にしています。この2つが無いと、管理画面の投稿一覧の検索まで変わってしまいます。
  • 検証環境では、タイトルに検索語を含む固定ページが結果から外れることを確認しました。

ほかの絞り込みの例です(上のコードの $query->set() の行を差し替えます)。

やりたいこと 書き方
カテゴリー ID 5 の記事だけ検索 $query->set( 'cat', 5 );
投稿とカスタム投稿タイプ product を検索 $query->set( 'post_type', array( 'post', 'product' ) );
タイトルだけを検索(WordPress 6.2 以降) $query->set( 'search_columns', array( 'post_title' ) );

WordPress 標準の検索は、タイトル・抜粋・本文を対象に部分一致で探します。カスタムフィールドの値は対象になりません。pre_get_posts の使い方は「pre_get_postsでクエリを変更する方法」で詳しく説明しています。

手順4: 見た目を整える

手順1・2で付けたクラスに、子テーマの style.css でスタイルを当てます。

.search-query {
	color: #c00;
}

.search-results {
	list-style: none;
	padding: 0;
}

.search-result {
	border-bottom: 1px solid #ddd;
	padding: 1em 0;
}

.search-form {
	display: flex;
	gap: 0.5em;
	margin: 1em 0;
}

<body> には検索結果ページで search と、結果があれば search-results、無ければ search-no-results のクラスが付きます(body_class() が出力)。検索結果ページだけ見た目を変えたいときは、.search .site-main のように指定できます。

運用上の注意

  • 表示速度: 標準の検索は投稿数が多いと遅くなることがあります。記事数が多いサイトや、日本語の検索精度を上げたい場合は「WordPressで日本語の全文検索を実装する」のような方法も検討してください。
  • 検索結果ページのインデックス: 検索結果ページは中身が検索語ごとに変わるため、検索エンジンに登録させない設定にするサイトが多くあります。設定方法は「WordPressの検索結果ページをnoindexにする方法」を参照してください。
  • 変更が反映されないとき: 編集したのが有効なテーマ(子テーマ)のファイルか、キャッシュ系プラグインのキャッシュが残っていないかを確認します。

まとめ

  • 検索結果は search.php、無ければ index.php で表示されます。配布テーマを変える場合は子テーマに置きます。
  • 検索キーワードは esc_html( get_search_query( false ) ) のようにエスケープして表示し、件数は $wp_query->found_posts で取ります。
  • 検索フォームは searchform.php で差し替えられます。入力欄の name は s です。
  • 検索対象の絞り込みは query_posts() ではなく、functions.php の pre_get_posts で行います。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲