一つの WordPress で構築したサイトの中でブログを運営している場合に、サイト全体を検索対象とするサイト内検索と、ブログ記事のみを検索対象とするブログ内検索の両方を設置したいということがあります。

ブログ内検索に WordPress の検索機能を利用し、サイト内検索は Google カスタム検索を利用するというのも一つの方法ですが、今回、既に WordPress の機能でサイト内検索を設置しているこのサイトに、WordPress の機能でブログ内検索を追加しました。

サイト内検索のフォームは共通のヘッダーに設置されているため、ブログの各ページでは検索フォームが2つ存在することになります。追加するブログ内検索のフォームはサイドバーに設置します。

また、その検索結果のページのデザインはそれぞれ異なるものとし、ブログ内検索の検索結果はブログのデザインの中で表示させます。

検索フォームの設置

サイト内検索のフォームは header.php に以下のように直接記述しています。

<form method="get" id="siteSearch" action="<?php echo home_url('/'); ?>">
  <label class="scrText" for="searchInput">サイト内検索</label>
  <input type="text" name="s" id="searchInput" value="<?php the_search_query(); ?>" placeholder="サイト内検索" />
  <input type="submit" value="検索" accesskey="f" />
</form>

一方、ブログ内検索のフォームは sidebar.php の get_post_type() == 'blog' で条件分岐している中に記述しました。

<form method="get" id="blogSearch" action="<?php echo home_url('/'); ?>">
  <label class="scrText" for="blogSearchInput">blog内検索</label>
  <input type="text" name="s" id="blogSearchInput" value="<?php the_search_query(); ?>" placeholder="blog内検索" />
  <input type="hidden" name="post_type" value="blog">
  <input type="submit" value="検索" accesskey="f" />
</form>

検索フォームに <input type="hidden" name="post_type" value="blog"> のように隠しデータを追加することで、検索対象の投稿タイプを絞り込むことができます。この検索結果の URL は http://www.will3in.co.jp/?s=searchword&post_type=blog のように post_type のパラメータがつきます。

ただ、このままではブログ内検索のフォームに入力した検索ワードが、検索結果のページでブログ内検索のフォームとサイト内検索のフォームの両方に表示されてしまいます。name 属性の “s” は変更できないようなので、サイト内検索の方は[ここから削除] value="<?php the_search_query(); ?>" を削除して、[ここまで削除][ここから追記] value="<?php if ( is_post_type_archive('blog') ){ echo get_search_query(); } ?>" として、ブログ内検索の[ここまで追記]検索結果ページで検索ワードを表示しないようにしました。

なお、同一ページの中で同じ id 属性の値を繰り返し使用することはできませんので、テキストフィールドの id 属性等は、サイト内検索のものと異なるものに必要があります。検索フォームを searchform.php で使い回すような場合は注意が必要です。

検索結果の表示

サイト内検索の検索結果は search.php によって表示していますが、ブログ内検索の検索結果はブログのアーカイブページと同じスタイルで表示させたいので、テンプレートを分ける必要があります。

でも、検索結果のテンプレートの適用ルールは search.php > index.php のみです。 search.php の中で条件分岐を行う方法も考えられますが、複雑になりそうです。そこでググってみたら、投稿タイプ毎に検索結果のテンプレートを作る方法がいくつか見つかりました。

functions.php に以下の記述を加えることで、“search-blog.php” など、“search-投稿タイプ名.php” というテンプレートが使えるようになります。

add_filter('template_include','custom_search_template');
function custom_search_template($template){
  if ( is_search() ){
    $post_types = get_query_var('post_type');
    foreach ( (array) $post_types as $post_type )
      $templates[] = "search-{$post_type}.php";
    $templates[] = 'search.php';
    $template = get_query_template('search',$templates);
  }
  return $template;
}

これで、ブログ内検索結果に独自のテンプレートを適用することができるようになりました。

なお、6行目のみダブルクォーテションで囲まれていますが、これをシングルクォーテションにすると機能しません。

でもこれだけでは不十分で、パンくずリストにブログのメインページへのリンクが表示されなかったり、検索結果が無い場合にブログ用のサイドバーや body に設定している id 属性の値が読み込まれなかったりしますので、これらを調整する必要があります。

検索結果が無い場合でもブログのページとして表示する調整

サイドバーの表示や body の id 属性の値は、sidebar.php や header.php の中で条件分岐によって投稿タイプ毎に内容を変えています。ブログ部分は get_post_type() == 'blog' で分岐していますが、検索結果が無い場合はこれに該当しませんので、検索結果ページかつブログのアーカイブページという条件を付け加えます。

if ( get_post_type() == 'blog' || is_search() && is_post_type_archive('blog') ):

一方、サイト内検索の検索結果ページの条件分岐は、検索結果ページかつブログのアーカイブページ以外というふうにして、ブログ検索の検索結果ページに適用されないようにします。

if ( is_search() && !is_post_type_archive('blog') ):

パンくずリストの調整

パンくずリストは Breadcrumb NavXT プラグインを使用していますが、サイト内検索とブログ内検索を区別できませんので、どちらも以下のように表示されます。

Home > “○○” の検索

これを、ブログ内検索では

Home > ブログ > “○○” の検索

のように表示されるようにする必要があります。

以前、「カスタム投稿タイプの日付ベースアーカイブとパンくずリスト」という記事で、カスタム投稿タイプのページのパンくずリストに、カスタム投稿タイプのメインページへのリンクの追加し、年別アーカイブのリンク先を修正する方法を書きましたが、これにブログ内検索の検索結果ページの場合の記述を追加しました。

if ( is_date() ){
  (日付ベースアーカイブのパンくずリスト)
} elseif ( is_search() && is_post_type_archive('blog') ){
  $post_type_link = ' &gt; <a href="'. get_post_type_archive_link('blog'). '">'. esc_html(get_post_type_object('blog')->label). '</a>';
[ここから削除]  echo preg_replace('/(home.+?<\/a>)/', '$1'. $post_type_link, bcn_display(true));[ここまで削除]
[ここから追記]  $patterns = array ('/(home.+?<\/a>)/', '/search\/([^\/]+)\//');
  $replace = array ('$1'. $post_type_link, '?s=$1&amp;post_type=blog');
  echo preg_replace($patterns, $replace, bcn_display(true));[ここまで追記]
} else {
  bcn_display();
}

これも検索結果が無い場合を考慮した条件分岐とし、Breadcrumb NavXT で吐き出される Home へのリンクを、この後にブログのメインページへのリンクを加えたものに置き換えています。

これで、思いどおりの検索フォームの切り分けと、それぞれの検索結果ページの表示ができたと思います。

(7月24日訂正)
検索結果の2ページ目以降のパンくずリストの、1ページ目へのリンクが正しくないので、これも合わせて置換しています。

(7月28日訂正)
ブログ内検索のフォームに入力した検索ワードが、検索結果のページでブログ内検索のフォームとサイト内検索のフォームの両方に表示されてしまう問題の解決法を修正しました。