WordPressの検索ページを人気順などで並び替えるボタンをつける

WordPressの検索ページを人気順などで並び替えるボタンをつける

カテゴリとタグのアーカイブページに日付順や閲覧数順の並び替えボタンを実装してあったのですが、検索ページにも追加したので方法をまとめてみました。


検索ページにも並び替えボタン

半年ほど前、このような記事を書いたのですが。

GET関数でどのボタンを押されたか判別してpre_get_posts()で並び替える(閲覧数はWP-PostViewsというプラグインを利用)、という。これが、アーカイブページなら

https://ateitexe.com/category/xxx/
 ↓
https://ateitexe.com/category/xxx/?sort=popular

このようにGET変数を付加して処理すればいけるな、という内容だったわけですが、検索ページだと

https://ateitexe.com/?s=キーワード

このようにもう既にGET変数がついているので、検索ページを並び替えたい場合は

https://ateitexe.com/?s=キーワード&sort=popular

という形にするためにもうちょっとテコ入れしないとうまくいかないなーということに気がついて、せっかくだからやってみようかな、と思ったわけです。

150203-1

このように、検索ページにも並び替えボタンがつきました。以下解説です。前記事からの派生という形で書いて行きますので、基本的な説明などは前記事と合わせて見ていってください。

先にpre_get_posts()のほうを

functions.php

function SortArchive( $query ) {
	if ( is_admin() || ! $query->is_main_query() )
		return;

	if ( $query->is_category() || $query->is_tag() || $query->is_search() ) {
		$sortset = (string)filter_input(INPUT_GET, 'sort');
		if ( $sortset === 'older' ) { //古い
			$query->set( 'orderby', 'date' );
			$query->set( 'order', 'ASC' );
		} elseif ( $sortset === 'popular' ) { //閲覧多
			$query->set( 'meta_key', 'views' );
			$query->set( 'orderby', 'meta_value_num' );
		} elseif ( $sortset === 'unpopular' ) { //閲覧少
			$query->set( 'meta_key', 'views' );
			$query->set( 'orderby', 'meta_value_num' );
			$query->set( 'order', 'ASC' );
		} else { //それ以外(新しい)
			$query->set( 'orderby', 'date' );
		}
		return;
	}
}
add_action( 'pre_get_posts', 'SortArchive' );

並び替える条件に、$query->is_search()も追加しただけ。ほぼ前回のと一緒です。

コードの変更点

概要

前の記事では

<?php if ( is_archive() ): //アーカイブページ ?>
	<?php if ( is_category() || is_tag() ): ?>
		//カテゴリ,タグアーカイブのとき
		//ここに並び替えボタンを実装
	<?php elseif( is_date() ): ?>
		//日付アーカイブのとき
	<?php endif; ?>
<?php endif; ?>

<?php if ( is_search() ): ?>
	//検索ページのとき
<?php endif; ?>

このような形で書いたのですが、1行目で「アーカイブページのときに」という条件で括っているために、検索ページは10~12行目に別で書いています。ここにも並び替えボタンを実装したいので、この形では非効率ですよね。なので、

<?php if( is_category() || is_tag() || is_search() ): ?>
	// カテゴリ,タグ,検索ページのとき
	//ここに並び替えボタンを実装
<?php endif; ?>

<?php if( is_date() ): ?>
	//日付アーカイブのとき
<?php endif; ?>

こういう形にしました。

詳細

<?php
if ( is_archive() || is_search() ) {
	global $wp_query;
	$total_results = $wp_query->found_posts; //件数を取得しておく
}
?>

<?php if( is_category() || is_tag() || is_search() ): // カテゴリ,タグ,検索 ?>
	<div class="result">
		<?php if( is_category() ): //カテゴリアーカイブのとき ?>
			カテゴリ "<?php single_cat_title(); ?>":<?php echo $total_results; ?>件<br />
		<?php elseif( is_tag() ): //タグアーカイブのとき ?>
			タグ "<?php single_tag_title(); ?>":<?php echo $total_results; ?>件<br />
		<?php elseif( is_search() ): //検索ページのとき ?>
			"<?php the_search_query(); ?>" で検索した結果:<?php echo $total_results; ?>件<br />
		<?php endif; ?>
		//並び替えボタンの実装
	</div>
<?php endif; ?>

<?php if( is_date() ): //日付アーカイブ ?>
	//前回と同じ
<?php endif; ?>

ベースの形に肉付けして、こんな感じ。更にハイライト部分に書くボタンの記述を以下に説明していきます。

CSSは同じですので前の記事を参照してください。

並び替えボタンの実装

htmlのイメージ

例えば前回カテゴリアーカイブでは、このようなhtmlが出力されるようにPHPを書きました。

<form method="get" action="https://ateitexe.com/category/xxx/">
	<input type="hidden" name="sort" value="newer" />
	<input type="submit" value="新しい順" />
</form>

これがもし検索ページだった場合、

<form method="get" action="https://ateitexe.com/">
	<input type="hidden" name="s" value="キーワード" />
	<input type="hidden" name="sort" value="newer" />
	<input type="submit" value="新しい順" />
</form>

検索されたキーワードの情報も一緒に持たせます。更にaction=の遷移先をトップページにすることで、ボタンを押された時に

https://ateitexe.com/?s=キーワード&sort=newer

というURLに遷移することができます。

この形を目指して、カテゴリ・タグアーカイブの場合はこっち、検索ページのときはこっち、という分岐をさせてhtmlを出し分けるように、PHPを書いていきます。

コード

前回のコード(アーカイブページのみ)

<?php
$url_str = get_pagenum_link(1);
$sortset = (string)filter_input(INPUT_GET, 'sort');
$crt = ' class="sort_current"';
?>
<form method="get" action="<?php echo $url_str ?>">
	<input type="hidden" name="sort" value="newer" />
	<input type="submit"<?php if( $sortset === 'newer' ){ echo $crt; } ?> value="新しい順" />
</form>

「新しい順」に並び替えるボタンを例に、このように書いていました。

2行目で取得したURLを$url_strという変数に入れ、6行目の遷移先action=に指定してるので(詳細は前回の記事をご参照ください)、ここを分岐してやらなきゃいけないですね。

検索ページとアーカイブページで出し分け

<?php
if( is_search() ){
	$url_str = site_url('/');
} else {
	$url_str = get_pagenum_link(1);
}
$sortset = (string)filter_input(INPUT_GET, 'sort');
$crt = ' class="sort_current"';
?>
<form method="get" action="<?php echo $url_str ?>">
<?php if( is_search() ): ?>
	<input type="hidden" name="s" value="<?php the_search_query(); ?>" />
<?php endif; ?>
	<input type="hidden" name="sort" value="newer" />
	<input type="submit"<?php if( $sortset === 'newer' ){ echo $crt; } ?> value="新しい順" />
</form>

検索ページの時はトップページURLを、それ以外(カテゴリ・タグアーカイブ)の場合は従来どおり生成したURLを、変数$url_strに入れます。これで遷移先が変化します。

後は11~13行目を追加で、検索ページのときだけ検索キーワードの情報を持たせます。検索文字列はthe_search_query()で表示することができます。

ただこの11~13行、これだけ見るぶんにはいいのですが、ボタンの数だけ同じことを書く羽目になるのでもうちょっと軽くしたいところ。

省コード化

<?php
if( is_search() ){
	$url_str = site_url('/');
	$srch = "\t" . '<input type="hidden" name="s" value="' . get_search_query() . '" />' . "\n";
} else {
	$url_str = get_pagenum_link(1);
}
$sortset = (string)filter_input(INPUT_GET, 'sort');
$crt = ' class="sort_current"';
?>
<form method="get" action="<?php echo $url_str ?>">
<?php if( is_search() ){ echo $srch; } ?>
	<input type="hidden" name="sort" value="newer" />
	<input type="submit"<?php if( $sortset === 'newer' ){ echo $crt; } ?> value="新しい順" />
</form>

検索ページだった場合のみ、4行目で予め文字列を入れておいて12行目で出力する、という形へ。出力コードの見た目を整えるためタブや改行も含めています。

あと、さっきはthe_search_query()を使っていましたが、ここでは出力せずに取得するので、get_search_query()を使っています。

テンプレートタグの出力と取得の違いについてはこちら

エスケープ処理のご注意

こちらにあるとおり、get_search_query()$escapedというパラメータがあり、カッコ内にtrueでエスケープ処理を行い、falseでエスケープ処理を行いません。空だと、デフォルトでtrueとされます。

エスケープ処理とは特殊文字を無害化することですが、とても簡単に言うとこれを行わないと危険なのです。

どのバージョンからget_search_query()にエスケープ処理がデフォルトで実装されたのか特定できなかったのですが、WordPressの過去のバージョンではこの関数にエスケープ処理がなされていなかった、という経緯があるようです。(2008年くらいまで…?)

お使いのWPのバージョンにはくれぐれもお気をつけて、自己責任でお願いいたします。

4つ並べる

それでは、今までの流れでボタンを4つつけて、それぞれの区切りに「|」を入れてみると、

<?php
if( is_search() ){
	$url_str = site_url('/');
	$srch = "\t" . '<input type="hidden" name="s" value="' . get_search_query() . '" />' . "\n";
} else {
	$url_str = get_pagenum_link(1);
}
$sortset = (string)filter_input(INPUT_GET, 'sort');
$crt = ' class="sort_current"';
?>
並び替え:
<form method="get" action="<?php echo $url_str ?>">
<?php if( is_search() ){ echo $srch; } ?>
	<input type="hidden" name="sort" value="newer" />
	<input type="submit"<?php if( $sortset !== 'older' && $sortset !== 'popular' && $sortset !== 'unpopular' ){ echo $crt; } ?> value="新しい" />
</form>
|
<form method="get" action="<?php echo $url_str ?>">
<?php if( is_search() ){ echo $srch; } ?>
	<input type="hidden" name="sort" value="older" />
	<input type="submit"<?php if( $sortset === 'older' ){ echo $crt; } ?> value="古い" />
</form>
|
<form method="get" action="<?php echo $url_str ?>">
<?php if( is_search() ){ echo $srch; } ?>
	<input type="hidden" name="sort" value="popular" />
	<input type="submit"<?php if( $sortset === 'popular' ){ echo $crt; } ?> value="閲覧多" />
</form>
|
<form method="get" action="<?php echo $url_str ?>">
<?php if( is_search() ){ echo $srch; } ?>
	<input type="hidden" name="sort" value="unpopular" />
	<input type="submit"<?php if( $sortset === 'unpopular' ){ echo $crt; } ?> value="閲覧少" />
</form>

このような感じに。15行目は「日付が新しい順」をデフォルトとする、という意味で書いていますので、こちらも前回の記事をご参照ください。

以上です! どなたかのご参考になれたら幸いですー!

公開日:2015/02/03
更新日:2018/03/27

9件のコメント

  1. まきあやや より:

    「WordPressのアーカイブページを人気順などで並び替えるボタンをつける」に続いてこちらの検索も参考にさせて頂きました。
    でも、これを実行するとキーワードのヒット率というのでしょうか、それが全く無視され、単にキーワードが出現したページの「新規」「投稿」「人気ありなし」の順序で表示されるだけになってしまいました。
    できれば、検索結果の初期ページは「新規」「投稿」「人気ありなし」ではない、WordPress初期の検索結果が出るようになったら、もっと素敵かなと思います。
    よろしくお願いします。

    • *you より:

      まきあややさん、コメントありがとうございます。

      すみません、検索結果のデフォルトは日付の新しい順だと思ってました…! 調べてみたらWP3.7から「関連度」順になってたらしいですね! functions.phpのソート部分をこのハイライト部のように直してもらえれば、検索結果の初期画面はWPデフォルトの並び順になるはずです。

      function SortArchive( $query ) {
      	if ( is_admin() || ! $query->is_main_query() )
      		return;
      
      	if ( $query->is_tag() || $query->is_category() || $query->is_search() ) {
      		$sortset = (string)filter_input(INPUT_GET, 'sort');
      		if ( $sortset === 'older' ) { //古い
      			$query->set( 'orderby', 'date' );
      			$query->set( 'order', 'ASC' );
      		} elseif ( $sortset === 'popular' ) { //閲覧多
      			$query->set( 'meta_key', 'views' );
      			$query->set( 'orderby', 'meta_value_num' );
      		} elseif ( $sortset === 'unpopular' ) { //閲覧少
      			$query->set( 'meta_key', 'views' );
      			$query->set( 'orderby', 'meta_value_num' );
      			$query->set( 'order', 'ASC' );
       		} else { //それ以外(新しい)
      			if ( !( $query->is_search() ) || $sortset === 'newer' ){
      				$query->set( 'orderby', 'date' );
      			}
      		}
      		return;
      	}
      }
      add_action( 'pre_get_posts', 'SortArchive' );
      

      ボタン部分の表示は、記事内の「4つ並べる」のコードでハイライトされている15行目を

      <input type="submit"<?php if( $sortset !== 'older' && $sortset !== 'popular' && $sortset !== 'unpopular' ){ if( !is_search() || $sortset === 'newer' ){ echo $crt; }} ?> value="新しい" />
      

      こちらに差し替えれば、検索ページでデフォルトの場合はカレントが外れるようになります。こんな長いのをワンライナーで書くのはどうかと思いますが一応同じ形式で…(;´Д`)

      このブログでは従来通り新しい日付順で並ぶようにしておりますが、用途によりますもんね。お試しください。

  2. まきあやや より:

    *youさんへ

    わざわざコードを書いていただき、大変ありがとうございます。
    早速、「関連度順」というリンクを追加して使わして頂きました。

    • *you より:

      こちらこそお返事ありがとうございます! お役に立てましたら光栄です(●´ω`●)

  3. tanaka より:

    *youさんはじめまして。tanakaと申します。

    現在wordpressの勉強をしており、絞り込み検索の実装をしております。

    http://kotori-blog.com/wordpress/refinement_search/
    のサイトを参考にカスタムフィールドで絞り込み検索を実装することはできたのですが、絞り込んだ検索結果をさらに価格の安い順・高い順などをこの記事のように並び替えボタンで並び替えたいと思っています。

    query_postsを削除しこちらの記事を参考に(全てコピペですが。笑)function.php(meta_valueはカスタムフィールドのキーに変更。)とsearch.phpを全くそのままの状態で書き加えたのですが、絞り込み検索はできてもさらに並び替えることができませんでした。

    どうすればカスタムフィールドで絞り込んだ検索結果をさらにカスタムフィールドの値で昇順降順のように並び替えることができるでしょうか?

    まだまだ知識不足ですので、何かアドバイスいただけると幸いです。

    よろしくお願いします。

    tanaka

    • *you より:

      tanakaさん、はじめまして。コメントありがとうございます。

      実際のコードと挙動を見てみないとなんとも言えないのですが、以下の形だと仮定して返信いたします。

      • カスタムフィールドの価格は、meta_keyがpriceという名称で格納されている
      • ソートに使うGET変数は、価格の高い順はhigher、低い順はlowerとする

      カスタムフィールドをキーワードにして、更にカスタムフィールドでソートするということなので、pre_get_postで価格の低い順を例にすると

      if ( $query->is_search() ) {
      	$sortset = (string)filter_input(INPUT_GET, 'sort');
      	if ( $sortset === 'lower' ) {
      		$query->set( 'meta_key', 'price' );
      		$query->set( 'orderby', 'meta_value_num' );
      		$query->set( 'order', 'ASC' );
      		$query->set( 'meta_query', array(
      			'key' => 'meta_key名',
      			'value' => '絞込対象',
      		));
      	}
      }
      

      このような形にすれば良いんじゃないかなーと思います。きちんと検証したわけではないので確実性がなくて申し訳ないですが、ご参考になれば幸いです。

  4. yama より:

    はじめまして。
    始めてWordPressでのサイト構築をしておりいろいろと検索を重ねており、やりたかったことがやっと見つかり、とても感謝しています!!
    こちらで思うように並び替えることが実現できたのですが、ネットで拾ったページネーションでは並び替えとページ切り替えが上手くいっておらず…
    こちらのブログで使われているページネーションのfunctionなのかプラグインなのかを教えていただけないでしょうか?
    function.phpを公開している記事を見つけたのですが、ページネーションの部分は削除されているようで。。
    こんなお願い大変失礼かと思いましたが、何卒よろしくお願いいたします。

    • *you より:

      yamaさん、コメントありがとうございます。すみません! 前書いてあった記事、だいぶ古くて現状と違ってたので消してしまったのです…!

      現状、私のブログではこちらの記事を参考させていただいてfunctions.phpに書いて出力しております。よろしくお願いしますー!

      ちなみになんですが、いまテーマを新しくしようと作っておりまして、レスポンシブ対応のページネーションを実装したのを記事にしようかと思ってます。もしよろしければチェックしてみてくださいー!

      追記:書きました

    • yama より:

      youさん
      さっそくお返事ありがとうございます!!
      教えていただいたページを参考に入れてみたら、ばっちり動きました♪ほんとうにありがとうございます!
      レスポンシブ対応も気になるので、また参考にさせていただきます(^^)


まきあやや へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)