WEB制作

【WordPress】WP_Queryでカテゴリー別に並び替えてデータを出力する方法

こんにちは、ぷぷのすけです。

あるWebサイトを作っていた時にお客様から検索に該当した投稿データをカテゴリー毎に日付の新しい順に並び替えて一覧を表示してほしいと要望がありました。
やりたいことはこんな感じ。

・投稿データ

カテゴリー 最終更新日 品目
野菜・果物 2018/10/2 バナナ
肉・魚 2018/10/3 牛肉
お惣菜 2018/10/1 竜田揚げ
肉・魚 2018/10/5 イワシ
お惣菜 2018/10/4 おひたし
野菜・果物 2018/10/5  トマト

・検索結果

カテゴリー 最終更新日 品目
野菜・果物 2018/10/5 トマト
野菜・果物 2018/10/2 バナナ
肉・魚 2018/10/5 イワシ
肉・魚 2018/10/3 牛肉
お惣菜 2018/10/4 おひたし
お惣菜 2018/10/1 竜田揚げ

 

カテゴリー別に並び替えてデータを取得できない

サブループ1回でカテゴリー別に並び替えてデータを取得出来ると簡単に考えていたら考えが甘かった…
WordPressのリファレンスを見てみると以下のようになっている。

関数リファレンス/WP Query

orderby (文字列 | 配列) – パラメータで指定した項目の値で投稿をソートする。デフォルトは ‘date’ (post_date) です。2つ以上のオプションを含めることもできます。

  • none‘ – 順序をつけない(バージョン 2.8 以降で使用可能)。
  • ID‘ – 投稿 ID で並び替える。大文字に注意。
  • author‘ – 著者で並び替える。(‘post_author‘ でも良い。)
  • title‘ – タイトルで並び替える。(‘post_title‘ でも良い。)
  • name‘ – スラッグで並び替える。(‘post_name‘ でも良い。)
  • type‘ – 投稿タイプで並び替える。(‘post_type‘ でも良い。)
  • date‘ – 日付で並び替える。(‘post_date‘ でも良い。)
  • modified‘ – 更新日で並び替える。(‘post_modified‘ でも良い。)
  • parent‘ – 投稿/固定ページの親 ID 順。(‘post_parent‘ でも良い。)
  • rand‘ – ランダムで並び替える。’RAND(x)‘ も使えます(’x‘ はシードになる整数)。
  • comment_count‘ – コメント数で並び替える(バージョン 2.9 以降で使用可能)。
  • relevance‘ – 文字列検索のとき次の順で並び替える: 1. 文字列全体がマッチ。 2. すべての単語がタイトルに含まれる。 3. いずれかの単語がタイトルに現れる。 4. 文字列全体が post_content に現れる。
  • menu_order‘ – 固定ページの表示順で並び替える。固定ページ(固定ページ編集画面のページ属性ボックス)と添付ファイル(ギャラリー内のメディアの順番に相当)で使うことが最も多いでしょう。しかしバラバラの値が入った ‘menu_order‘ を持つ任意の投稿タイプに対して使うことができます(デフォルト値は 0)。
  • meta_value‘ – カスタムフィールドで並び替える。’meta_key=keyname‘ がクエリに存在しなければいけません。また、ソート順は文字列順になることに注意して下さい。数値だと予想外の挙動をします(通常、1, 3, 4, 6, 34, 56となると思うところが、1, 3, 34, 4, 56, 6となります)。数値なら代わりに ‘meta_value_num‘ を使ってください。カスタムフィールドの値を特定の型にキャストしたければ ‘meta_type‘ を指定できます。有効な値は ‘NUMERIC’, ‘BINARY’, ‘CHAR’, ‘DATE’, ‘DATETIME’, ‘DECIMAL’, ‘SIGNED’, ‘TIME’, ‘UNSIGNED’ です(’meta_query‘ と同じ)。’meta_type‘ を使うとき、それに応じて ‘meta_value_*‘ も使えます。例えば ‘meta_type‘ に DATETIME を指定するとき、ソート順の定義に ‘meta_value_datetime‘ を使えます。
  • meta_value_num‘ – カスタムフィールドの値を数値として並び替える。(バージョン 2.8 以降で使用可能)。これもまた、’meta_key=keyname‘がクエリに存在しなければならないことに注意して下さい。こちらは ‘meta_value‘ 示したような数値での並べ替えを可能にします。
  • post__in‘ – post__in パラメータの配列に並んだ投稿 ID の順になります(バージョン 3.5 以降で利用可能)。
  • post_name__in‘ – ‘post_name__in‘ パラメータの配列に並んだ投稿スラッグの順になります(バージョン 4.6 以降で利用可能)。参考: このとき order パラメータの値はソート順を変えません。
  • post_parent__in‘ – ‘post_parent__in‘ パラメータの配列に並んだ親投稿 ID の順になります(バージョン 4.6 以降で利用可能)。参考: このとき order パラメータの値はソート順を変えません。

orderbyパラメーターに日付は指定できるがカテゴリー別に並び替えるパラメーターがそもそも存在しない…
取得したデータの配列をソートすれば出来なくはないが別の方法はないかと見ていたら…

  • meta_value‘ – カスタムフィールドで並び替える。

カスタムフィールドの文字を発見!
投稿のカテゴリーはそのままにしてカスタムフィールド使用して検索結果の順番を投稿の管理画面で指定できるようにした。

Advanced Custom Fieldsの設定

Advanced Custom Fieldsプラグインはインストールされていたのでそれを使うことにした。

カスタムフィールドの設定は下の画像のように設定。
並び替える順番を数字で指定しカテゴリーと同じ項目をラベルに指定する。

作成したフィールドグループを表示する条件を「投稿タイプ」に設定。

投稿データを作成

投稿の新規追加または変更で下の画像の様に設定して「公開」する。
赤枠の様に商品種類とカテゴリーを一緒に指定する。
カテゴリーを使用しなかったら指定しなくてもOK!

HTML5を使用していることを明示する

WordPress は組み込みの HTML5 検索フォームを使用するためfunction.phpに下記のコードを追加。

add_theme_support( 'html5', array( 'search-form' ) );

 

searchform.phpを作成

searchform.phpに検索フォームを作成。
前項でWordPress は組み込みの HTML5 検索フォームを指定したのでformタグのclassに”search-form”を指定する。
またテキストタイプのinputタグのtype属性は”search”を指定する。

参考:関数リファレンス/get search form

<h2>検索フォーム</h2>
<form class="search-form" role="search" method="get" action="<?php echo home_url('/'); ?>">
	<div class="type">
		<h3>商品種類</h3>
		<label><input type="checkbox" name="type[]" value="1">野菜・果物</label>
		<label><input type="checkbox" name="type[]" value="2">肉・魚</label>
		<label><input type="checkbox" name="type[]" value="3">お惣菜</label>
	</div>
	<div class="price">
		<h3>価格</h3>
		<select class="price_low" name="low">
			<option value="0" selected>下限なし</option>
			<option value="100">100円以上</option>
			<option value="200">200円以上</option>
			<option value="300">300円以上</option>
			<option value="400">400円以上</option>
			<option value="500">500円以上</option>
			<option value="600">600円以上</option>
			<option value="700">700円以上</option>
			<option value="800">800円以上</option>
			<option value="900">900円以上</option>
			<option value="1000">1000円以上</option>
		</select>
		<span>~</span>
		<select class="price_high" name="high">
			<option value="200">200円以下</option>
			<option value="300">300円以下</option>
			<option value="400">400円以下</option>
			<option value="500">500円以下</option>
			<option value="600">600円以下</option>
			<option value="700">700円以下</option>
			<option value="800">800円以下</option>
			<option value="900">900円以下</option>
			<option value="1000">1000円以下</option>
			<option value="9999999" selected>上限なし</option>
		</select>
	</div>
	<div class="free_word">
		<h3>フリーワード</h3>
		<input class="search-field" type="search" name="s">
	</div>
	<input type="submit" value="検索">
</form>

 

検索フォームを任意の場所に表示する

このサンプルではトップページ(front-page.php)に検索フォームを設置した。

front-page.phpはこちら↓

<?php
get_header(); ?>

<div><?php get_search_form(); ?></div>

<?php
get_sidebar();
get_footer();

 

検索結果を表示する

検索フォームに入力された値を元にsearch.phpに検索結果を表示する処理を実装する。
サンプルでは検索フォームのデータを「GET」で受け取っているが「POST」でもOK!

search.phpはこちら↓

<?php
get_header();

	$type = $_GET['type'];
	$low = $_GET['low'];
	$high = $_GET['high'];
	$s = $_GET['s'];

	// 商品種類をエスケープ処理して配列にセット
	foreach($type as $val) {
		$array[] = htmlspecialchars($val, ENT_QUOTES, 'UTF-8');
	}
	// カスタムフィールドのメタデータを配列に設定
	$metaq[] = array('relation' => 'AND',
									 array('key' => 'type',				// キー:カスタムフィールド名(type)
												 'value' => $array,			// 値:フォームで入力された値を配列で渡す
												 'compare' => 'IN', ),	// 条件判定:指定した値のいずれかに該当
									 array('key'=>'price',				// キー:カスタムフィールド名(price)
												 'value'=> array(htmlspecialchars($low, ENT_QUOTES, 'UTF-8'),
																				 htmlspecialchars($high, ENT_QUOTES, 'UTF-8')),
												 												// 値:フォームで入力された値を配列で渡す
												 'compare'=> 'BETWEEN',	// 条件判定:指定した値の範囲内
												 'type'=> 'NUMERIC',)		// 数値
									);

	// 商品種類が昇順で投稿日付の新しい順に並び替えてデータを取得
	$orderby = array(
		'type' => 'ASC',														// 商品種類(type)は降順
		'modified' => 'DESC'														// 更新日は昇順
	);
	// WP_Queryのパラメーターを設定
	$args = array('post_type' => 'post',					// 投稿(post)
								'meta_query' => $metaq,					// カスタムフィールドの値
								'orderby' => $orderby,					// 商品種類が昇順で投稿日付の新しい順
								's' => $s,											// フリーワード
								'posts_per_page' => -1					// 取得件数
								);
	$the_query = new WP_Query($args);
	if($the_query->have_posts()):
		while($the_query->have_posts()):
			$the_query->the_post();
?>
			<div><?php the_content(); ?></div>
<?php
		endwhile;
			wp_reset_postdata();
	else:
?>
			<p>該当なし</p>
<?php
	endif;
get_footer();

 

これで実行した結果がこちら↓

デモはこちら

要点まとめ
  • WP_Queryのorderbyパラメータにカテゴリーで並び替えてデータを取得するパラメータがない。
  • カスタムフィールドの値は並び替えたいカテゴリーの順番を「番号」や「アルファベット」で指定する。
  • 投稿でカスタムフィールドを指定してカスタムフィールドの値を投稿データに紐付ける。
  • 投稿のカテゴリーとカスタムフィールドのラベルを同じにする。(カテゴリーと同じにしたい場合)
  • 最終更新日で並び変えるのはorderbyパラメーターに”modified”を指定する。公開日で並び変えるならば”date”を指定する。(search.php 29行目)
  • カスタムフィールドの値と最終更新日を両方指定して並び替えるにはorderbyパラメーターに配列で指定する。(search.php 27行目)
  • カスタムフィールドやWP_Queryのパラメーターを変えればカスタム投稿のカスタム分類でも同じことができる。

デメリットは投稿するときにカスタムフィールドとカテゴリーと同じものを選ぶ手間が発生する。まぁカテゴリーを使わずにカスタムフィールドで代用するのであればその手間をはぶけるけどね。

この記事を見て間違いやもっといい方法があったら教えていただけると嬉しいです。

COMMENT

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