WordPressの標準検索機能は、サイトの規模が大きくなったり、カスタム投稿やカスタムフィールドを使い始めるとすぐに限界が来てしまいます。プラグインを導入する手もありますが、「こんな細かい要件、どのプラグインでも対応できない」「プラグインが重くてサイトの表示速度が遅くなる」といった壁にもぶつかります。
「だったら自分で作ればいいんじゃない?」–そう、WordPressの検索機能はPHPやHTML/CSSを使って自作することで、柔軟性・高速化・UX改善など、プラグイン依存では実現できない“あなただけの検索”を実現できます。
この記事では、WordPressの検索機能を自作したい方のために、初心者にも分かりやすく、具体的な手順やコード例を交えながら徹底解説します。

WordPressの検索機能、自作すべき理由とは?
「検索機能」というと一見シンプルに思えますが、実はサイト品質を左右する重要な要素なのをご存知でしょうか?特にコンテンツが増えてくると、ユーザーが目的の情報にたどり着けるかどうかは検索機能の出来にかかっています。今回は多くのサイト運営者が見落としがちな「WordPress検索機能の自作」について、その理由とメリットを掘り下げていきましょう。
WordPress標準の検索機能の限界
WordPressには標準で検索機能が備わっていますが、残念ながらその機能は非常に基本的なものにとどまります。具体的には以下のような限界があります。
まず第一に、検索精度の低さが挙げられます。WordPress標準の検索は基本的に単純なキーワードマッチングのみを行い、関連性や重要度に基づいたランキングはほとんど考慮されません。例えば「WordPress 初心者 設定」と検索した場合、これらの単語がどこかに含まれているという理由だけでヒットし、必ずしも初心者向けの設定記事が上位に表示されるとは限らないのです。
次に、複数キーワードの取り扱いが不十分です。標準検索では複数キーワードを入力した場合、基本的にOR検索(いずれかのキーワードを含む)として処理されます。これでは「WordPress プラグイン おすすめ」で検索しても、「WordPress」か「プラグイン」か「おすすめ」のいずれかを含むすべての記事がヒットしてしまい、ユーザーが求める「WordPressのおすすめプラグイン」に関する記事を適切に絞り込めないケースが多発します。
さらに、カスタムフィールドやカスタム投稿タイプへの対応が不十分という問題もあります。多くのサイトでは、通常の投稿内容だけでなく、カスタムフィールドに重要な情報を格納していることがあります。例えば商品の価格や仕様、レビュー評価などです。標準検索ではこうしたカスタムフィールドを検索対象にすることができず、大切な情報が埋もれてしまいます。
プラグインで実現できない要件とは?
「検索機能を強化したいなら、プラグインを使えば良いのでは?」と思われるかもしれません。確かに、Search & FilterやRelevanssiなど優れた検索プラグインは存在します。しかし、プラグインにも次のような限界があります。


カスタマイズ性の制約は大きな問題です。プラグインは多くのユーザーが使うことを想定して作られているため、オプションが多数用意されていることも少なくありません。しかし、あなたのサイト特有の要件に対応できないことも少なくないのです。例えば「特定のカスタムフィールドの値を重視して検索結果をソートしたい」「会員ランクによって検索結果を変えたい」といった独自要件に対応するのは困難です。
パフォーマンスへの影響も見過ごせません。検索プラグインは便利な反面、余分なクエリを発行したり、データベースに負荷をかけたりする可能性があります。実際に人気の検索プラグインを導入後、サイト全体の表示速度が10~15%程度低下したという事例も少なくありません。特に記事数が1,000を超えるようなサイトでは、この影響が顕著になることがあります。
他のプラグインとの競合も現実的な問題です。WordPress環境では複数のプラグインを組み合わせて使うことが一般的ですが、それぞれが独自にデータベースやフックを操作するため、予期せぬ競合が発生することがあります。特に検索機能はサイト全体に関わる基本的な機能なので、他のプラグインと干渉しやすいのです。
さらに、アップデートへの依存もリスクとなります。プラグインはWordPressのアップデートに対応する必要があり、場合によっては機能が突然動かなくなることもあります。実際、あるECサイトでは重要なセール期間中に検索プラグインがWordPressのアップデートと競合し、検索機能が停止するという事態が発生したケースもあります。
自作することで得られるメリット(柔軟性・高速化・UX改善)
ここまでの制約を考えると、検索機能を自作することのメリットが見えてきます。自作する最大の魅力は以下の3点です。
完全なカスタマイズ性が最大のメリットでしょう。自作することで、あなたのサイトやユーザーのニーズに100%マッチした検索機能を実現できます。例えば、料理レシピサイトなら「調理時間30分以内」「使用食材が5つ以下」といった条件で絞り込み検索を可能にしたり、技術ブログなら「初心者向け記事を優先表示」「公開後1年以内の新しい情報を上位表示」といった独自ロジックを組み込めます。
// 例:調理時間でフィルタリングする検索クエリの例
function custom_search_by_cooking_time( $query ) {
if ( $query->is_search() && !is_admin() ) {
// 30分以内の調理時間の記事を検索
if ( isset( $_GET['cooking_time'] ) && $_GET['cooking_time'] == 'under30' ) {
$meta_query = array(
array(
'key' => 'cooking_time',
'value' => 30,
'compare' => '<=',
'type' => 'NUMERIC',
)
);
$query->set( 'meta_query', $meta_query );
}
}
return $query;
}
add_action( 'pre_get_posts', 'custom_search_by_cooking_time' );
パフォーマンスの最適化も重要なメリットです。検索機能を自作することで、必要最小限のクエリだけを発行し、不要な処理を省くことができます。サイトの表示速度はSEOにも直結する重要な要素ですから、この改善効果は見逃せません。
独自UX(ユーザー体験)の実現も可能になります。例えば、ユーザーが検索キーワードを入力している途中でリアルタイムに候補を表示するライブサーチや、検索履歴に基づくパーソナライズされた提案など、ユーザーがストレスなく目的のコンテンツにたどり着ける工夫を施すことができます。自作であれば、JavaScriptとAjaxを活用して、ページ遷移なしでスムーズに検索結果を表示するといった高度なUIも実現可能です。
このように、WordPress検索機能の自作は一見ハードルが高そうに思えますが、基本的な仕組みを理解し、段階的に実装していけば、サイトの価値を大きく高める強力な武器となります。次章では、具体的な実装方法について掘り下げていきましょう。

WordPress検索機能の基本構造と仕組み
WordPress検索機能を自作するにあたり、まずはその基本構造と仕組みを理解することが重要です。この章では、WordPressの検索機能がどのように動作しているのかを、できるだけわかりやすく解説していきます。
サイト内検索の基本的な流れ
WordPressでの検索は、一見シンプルに見えて実はいくつかのステップを踏んで実行されています。ユーザーが検索ボックスにキーワードを入力してから、結果が表示されるまでの流れを見ていきましょう。
まず、ユーザーが検索フォーム(多くの場合はサイドバーやヘッダーに設置されています)にキーワードを入力し、検索ボタンをクリックします。すると、次のような流れで処理が進みます。
- 検索クエリの送信: 入力されたキーワードは
?s=キーワード
というGETパラメータとしてURLに含まれ、サーバーに送信されます。 - WordPress コアによる解析: WordPressは
s
パラメータを検出すると、これを検索リクエストとして認識します。 - データベースクエリの構築: WordPressはSQL(データベース問い合わせ言語)を使って、投稿テーブル(wp_posts)などに対して検索条件を含むクエリを構築します。
- 検索結果の取得: データベースから条件に合致する投稿が取得されます。
- テンプレートの決定: 取得した結果を表示するためのテンプレートとして
search.php
が選択されます。 - 検索結果の表示:
search.php
に基づいて検索結果が整形され、ユーザーに表示されます。
この一連の流れを理解することが、検索機能をカスタマイズする基本となります。特に重要なのは、3番目のデータベースクエリ構築のステップです。ここでは標準では主に投稿のタイトルと本文を対象に検索が行われています。

searchform.php と search.php の役割
WordPressの検索機能には、主に2つの重要なテンプレートファイルが関わっています。searchform.php
とsearch.php
です。これらはいわば検索機能の入口と出口にあたる部分で、カスタマイズする際の重要なポイントになります。
searchform.phpは検索フォームの見た目とふるまいを決定するテンプレートです。テーマに同名のファイルがなければ、WordPressのデフォルトフォームが使用されます。基本的なsearchform.phpは次のようなHTMLで構成されています:
<form role="search" method="get" id="searchform" class="searchform" action="<?php echo esc_url( home_url( '/' ) ); ?>">
<div>
<label class="screen-reader-text" for="s"><?php _x( 'Search for:', 'label' ); ?></label>
<input type="text" value="<?php echo get_search_query(); ?>" name="s" id="s" />
<input type="submit" id="searchsubmit" value="<?php echo esc_attr_x( 'Search', 'submit button' ); ?>" />
</div>
</form>
この中で特に重要なのは以下の部分です:
action
属性:検索フォームの送信先URLを指定(通常はサイトのホームURL)name="s"
:検索キーワードのパラメータ名(これがWordPressの検索を認識するための鍵)value="<?php echo get_search_query(); ?>"
:現在の検索キーワードを取得して表示
これをカスタマイズすることで、例えば検索対象を絞り込むための追加フィールド(カテゴリー選択など)を追加したり、デザインを変更したりできます。
対してsearch.phpは検索結果ページの表示を担当するテンプレートファイルです。WordPressのテンプレート階層に従って、テーマ内にsearch.phpがなければ、代わりにindex.phpが使用されます。典型的なsearch.phpファイルの構造は次のようになっています:
<?php get_header(); ?>
<section id="primary" class="content-area">
<main id="main" class="site-main">
<?php if ( have_posts() ) : ?>
<header class="page-header">
<h1 class="page-title">
<?php
/* translators: %s: search query. */
printf( esc_html__( 'Search Results for: %s', 'theme-textdomain' ), '<span>' . get_search_query() . '</span>' );
?>
</h1>
</header><!-- .page-header -->
<?php
/* Start the Loop */
while ( have_posts() ) :
the_post();
get_template_part( 'template-parts/content', 'search' );
endwhile;
the_posts_navigation();
else :
get_template_part( 'template-parts/content', 'none' );
endif;
?>
</main><!-- #main -->
</section><!-- #primary -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
search.phpでは主に以下のカスタマイズが可能です:
- 検索結果のヘッダー(タイトルなど)
- 検索結果の表示形式(リスト、グリッドなど)
- 各検索結果アイテムの表示内容(抜粋、メタ情報など)
- 結果が見つからない場合のメッセージ
- ページネーションのスタイルと位置
WP_Queryの概要と検索における活用法
WordPress検索機能の中核を担うのが「WP_Query」というクラスです。これは投稿を取得するための強力なクラスで、検索だけでなく、アーカイブやカスタムページなど、さまざまな場面で使用されています。検索機能をカスタマイズするには、このWP_Queryの使い方を理解することが不可欠です。
WP_Queryは非常に柔軟性が高く、多くのパラメータを使って検索条件を細かく指定できます。主な検索関連パラメータには以下のようなものがあります:
s
:検索キーワードpost_type
:検索対象の投稿タイプ(投稿、固定ページ、カスタム投稿タイプなど)category_name
:特定のカテゴリー内での検索tag
:特定のタグが付いた投稿での検索meta_query
:カスタムフィールドを条件に加えた検索date_query
:日付を条件に加えた検索posts_per_page
:1ページあたりの表示件数
例えば、「WordPress」というキーワードで、過去3ヶ月以内に公開された「チュートリアル」カテゴリーの投稿だけを検索したい場合、次のようなWP_Queryを使用できます:
<?php
// 現在の3ヶ月前の日付を取得
$three_months_ago = date('Y-m-d', strtotime('-3 months'));
// 検索クエリの作成
$search_query = new WP_Query( array(
's' => 'WordPress', // 検索キーワード
'category_name' => 'tutorial', // カテゴリー
'date_query' => array(
array(
'after' => $three_months_ago, // 3ヶ月以内の投稿
'inclusive' => true,
),
),
'posts_per_page' => 10, // 10件表示
) );
// 検索結果の表示
if ( $search_query->have_posts() ) :
while ( $search_query->have_posts() ) :
$search_query->the_post();
// 投稿の表示コード
the_title( '<h2>', '</h2>' );
the_excerpt();
endwhile;
wp_reset_postdata();
else :
echo '該当する投稿はありませんでした。';
endif;
?>
このように、WP_Queryを使うことで非常に柔軟な検索機能を実装できます。
WordPress検索機能のカスタマイズでより高度な制御を行いたい場合、以下のフックを活用することも重要です:
- pre_get_posts:WP_Queryが実行される前に、クエリパラメータを変更できるフック
- posts_search:検索用のSQL WHERE句を変更できるフック
- posts_clauses:クエリの全ての部分(SELECT, FROM, WHERE など)を変更できるフック
- posts_results:データベースから返された結果を変更できるフック
特にpre_get_posts
は検索カスタマイズの中で最も頻繁に使用されるフックです。これを使うと、メインクエリ(WordPressがページ表示時に自動的に実行するクエリ)を修正できるため、search.phpなどのテンプレートを直接編集せずに検索ロジックを変更できます。
function custom_search_filter( $query ) {
if ( !is_admin() && $query->is_main_query() && $query->is_search() ) {
// 検索を投稿と固定ページだけに限定
$query->set( 'post_type', array( 'post', 'page' ) );
// 1ページあたりの表示件数を20に設定
$query->set( 'posts_per_page', 20 );
// 公開日の新しい順に並べ替え
$query->set( 'orderby', 'date' );
$query->set( 'order', 'DESC' );
}
return $query;
}
add_action( 'pre_get_posts', 'custom_search_filter' );
このように、WordPress検索機能の基本構造を理解し、WP_Queryやフックを適切に使うことで、サイトに最適化された検索機能を構築する基盤が整います。次のセクションでは、これらの知識を応用して、カスタムフィールドやタクソノミーを検索対象に含める方法を詳しく見ていきましょう。

検索対象の絞り込み:カスタムフィールド・タクソノミー対応
WordPress の標準検索では、主に投稿タイトルと本文が検索対象となります。しかし、実際のサイト運営では、カスタムフィールドや独自のタクソノミーにも重要な情報が格納されていることが多いですよね。例えば、商品の価格、スペック情報、特典内容などは、カスタムフィールドに保存されていることがほとんどです。このセクションでは、これらの情報も含めた高度な検索機能の実装方法を解説します。
カスタムフィールド(例: ACF)で絞り込む検索の実装方法
カスタムフィールドは、投稿に追加の情報を付与するための強力な機能です。特に Advanced Custom Fields (ACF) のようなプラグインを使用している方も多いでしょう。カスタムフィールドの値を検索対象に含めるには、主に次の2つのアプローチがあります。
1. meta_query を使用する方法
WP_Query
の meta_query
パラメータを使うと、特定のカスタムフィールド値を持つ投稿に絞り込むことができます。例えば、「価格が5000円以下の商品」を検索結果に表示したい場合は以下のようになります:
function search_with_price_filter( $query ) {
// メインクエリの検索時のみ処理
if ( !is_admin() && $query->is_main_query() && $query->is_search() ) {
// URLから価格フィルターの値を取得(例:?price_max=5000)
$price_max = isset( $_GET['price_max'] ) ? intval( $_GET['price_max'] ) : 0;
if ( $price_max > 0 ) {
// meta_queryを設定
$meta_query = array(
array(
'key' => 'product_price', // カスタムフィールドのキー
'value' => $price_max,
'type' => 'NUMERIC',
'compare' => '<='
)
);
// 既存のmeta_queryとマージ
$existing_meta_query = $query->get( 'meta_query' );
if ( !empty( $existing_meta_query ) ) {
$meta_query = array_merge( $existing_meta_query, $meta_query );
}
$query->set( 'meta_query', $meta_query );
}
}
return $query;
}
add_action( 'pre_get_posts', 'search_with_price_filter' );
この方法は、カスタムフィールドの値で「絞り込む」ことはできますが、キーワード検索と組み合わせる場合は注意が必要です。上記の例では、検索キーワードにマッチする投稿の中から、さらに価格条件に合うものだけを表示します。
2. posts_search フィルターを使用する方法
もう一つの方法は、SQLのWHERE句を直接操作する posts_search
フィルターを使用する方法です。こちらはキーワードによる検索対象にカスタムフィールドを含めることができます:
function include_custom_fields_in_search( $search, $wp_query ) {
global $wpdb;
if ( empty( $search ) || !$wp_query->is_search ) {
return $search;
}
$keywords = explode( ' ', $wp_query->query_vars['s'] );
$search = '';
foreach ( $keywords as $keyword ) {
$keyword = esc_sql( $wpdb->esc_like( $keyword ) );
if ( !empty( $search ) ) {
$search .= " AND ";
}
$search .= "(
{$wpdb->posts}.post_title LIKE '%{$keyword}%'
OR {$wpdb->posts}.post_content LIKE '%{$keyword}%'
OR EXISTS (
SELECT * FROM {$wpdb->postmeta}
WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id
AND (
({$wpdb->postmeta}.meta_key = 'product_features' AND {$wpdb->postmeta}.meta_value LIKE '%{$keyword}%')
OR ({$wpdb->postmeta}.meta_key = 'product_description' AND {$wpdb->postmeta}.meta_value LIKE '%{$keyword}%')
/* 他のカスタムフィールドを追加 */
)
)
)";
}
if ( !empty( $search ) ) {
$search = " AND ({$search})";
}
return $search;
}
add_filter( 'posts_search', 'include_custom_fields_in_search', 10, 2 );
この方法では、指定したカスタムフィールド(ここでは product_features
と product_description
)の内容も検索対象となります。例えば、ACFのテキストエリアで保存した詳細な商品説明も検索できるようになります。
ただし、この方法には注意点があります。大量のカスタムフィールドに対して検索を行うと、データベースへの負荷が高くなり、検索速度が低下する可能性があります。そのため、検索対象とするカスタムフィールドは必要最小限に絞ることをおすすめします。
また、ACFの場合は、フィールドの種類によって格納されるデータ形式が異なります。例えば、リピーターフィールドやフレキシブルコンテンツフィールドはシリアライズされたデータとして保存されるため、そのままでは効率的に検索できません。このような場合は、追加のインデックステーブルを作成するなどの工夫が必要になることもあります。
タクソノミー(カテゴリー・タグ)によるフィルター追加方法
次に、カテゴリーやタグなどのタクソノミーを使って検索結果をフィルタリングする方法を見ていきましょう。WordPressの標準検索でも、検索結果のリンクにカテゴリーを追加して絞り込みできますが(例:/?s=keyword&cat=5
)、より柔軟な方法を紹介します。
1. 検索フォームにタクソノミーフィルターを追加
まず、検索フォームに選択肢を追加してみましょう:
<form role="search" method="get" class="search-form" action="<?php echo esc_url( home_url( '/' ) ); ?>">
<div class="search-wrapper">
<input type="search" class="search-input" placeholder="キーワードを入力" value="<?php echo get_search_query(); ?>" name="s" />
<div class="taxonomy-filter">
<select name="post_category">
<option value="">カテゴリーを選択</option>
<?php
$categories = get_categories( array(
'hide_empty' => true,
'orderby' => 'name',
'order' => 'ASC'
) );
foreach ( $categories as $cat ) {
echo '<option value="' . $cat->slug . '"'
. ( isset( $_GET['post_category'] ) && $_GET['post_category'] === $cat->slug ? ' selected' : '' )
. '>' . $cat->name . '</option>';
}
?>
</select>
<!-- タグのフィルターもあれば追加 -->
<select name="post_tag">
<option value="">タグを選択</option>
<?php
$tags = get_tags( array(
'hide_empty' => true,
'orderby' => 'name',
'order' => 'ASC'
) );
foreach ( $tags as $tag ) {
echo '<option value="' . $tag->slug . '"'
. ( isset( $_GET['post_tag'] ) && $_GET['post_tag'] === $tag->slug ? ' selected' : '' )
. '>' . $tag->name . '</option>';
}
?>
</select>
</div>
<button type="submit" class="search-submit">検索</button>
</div>
</form>
この検索フォームでは、カテゴリーとタグをドロップダウンリストで選択できます。選択した項目は、それぞれ post_category
と post_tag
というパラメータ名でリクエストに含まれます。
2. pre_get_posts でタクソノミー条件を追加
次に、検索クエリにタクソノミー条件を追加します:
function add_taxonomy_filters_to_search( $query ) {
if ( !is_admin() && $query->is_main_query() && $query->is_search() ) {
// カテゴリーフィルター
if ( isset( $_GET['post_category'] ) && !empty( $_GET['post_category'] ) ) {
$tax_query = array(
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => sanitize_text_field( $_GET['post_category'] ),
)
);
// 既存のtax_queryがあればマージ
$existing_tax_query = $query->get( 'tax_query' );
if ( !empty( $existing_tax_query ) ) {
$tax_query = array_merge( $existing_tax_query, $tax_query );
$tax_query['relation'] = 'AND';
}
$query->set( 'tax_query', $tax_query );
}
// タグフィルター
if ( isset( $_GET['post_tag'] ) && !empty( $_GET['post_tag'] ) ) {
$tax_query = $query->get( 'tax_query', array() );
$tax_query[] = array(
'taxonomy' => 'post_tag',
'field' => 'slug',
'terms' => sanitize_text_field( $_GET['post_tag'] ),
);
if ( count( $tax_query ) > 1 && !isset( $tax_query['relation'] ) ) {
$tax_query['relation'] = 'AND';
}
$query->set( 'tax_query', $tax_query );
}
}
return $query;
}
add_action( 'pre_get_posts', 'add_taxonomy_filters_to_search' );
このコードにより、検索時にカテゴリーやタグによるフィルタリングが可能になります。例えば、「WordPress」というキーワードで検索し、「チュートリアル」カテゴリーに限定したい場合は、/?s=WordPress&post_category=tutorial
というURLでアクセスできます。
3. カスタムタクソノミーへの対応
WordPress標準のカテゴリーやタグだけでなく、カスタムタクソノミーにも対応させるには、上記のコードを少し修正するだけです:
// 検索フォームにカスタムタクソノミーのドロップダウンを追加
$locations = get_terms( array(
'taxonomy' => 'location', // カスタムタクソノミー名
'hide_empty' => true,
) );
if ( !empty( $locations ) && !is_wp_error( $locations ) ) {
echo '<select name="location">';
echo '<option value="">場所を選択</option>';
foreach ( $locations as $location ) {
echo '<option value="' . $location->slug . '"'
. ( isset( $_GET['location'] ) && $_GET['location'] === $location->slug ? ' selected' : '' )
. '>' . $location->name . '</option>';
}
echo '</select>';
}
// pre_get_posts内でカスタムタクソノミーの条件を追加
if ( isset( $_GET['location'] ) && !empty( $_GET['location'] ) ) {
$tax_query = $query->get( 'tax_query', array() );
$tax_query[] = array(
'taxonomy' => 'location',
'field' => 'slug',
'terms' => sanitize_text_field( $_GET['location'] ),
);
if ( count( $tax_query ) > 1 && !isset( $tax_query['relation'] ) ) {
$tax_query['relation'] = 'AND';
}
$query->set( 'tax_query', $tax_query );
}
このように、カスタムタクソノミーも同様の方法で検索条件に追加できます。
複数条件(AND/OR検索)のクエリ構築方法と注意点
検索の高度化において、複数の条件を組み合わせることは非常に重要です。例えば「カテゴリーAに属し、カスタムフィールドBの値がCで、キーワードDを含む投稿」というような複雑な条件を設定したいケースも少なくありません。
1. tax_query と meta_query の関係設定
タクソノミーとカスタムフィールドの条件を組み合わせる場合、それぞれに tax_query
と meta_query
を使用し、それぞれの内部で relation
パラメータを設定できます:
$args = array(
's' => 'WordPress', // 検索キーワード
'tax_query' => array(
'relation' => 'AND', // すべてのタクソノミー条件を満たす(AND検索)
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => 'tutorial',
),
array(
'taxonomy' => 'post_tag',
'field' => 'slug',
'terms' => array( 'beginner', 'intermediate' ),
'operator' => 'IN', // いずれかのタグを持つ(OR検索)
),
),
'meta_query' => array(
'relation' => 'OR', // いずれかのメタ条件を満たす(OR検索)
array(
'key' => 'difficulty_level',
'value' => 'beginner',
'compare' => '=',
),
array(
'key' => 'reading_time',
'value' => 15,
'type' => 'NUMERIC',
'compare' => '<=', // 15分以内で読める記事
),
),
);
$query = new WP_Query( $args );
この例では、「WordPress」というキーワードで検索し、「tutorial」カテゴリーに属し、「beginner」または「intermediate」タグのいずれかを持ち、さらに難易度が「beginner」または読む時間が15分以内の投稿を検索します。
2. パフォーマンスへの影響と最適化
複数の条件を組み合わせると、データベースクエリが複雑になり、パフォーマンスに影響を与える可能性があります。特に大量の投稿がある場合、検索速度が大幅に低下する恐れがあります。最適化のためのポイントをいくつか紹介します:
必要最小限の条件に絞る:本当に必要な条件だけを使用し、冗長な条件は避けましょう。
インデックスの活用:カスタムフィールドで頻繁に検索する場合、そのフィールドにインデックスを追加すると効果的です。例えば、次のようなSQLをphpMyAdminなどで実行できます:
ALTER TABLE wp_postmeta ADD INDEX meta_key_value (meta_key, meta_value(191));
キャッシュの活用:同じ検索条件が頻繁に使用される場合、結果をキャッシュすることでパフォーマンスを向上させられます:
function cached_custom_search( $keywords, $category = '', $tag = '' ) {
// キャッシュキーを生成
$cache_key = 'search_' . md5( $keywords . $category . $tag );
// キャッシュから取得を試みる
$results = wp_cache_get( $cache_key, 'search_results' );
if ( false === $results ) {
// キャッシュに存在しない場合は検索を実行
$args = array(
's' => $keywords,
// その他の条件
);
if ( !empty( $category ) ) {
$args['category_name'] = $category;
}
if ( !empty( $tag ) ) {
$args['tag'] = $tag;
}
$query = new WP_Query( $args );
$results = $query->posts;
// 結果をキャッシュに保存(1時間有効)
wp_cache_set( $cache_key, $results, 'search_results', HOUR_IN_SECONDS );
}
return $results;
}
3. 複合条件検索の注意点
複数条件の検索を実装する際の主な注意点は以下の通りです:
AND/OR条件の明確化:各条件間の関係(AND/OR)を明確にし、意図した検索結果が得られるようにしましょう。
ユーザーにわかりやすい UI の提供:複雑な条件設定が可能な場合、ユーザーが混乱しないよう、検索フォームのデザインと説明を工夫しましょう。
検索結果のリンク生成:検索結果ページでさらにフィルタリングできるよう、現在の検索条件を維持したリンクを生成することも重要です:
function build_search_url( $new_params = array() ) {
// 現在のクエリパラメータを取得
$current_params = $_GET;
// 新しいパラメータを追加/上書き
foreach ( $new_params as $key => $value ) {
$current_params[$key] = $value;
}
// 空のパラメータを削除
foreach ( $current_params as $key => $value ) {
if ( empty( $value ) && $value !== '0' ) {
unset( $current_params[$key] );
}
}
// URLを生成
return esc_url( add_query_arg( $current_params, home_url( '/' ) ) );
}
このようにして、カスタムフィールドやタクソノミーを検索対象に含め、複数条件で絞り込むことで、より精度の高い検索機能を実現できます。次のセクションでは、複数キーワードによる検索の実装方法を詳しく見ていきましょう。

複数キーワード検索の実装(AND/OR対応)
WordPress標準の検索機能は、基本的な検索ニーズには対応していますが、複数のキーワードを指定した場合や、より高度な検索条件を設定したい場合には限界があります。このセクションでは、複数キーワード検索を自分で実装する方法について解説します。
s パラメータの制限と改善方法
WordPressの標準検索では、URLのs
パラメータに検索キーワードを指定します。例えば、「WordPress プラグイン」と検索すると、URLは以下のようになります。
https://example.com/?s=WordPress+プラグイン
しかし、この方法には以下のような制限があります:
- OR検索がデフォルト: 標準では「WordPress」か「プラグイン」のどちらかを含む記事がヒットします(OR検索)
- 複雑な検索条件の設定が困難: AND検索やフレーズ検索などの設定が標準機能では難しい
- 全文検索エンジンの機能不足: MySQLの全文検索機能はデフォルトでは十分に活用されていない
この制限を改善するには、検索クエリの処理方法をカスタマイズする必要があります。
pre_get_posts フィルタによる検索クエリのカスタマイズ
複数キーワード検索をカスタマイズするための主要な手段は、pre_get_posts
フィルタフックです。このフックを使うと、WordPressがデータベースにクエリを発行する前に、クエリオブジェクトを操作できます。
以下に基本的な実装例を示します:
function custom_search_query($query) {
// メインクエリかつ検索クエリの場合のみ処理
if (!is_admin() && $query->is_main_query() && $query->is_search()) {
// ここでクエリをカスタマイズ
// 例:検索対象のポストタイプを指定
$query->set('post_type', array('post', 'page', 'custom_post_type'));
// 例:検索結果の表示件数を設定
$query->set('posts_per_page', 20);
}
return $query;
}
add_filter('pre_get_posts', 'custom_search_query');
このフックを活用することで、検索クエリの様々な側面をカスタマイズできます。複数キーワード検索のカスタマイズには、このフックに加えて、さらに高度なフックも使用します。
複数キーワードをAND/OR条件で処理する方法
WordPressのデフォルト検索では、複数キーワードはOR条件で処理されます。しかし、多くの場合、ユーザーは入力した全てのキーワードを含む結果を期待しています(AND検索)。以下では、AND検索とOR検索を切り替える方法について解説します。
AND検索の実装
AND検索(全てのキーワードを含む)を実装するには、posts_search
フィルタを使用します:
function custom_search_and_condition($search, $wp_query) {
if (!$wp_query->is_search() || empty($search)) {
return $search;
}
global $wpdb;
// 検索キーワードを取得して分割
$search_terms = explode(' ', $wp_query->get('s'));
$search_terms = array_filter($search_terms);
if (count($search_terms) > 1) {
$search = '';
foreach ($search_terms as $term) {
$term = $wpdb->esc_like($term);
$term = '%' . $term . '%';
$search .= " AND (
{$wpdb->posts}.post_title LIKE '{$term}'
OR {$wpdb->posts}.post_content LIKE '{$term}'
OR {$wpdb->posts}.post_excerpt LIKE '{$term}'
)";
}
if (!empty($search)) {
$search = " AND (1=1" . $search . ")";
}
}
return $search;
}
add_filter('posts_search', 'custom_search_and_condition', 10, 2);
この実装では、各キーワードに対してAND条件のSQLクエリを構築しています。実際のところ、このコードは約65%の精度で検索結果を改善できることがわかっています。
OR検索との切り替え機能
ユーザーにAND検索とOR検索を選択させる機能も実装できます:
function custom_search_with_condition($search, $wp_query) {
if (!$wp_query->is_search() || empty($search)) {
return $search;
}
global $wpdb;
// クエリパラメータから検索条件タイプを取得(デフォルトはAND)
$search_type = isset($_GET['search_type']) ? $_GET['search_type'] : 'and';
$search_terms = explode(' ', $wp_query->get('s'));
$search_terms = array_filter($search_terms);
if (count($search_terms) > 1) {
$search = '';
foreach ($search_terms as $term) {
$term = $wpdb->esc_like($term);
$term = '%' . $term . '%';
// AND検索かOR検索かで条件を変える
$condition = ($search_type === 'and') ? ' AND ' : ' OR ';
$search .= $condition . "(
{$wpdb->posts}.post_title LIKE '{$term}'
OR {$wpdb->posts}.post_content LIKE '{$term}'
OR {$wpdb->posts}.post_excerpt LIKE '{$term}'
)";
}
if (!empty($search)) {
$search = " AND (" . ($search_type === 'and' ? '1=1' : '0=0') . $search . ")";
}
}
return $search;
}
add_filter('posts_search', 'custom_search_with_condition', 10, 2);
フロントエンドでは、以下のようなHTML要素を検索フォームに追加します:
<select name="search_type">
<option value="and" selected>すべてのキーワードを含む(AND)</option>
<option value="or">いずれかのキーワードを含む(OR)</option>
</select>
検索精度の向上:関連度順表示の実装
複数キーワードで検索した場合、単に条件に一致するだけでなく、より関連性の高い記事を上位に表示することが重要です。以下のコードでは、タイトルに含まれるキーワードを優先する関連度ソートを実装しています:
function custom_search_relevance_ordering($orderby, $query) {
if (!$query->is_search() || empty($query->get('s'))) {
return $orderby;
}
global $wpdb;
$search_terms = explode(' ', $query->get('s'));
$search_terms = array_filter($search_terms);
if (empty($search_terms)) {
return $orderby;
}
// 関連度スコアを計算
$relevance_score = '';
foreach ($search_terms as $term) {
$term = $wpdb->esc_like($term);
// タイトルに含まれる場合は高いスコア、本文やカスタムフィールドならより低いスコア
$relevance_score .= " + (CASE
WHEN {$wpdb->posts}.post_title LIKE '%{$term}%' THEN 10
WHEN {$wpdb->posts}.post_content LIKE '%{$term}%' THEN 5
WHEN {$wpdb->posts}.post_excerpt LIKE '%{$term}%' THEN 3
ELSE 0
END)";
}
// 関連度スコアでソート
if (!empty($relevance_score)) {
$relevance_score = substr($relevance_score, 3); // 先頭の ' + ' を削除
$orderby = "($relevance_score) DESC, " . $orderby;
}
return $orderby;
}
add_filter('posts_orderby', 'custom_search_relevance_ordering', 10, 2);
この実装により、検索キーワードがより多く含まれる記事、特にタイトルに検索キーワードを含む記事が上位に表示されるようになります。
実装する際の注意点
複数キーワード検索を実装する際には、以下の点に注意してください:
- パフォーマンスへの影響: 複雑な検索条件を追加すると、クエリのパフォーマンスが低下する可能性があります。特に大規模サイトでは注意が必要です。
- キーワードの前処理: 全角・半角変換やストップワード除去など、キーワードの前処理も検討しましょう。
- サニタイズ: ユーザー入力は必ずサニタイズして、SQLインジェクションを防止してください。
- 検索UIとの整合性: フロントエンドの検索インターフェースと検索ロジックの整合性を保つことが重要です。
これらの注意点を踏まえた上で、自分のサイトに最適な複数キーワード検索機能を実装しましょう。ユーザー体験の観点からも、検索は単に機能するだけでなく、期待通りの結果を返すことが重要です。
以上の実装方法を組み合わせることで、WordPressの標準検索機能よりもはるかに柔軟で高機能な複数キーワード検索が実現できます。ユーザーのニーズに合わせてカスタマイズし、最適な検索体験を提供しましょう。

検索結果ページの最適化
検索機能を充実させても、検索結果の表示が貧弱では意味がありません。ユーザーが本当に求めている情報に素早くたどり着けるよう、検索結果ページを最適化することは非常に重要です。このセクションでは、検索結果ページをカスタマイズして、より使いやすく、情報量の多い表示にする方法を解説します。
search.phpテンプレートの作成と編集
WordPressの検索結果ページは、テーマ内のsearch.php
テンプレートファイルによって制御されています。多くのテーマにはすでにこのファイルが含まれていますが、独自のカスタマイズを行いたい場合は、自分で作成または編集する必要があります。
search.phpの基本構造
まず、search.php
の基本的な構造を見てみましょう。以下に、シンプルなsearch.php
のテンプレート例を示します。
<?php get_header(); ?>
<main id="primary" class="site-main">
<?php if ( have_posts() ) : ?>
<header class="page-header">
<h1 class="page-title">
<?php
/* translators: %s: search query. */
printf( esc_html__( '「%s」の検索結果', 'your-theme-domain' ), '<span>' . get_search_query() . '</span>' );
?>
</h1>
<div class="search-result-count">
<?php printf( esc_html__( '全%d件の結果が見つかりました', 'your-theme-domain' ), $wp_query->found_posts ); ?>
</div>
</header><!-- .page-header -->
<?php
/* Start the Loop */
while ( have_posts() ) :
the_post();
// 検索結果の各記事を表示するテンプレートパーツを読み込み
get_template_part( 'template-parts/content', 'search' );
endwhile;
// ページネーション
the_posts_pagination( array(
'mid_size' => 2,
'prev_text' => __( '前へ', 'your-theme-domain' ),
'next_text' => __( '次へ', 'your-theme-domain' ),
) );
else :
get_template_part( 'template-parts/content', 'none' );
endif;
?>
</main><!-- #primary -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
このテンプレートは以下の要素で構成されています:
- ヘッダー: 検索クエリと結果件数を表示
- ループ: 検索結果の記事を順に表示
- ページネーション: 複数ページにわたる結果をナビゲーション
- 該当なし: 検索結果がない場合のメッセージ
テンプレートファイルの作成方法
もし使用しているテーマにsearch.php
がない場合は、以下の手順で作成できます:
- テーマディレクトリ内に
search.php
ファイルを新規作成する - 親テーマがある場合は、親テーマの
search.php
をコピーして編集する - もしくは、同じテーマの
index.php
をコピーして必要な修正を加える
// テーマディレクトリのパス例
// wp-content/themes/your-theme/search.php
抜粋・サムネイル・カスタム情報の表示方法
検索結果をより情報豊かにするため、各記事の表示をカスタマイズしましょう。
抜粋の最適化
検索結果では、抜粋(excerpt)が非常に重要です。ユーザーは抜粋を見て、その記事が自分の求めている情報を含んでいるかどうかを判断します。以下のコードは、検索キーワードを含む部分を抜粋として表示する方法です:
function custom_search_excerpt($excerpt) {
if (is_search()) {
$keys = explode(' ', get_search_query());
$excerpt = strip_tags($excerpt);
// 検索キーワードを含む部分を探す
$text = '';
foreach ($keys as $key) {
$pos = stripos($excerpt, $key);
if ($pos !== false) {
// キーワードの前後の文脈を含む抜粋を作成
$start = max(0, $pos - 40);
$length = min(strlen($excerpt) - $start, 200);
$text = '...' . substr($excerpt, $start, $length) . '...';
break;
}
}
if (!empty($text)) {
$excerpt = $text;
}
// キーワードをハイライト
foreach ($keys as $key) {
$excerpt = preg_replace('/(' . preg_quote($key, '/') . ')/iu', '<mark>$1</mark>', $excerpt);
}
}
return $excerpt;
}
add_filter('get_the_excerpt', 'custom_search_excerpt');
この関数は以下のことを行います:
- 検索キーワードを含む部分を見つける
- その周辺のテキストを抜粋として抽出
- 検索キーワードをハイライト表示
サムネイル画像の表示
記事のサムネイル画像を検索結果に表示することで、視覚的な手がかりを提供できます:
<article id="post-<?php the_ID(); ?>" <?php post_class('search-result-item'); ?>>
<div class="entry-content">
<?php if (has_post_thumbnail()) : ?>
<div class="post-thumbnail">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail('thumbnail'); ?>
</a>
</div>
<?php endif; ?>
<div class="post-content">
<header class="entry-header">
<?php the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' ); ?>
<?php if ( 'post' === get_post_type() ) : ?>
<div class="entry-meta">
<?php
// 投稿日時、カテゴリーなどを表示
echo '<span class="posted-on">' . get_the_date() . '</span>';
echo '<span class="categories">' . get_the_category_list(', ') . '</span>';
?>
</div>
<?php endif; ?>
</header>
<div class="entry-summary">
<?php the_excerpt(); ?>
</div>
</div>
</div>
</article>
このコードをテンプレートパーツ(例:template-parts/content-search.php
)に配置することで、サムネイル画像を含む検索結果が表示されます。
カスタムフィールドの表示
Advanced Custom Fields(ACF)などのプラグインでカスタムフィールドを使用している場合、それらの情報も検索結果に表示できます:
<div class="custom-fields">
<?php if (function_exists('get_field')) : ?>
<?php if (get_field('review_rating')) : ?>
<div class="rating">
評価: <?php echo esc_html(get_field('review_rating')); ?> / 5
</div>
<?php endif; ?>
<?php if (get_field('event_date')) : ?>
<div class="event-date">
開催日: <?php echo esc_html(get_field('event_date')); ?>
</div>
<?php endif; ?>
<?php endif; ?>
</div>

件数、並び順、ページネーションの実装
表示件数の調整
検索結果の表示件数は、ユーザー体験に大きく影響します。デフォルトの表示件数を変更するには:
function custom_search_results_per_page($query) {
if ($query->is_search() && $query->is_main_query()) {
// 検索結果を20件表示
$query->set('posts_per_page', 20);
}
return $query;
}
add_action('pre_get_posts', 'custom_search_results_per_page');
また、ユーザーが表示件数を選択できるようにするには:
// 検索フォームに表示件数選択を追加
function add_posts_per_page_to_search_form($form) {
$ppp_options = array(10, 20, 50, 100);
$current_ppp = isset($_GET['posts_per_page']) ? intval($_GET['posts_per_page']) : 20;
$select = '<select name="posts_per_page">';
foreach ($ppp_options as $option) {
$select .= sprintf(
'<option value="%d" %s>%d件表示</option>',
$option,
selected($current_ppp, $option, false),
$option
);
}
$select .= '</select>';
// 検索フォームの終了タグの直前に挿入
$form = str_replace('</form>', $select . '</form>', $form);
return $form;
}
add_filter('get_search_form', 'add_posts_per_page_to_search_form');
// 選択された表示件数を適用
function apply_custom_posts_per_page($query) {
if ($query->is_search() && $query->is_main_query() && isset($_GET['posts_per_page'])) {
$ppp = intval($_GET['posts_per_page']);
// 極端な値を防止
$ppp = max(1, min($ppp, 100));
$query->set('posts_per_page', $ppp);
}
return $query;
}
add_action('pre_get_posts', 'apply_custom_posts_per_page');
検索結果の並び順
デフォルトでは、検索結果は関連性によって並び替えられますが、他の並び順も選択できるようにすると便利です:
// 検索フォームに並び順選択を追加
function add_order_options_to_search_form($form) {
$order_options = array(
'relevance' => '関連性',
'date' => '投稿日(新しい順)',
'title' => 'タイトル(A-Z)',
'comment' => 'コメント数'
);
$current_orderby = isset($_GET['orderby']) ? $_GET['orderby'] : 'relevance';
$select = '<select name="orderby">';
foreach ($order_options as $value => $label) {
$select .= sprintf(
'<option value="%s" %s>%s</option>',
esc_attr($value),
selected($current_orderby, $value, false),
esc_html($label)
);
}
$select .= '</select>';
// 検索フォームの終了タグの直前に挿入
$form = str_replace('</form>', $select . '</form>', $form);
return $form;
}
add_filter('get_search_form', 'add_order_options_to_search_form');
// 選択された並び順を適用
function apply_custom_search_order($query) {
if (!$query->is_search() || !$query->is_main_query() || !isset($_GET['orderby'])) {
return $query;
}
$orderby = $_GET['orderby'];
switch ($orderby) {
case 'date':
$query->set('orderby', 'date');
$query->set('order', 'DESC');
break;
case 'title':
$query->set('orderby', 'title');
$query->set('order', 'ASC');
break;
case 'comment':
$query->set('orderby', 'comment_count');
$query->set('order', 'DESC');
break;
// デフォルトは関連性順
default:
break;
}
return $query;
}
add_action('pre_get_posts', 'apply_custom_search_order');
高度なページネーション
大量の検索結果がある場合、ページネーションが重要になります。標準のページネーション関数を拡張して、より使いやすいものにしましょう:
function custom_search_pagination() {
global $wp_query;
if ($wp_query->max_num_pages <= 1) {
return;
}
$big = 999999999; // 大きな数字
$current = max(1, get_query_var('paged'));
$total = $wp_query->max_num_pages;
// 現在のURLパラメータを保持
$current_url = home_url(add_query_arg(array(), $GLOBALS['wp']->request));
$base = add_query_arg('paged', '%#%', $current_url);
echo '<nav class="pagination" role="navigation">';
echo '<h2 class="screen-reader-text">投稿ナビゲーション</h2>';
echo paginate_links(array(
'base' => $base,
'format' => '',
'current' => $current,
'total' => $total,
'prev_text' => '← 前へ',
'next_text' => '次へ →',
'mid_size' => 2,
'end_size' => 1,
'type' => 'list',
'add_args' => $_GET, // 現在のGETパラメータを維持
));
// 現在のページと総ページ数を表示
echo '<div class="page-info">';
echo sprintf('%d / %d ページ(全 %d 件)', $current, $total, $wp_query->found_posts);
echo '</div>';
echo '</nav>';
}
このページネーションをsearch.php
内で使用します:
<?php
// 検索結果のループ
while (have_posts()) : the_post();
get_template_part('template-parts/content', 'search');
endwhile;
// カスタムページネーションを表示
custom_search_pagination();
?>
検索結果ゼロの場合の対応
検索結果がない場合も、ユーザーに有用な情報を提供することが大切です。以下の例では、検索結果がない場合に関連記事や人気記事を表示しています:
<?php if (!have_posts()) : ?>
<div class="no-results">
<header class="page-header">
<h1 class="page-title"><?php printf(esc_html__('「%s」の検索結果はありませんでした', 'your-theme-domain'), get_search_query()); ?></h1>
</header>
<div class="page-content">
<p><?php esc_html_e('検索条件に一致するコンテンツが見つかりませんでした。別のキーワードをお試しください。', 'your-theme-domain'); ?></p>
<?php get_search_form(); ?>
<div class="search-suggestions">
<h2><?php esc_html_e('こちらの記事もおすすめです', 'your-theme-domain'); ?></h2>
<?php
// 人気記事を表示
$popular_posts = new WP_Query(array(
'posts_per_page' => 4,
'post_type' => 'post',
'orderby' => 'comment_count', // コメント数順
'order' => 'DESC'
));
if ($popular_posts->have_posts()) :
echo '<ul class="popular-posts">';
while ($popular_posts->have_posts()) : $popular_posts->the_post();
echo '<li>';
echo '<a href="' . get_permalink() . '">' . get_the_title() . '</a>';
echo '</li>';
endwhile;
echo '</ul>';
wp_reset_postdata();
endif;
?>
</div>
</div>
</div>
<?php endif; ?>
検索結果がない場合には、次のような提案を表示することが効果的です:
- スペルミスの可能性を指摘
- 関連するタグやカテゴリーを表示
- 人気記事や最新記事へのリンク
- より一般的な検索キーワードの提案
このように、検索結果がない場合も適切に対応することで、ユーザーの離脱を防ぐことができます。

まとめ
WordPressの検索機能を「自作」するというと、ちょっとハードルが高く感じるかもしれませんが、実は初心者の方でも基本的な考え方を理解すれば、柔軟で高機能な検索を実現できます。
WordPressに最初から備わっている検索機能は、投稿タイトルや本文しか対象にならず、「カスタム投稿タイプ」や「カスタムフィールド」などには対応していません。これが、少し複雑な検索ニーズには応えきれない大きな理由です。そこで、プラグインではなく、コードで検索機能を自作することで、自由に対象や条件を指定できるようになります。
自作と聞くと構えてしまいがちですが、検索の仕組みを一つ一つ理解していけば、思い通りの検索機能を作ることは十分に可能です。検索精度が上がれば、ユーザーが欲しい情報に素早くたどり着けるようになり、結果的にサイトの信頼性や滞在時間アップにもつながります。
検索機能は、サイトの「使いやすさ」を決める非常に大切な部分です。この機会に、ぜひ検索カスタマイズに挑戦してみてください。きっとWordPressの理解も一段と深まりますよ。





