tips

複数タクソノミーで絞り込めるアーカイブページを作成する。

wordpressで複数タクソノミによるPOSTの絞り込みの方法はそちこちで紹介されています。(個人的にはここが参照しやすいと思う。)こいつを、従来のカテゴリページのようにページングができる複数タクソノミのアーカイブページとして設置したい、というわけです。
multiple_tax

 

パーマリンクがないからパラメータでURLをカスタマイズする

例えばポストに次のような2種類のカスタムタクソノミを割り当てているとします。

taxonomy: color   terms: red / blue / green

taxonomy: form   terms: square / circle / triangle

普通にタクソノミーのテンプレートでは
http://example.com/color/red
…とか
http://example.com/form/square/page/2
…とかは表示できても、colorはredかつformはsquareみたいにできない。そもそもそんなパーマリンクが存在しないのだから、ページングできるわけがない。この問題を回避するためにURLクエリパラメータを与えることにします。
最終的なURLは
http://example.com/items?color=red&form=square
…とか
http://example.com/items/page/2?color=blue&form=circle
…のような感じになります。googleさんの検索結果ページと一緒ですね。

 


 

設置の順序

① まずはカスタムタクソノミを作ります。

カスタムタクソノミを$postかカスタム投稿タイプに割り当てます。(まずそこからという方はこちらとかを参照して下さい。)

② アーカイブページの代わりにするための固定ページを作成

自動的に作られるアーカイブページの代わりに適当な名前の固定ページを作成し、適当なページ用のテンプレートphpを用意します。(今ひとつ意味が分からない方はこちらとかが参考になるかもしれません。)WP_Queryを使ってカスタム投稿タイプのアーカイブを表示します。(※以下ではカスタム投稿タイプは「item」、固定ページのslugは「items」と設定したものとして表記していきます。)

<?php
	$args = array(
		'post_type' => 'item',
	);
	$wp_query = new WP_Query();
	$wp_query->query( $args );
	$li = '';
	while ( $wp_query->have_posts() ) : $wp_query->the_post(); 
?>
<div class="post">
	<a href="<?php echo get_permalink( $post->ID );?>" title="<?php echo get_the_title( $post->ID );?">
		<h2><?php the_title( ); ?></h2>
		<div class="excerpt"><?php the_excerpt( ); ?></div>
	</a>
</div>
<?php endwhile; ?>
<div class="page-navigation">
    <div class="older"><?php previous_posts_link( '&laquo; 前へ' ); ?></div>
    <div class="newer"><?php next_posts_link( '次へ &raquo;' ); ?></div>
</div>
<?php $wp_reset_postdata(); ?>

 

③ カテゴリのリンクを作成する

ここから本題です。②の前にカテゴリのリンクを作成します。

<?php 
	$this_url = get_permalink( $post->ID );
	$tax1 = 'color'; //TAX1に自由なタクソノミ名を設定
	$tax2 = 'form'; //TAX2に自由なタクソノミ名を設定
	if ( isset( $_GET[$tax1] ) ) $tax1_get = $_GET[$tax1]; else $tax1_get = 'all'; //URLパラメータを取得
	if ( isset( $_GET[$tax2] ) ) $tax2_get = $_GET[$tax2]; else $tax2_get = 'all'; //URLパラメータを取得
	$tax1_terms = get_terms( $tax1, '&hide_empty=true' );
	if ( $tax1_terms ){ 
		$current = '';
		if ( $tax1_get == 'all' ) $current = 'current';
		$tax1_term_items = "t" .'<li><a href="'.$this_url.'?'.$tax1.'=all&'.$tax2.'='.$tax2_get.'" title="View all '.$tax1.'" class="'.$current.'">All '.$tax1.'</a></li>'. "n";
		foreach( $tax1_terms as $tax1_term ){
			$current = '';
			if ( $tax1_get == $tax1_term->slug ) $current = 'current';
			$tax1_term_items .= "t" .'<li><a href="'.$this_url.'?'.$tax1.'='.$tax1_term->slug.'&'.$tax2.'='.$tax2_get.'" title="'.$tax1_term->name.'" class="'.$current.'">' .esc_html( $tax1_term->name ). '</a></li>'. "n";
		}
	}
	$tax1_term_items = '<ul id="tax1">' ."n". $tax1_term_items. '</ul>' ."n";
	echo $tax1_term_items;

	$tax2_terms = get_terms( $tax2, '&hide_empty=true' );
	if ( $tax2_terms ){ 
		$current = '';
		if ( $tax2_get == 'all' ) $current = 'current';
		$tax2_term_items = "t" .'<li><a href="'.$this_url.'?'.$tax1.'='.$tax1_get.'&'.$tax2.'=all" title="View all '.$tax2.'" class="'.$current.'">All '.$tax2.'</a></li>'. "n";
		foreach( $tax2_terms as $tax2_term ){
			$current = '';
			if ( $tax2_get == $tax2_term->slug ) $current = 'current';
			$tax2_term_items .= "t" .'<li><a href="'.$this_url.'?'.$tax1.'='.$tax1_get.'&'.$tax2.'='.$tax2_term->slug.'" title="'.$tax2_term->name.'" class="'.$current.'">' .esc_html( $tax2_term->name ). '</a></li>'. "n";
		}
	}
	$tax2_term_items = '<ul id="tax2">' ."n". $tax2_term_items. '</ul>' ."n";
	echo $tax2_term_items;
?>

※特定のタクソノミに絞られている環境で、好みのデザインを適用するイメージで書いてますので、ループさせずに似たような処理を繰り返していますが、不特定多数のタクソノミで絞り込んでいくようなカタログサイトだったらadd_query_argなどの関数を使ってループさせた方が吉です。

出力したカテゴリはたぶんこんな感じ↓になるはず。

<ul id="tax1">
	<li><a href="http://example.com/items?color=all&form=all" title="View all color" class="current">color</a></li>
	<li><a href="http://example.com/items?color=red&form=all" title="レッド" class="">red</a></li>
	<li><a href="http://example.com/items?color=blue&form=all" title="ブルー" class="">blue</a></li>
	<li><a href="http://example.com/items?color=green&form=all" title="グリーン" class="">green</a></li>
</ul>
<ul id="tax2">
	<li><a href="http://example.com/items?color=all&form=all" title="View all form" class="current">form</a></li>
	<li><a href="http://example.com/items?color=all&form=square" title="square" class="">square</a></li>
	<li><a href="http://example.com/items?color=all&form=circle" title="circle" class="">circle</a></li>
	<li><a href="http://example.com/items?color=all&form=triangle" title="triangle" class="">triangle</a></li>
</ul>

$_GET[ $tax ]でパラメータを取得し、表示されているカテゴリのaタグのclassにcurrentを付与してます。上はパラメータが何も付いていないか、allが選択されている場合です。もし現在選択されているcurrentがblueとtriangleだとすると、以下のように代入されます。
#tax1↓
href=”~/items?color=all&form=triangle” class=””
href=”~/items?color=red&form=triangle” class=””
href=”~/items?color=blue&form=triangle” class=”current
href=”~/items?color=green&form=triangle” class=””

#tax2↓
href=”~/items?color=blue&form=all” class=””
href=”~/items?color=blue&form=square” class=””
href=”~/items?color=blue&form=circle” class=””
href=”~/items?color=blue&form=triangle” class=”current

④ tax_Queryにパラメータを代入してやる

最後にWP_Queryのtax_queryにカスタムタクソノミのパラメータを放り込んでやる必要があります。②の$argsを下記のように補完してやります。

<?php
	$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
	$args = array(
		'post_type' => 'item', //自由なポストタイプを設定
		'paged' => $paged,
	);
	if ( $tax1_get !== 'all' ) { 
		$tax1_arg = array(
			'taxonomy' => $tax1,
			'field' => 'slug',
			'terms' => $tax1_get,
		);
	} else {
		$tax1_arg = '';
	}
	if ( $tax2_get !== 'all' ) { 
		$tax2_arg = array(
			'taxonomy' => $tax2,
			'field' => 'slug',
			'terms' => $tax2_get,
		);
	} else {
		$tax2_arg = '';
	}
	if ( !empty($tax1_arg) || !empty($tax2_arg) ){
		$args['tax_query'] = array(
			$tax1_arg, $tax2_arg
		);
	}
?>

 


 

PHPの記述まとめ

phpの記述をまとめると次のようになります。適当にカスタマイズして下さい。post_typeをpostにタクソノミ名をcategoryとpost_tagにすれば、従来の投稿でも使えます。

<?php 
	//カテゴリのリンクを作成する
	$this_url = get_permalink( $post->ID );
	$tax1 = 'color'; //TAX1に自由なタクソノミ名を設定
	$tax2 = 'form'; //TAX2に自由なタクソノミ名を設定
	if ( isset( $_GET[$tax1] ) ) $tax1_get = $_GET[$tax1]; else $tax1_get = 'all'; //URLパラメータを取得
	if ( isset( $_GET[$tax2] ) ) $tax2_get = $_GET[$tax2]; else $tax2_get = 'all'; //URLパラメータを取得
	$tax1_terms = get_terms( $tax1, '&hide_empty=true' );
	if ( $tax1_terms ){ 
		$current = '';
		if ( $tax1_get == 'all' ) $current = 'current';
		$tax1_term_items = "t" .'<li><a href="'.$this_url.'?'.$tax1.'=all&'.$tax2.'='.$tax2_get.'" title="View all '.$tax1.'" class="'.$current.'">All '.$tax1.'</a></li>'. "n";
		foreach( $tax1_terms as $tax1_term ){
			$current = '';
			if ( $tax1_get == $tax1_term->slug ) $current = 'current';
			$tax1_term_items .= "t" .'<li><a href="'.$this_url.'?'.$tax1.'='.$tax1_term->slug.'&'.$tax2.'='.$tax2_get.'" title="'.$tax1_term->name.'" class="'.$current.'">' .esc_html( $tax1_term->name ). '</a></li>'. "n";
		}
	}
	$tax1_term_items = '<ul id="tax1">' ."n". $tax1_term_items. '</ul>' ."n";
	echo $tax1_term_items;
	$tax2_terms = get_terms( $tax2, '&hide_empty=true' );
	if ( $tax2_terms ){ 
		$current = '';
		if ( $tax2_get == 'all' ) $current = 'current';
		$tax2_term_items = "t" .'<li><a href="'.$this_url.'?'.$tax1.'='.$tax1_get.'&'.$tax2.'=all" title="View all '.$tax2.'" class="'.$current.'">All '.$tax2.'</a></li>'. "n";
		foreach( $tax2_terms as $tax2_term ){
			$current = '';
			if ( $tax2_get == $tax2_term->slug ) $current = 'current';
			$tax2_term_items .= "t" .'<li><a href="'.$this_url.'?'.$tax1.'='.$tax1_get.'&'.$tax2.'='.$tax2_term->slug.'" title="'.$tax2_term->name.'" class="'.$current.'">' .esc_html( $tax2_term->name ). '</a></li>'. "n";
		}
	}
	$tax2_term_items = '<ul id="tax2">' ."n". $tax2_term_items. '</ul>' ."n";
	echo $tax2_term_items;
	//tax_Queryにパラメータを代入
	$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
	$args = array(
		'post_type' => 'item', //自由なポストタイプを設定
		'paged' => $paged,
	);
	if ( $tax1_get !== 'all' ) { 
		$tax1_arg = array(
			'taxonomy' => $tax1,
			'field' => 'slug',
			'terms' => $tax1_get,
		);
	} else {
		$tax1_arg = '';
	}
	if ( $tax2_get !== 'all' ) { 
		$tax2_arg = array(
			'taxonomy' => $tax2,
			'field' => 'slug',
			'terms' => $tax2_get,
		);
	} else {
		$tax2_arg = '';
	}
	if ( !empty($tax1_arg) || !empty($tax2_arg) ){
		$args['tax_query'] = array(
			$tax1_arg, $tax2_arg
		);
	}
	//クエリを出力
	$wp_query = new WP_Query();
	$wp_query->query( $args );
	while ( $wp_query->have_posts() ) : $wp_query->the_post();
?>
<div class="post">
	<a href="<?php echo get_permalink( $post->ID );?>" title="<?php echo get_the_title( $post->ID );?">
		<h2><?php the_title( ); ?></h2>
		<div class="excerpt"><?php the_excerpt( ); ?></div>
	</a>
</div>
<?php endwhile; ?>
<div class="page-navigation">
    <div class="older"><?php previous_posts_link( '&laquo; 前へ' ); ?></div>
    <div class="newer"><?php next_posts_link( '次へ &raquo;' ); ?></div>
</div>
<?php wp_reset_postdata(); ?>

Your Comment

コードの記述は<pre>または<code>タグで括って下さい。自動的にエスケープされます。

 

右の文字を入力して下さい captcha

7 comments

  1. ku

    Oct 9, 2014

    はじめまして。

    まさに探していた内容で試してみたのですが、
    うまくいかず、分からないことがあるので教えていただけると嬉しいです。

    カスタム投稿games
    カスタムタクソノミー gamelist
    ターム a , b , c
    カスタムタクソノミー gameyear
    ターム 2014 , 2015

    gamelistとgameyearは必ず一つ選択するようになっている。

    作成したいのは、
    gamelist のターム a のターム 2014 とターム 2015 を固定ページaaaにて表示
    gamelist のターム b のターム 2014 とターム 2015 を固定ページbbbにて表示
    gamelist のターム c のターム 2014 とターム 2015 を固定ページcccにて表示

    「href=”~/aaa?gamelist=a&gameyear=2014” class=”current”」
    「href=”~/aaa?gamelist=a&gameyear=2015” class=”current”」
    と表示はされますが、クリックすると表示されなかったり、全部表示されたりとうまく表示されません。

    また、表示される項目は例題だとリスト形式でタイトルを取得している形ですが、


    タイトル
    項目3
    項目4
    項目5
    項目6

    ・上記のようなtableで6項目表示
    ・それらはAdvanced Custom Fieldsで入力したもの
    ・Advanced Custom Fieldsで入力した日付(gamedate)で新しい日付→古い日付の順で並べ替えをしたい

    質問ばかりで申し訳ないのですが、あと一歩のところ頑張りたいのでよろしくお願いいたします。

    返信する
    • Mizuho Ogino

      Oct 9, 2014

      こんにちわ。

      3つのページではそれぞれタクソノミひとつは固定されているわけですね。それでしたら、ここで書いているものよりも少し簡単にすることができます。きっちり検証してませんが、これで行けるのではないでしょうか。

      <?php
          $this_url = get_permalink( $post->ID );
      
          $tax1 = 'gamelist'; //TAX1に自由なタクソノミ名を設定
          if (is_page( 'aaa' )){
              $tax1_get = 'a';
          } elseif (is_page( 'bbb' )){
              $tax1_get = 'b';
          } elseif (is_page( 'ccc' )){
              $tax1_get = 'c';
          }
      
          $tax2 = 'gameyear'; //TAX2に自由なタクソノミ名を設定
          if ( isset( $_GET[$tax2] ) ) $tax2_get = $_GET[$tax2]; //URLパラメータを取得
          $terms = get_terms( $tax2, '&hide_empty=true' );
          if ( $terms ){ 
              foreach( $terms as $term ){
                  $current = '';
                  if ( empty ( $tax2_get ) ) $tax2_get = $term->slug; //未指定の場合、タームの最上位をデフォルトに設定
                  if ( $tax2_get == $term->slug ) $current = 'current';
                  echo '<a href="'.$thisurl.'?'.$tax2.'='.$term->slug.'" title="'.$term->name.'" class="'.$current.'">' .$term->name. '</a>'. "\n";
              }
          }
      
          $args = array(
              'post_type' => 'games', //自由なポストタイプを設定
              'paged' => $paged,
              'meta_key' => 'gamedate', //ソートキーに指定するカスタムフィールド
              'orderby' => 'meta_value',
              'order' => 'ASC',  //降順はDESC
              'tax_query' => array(
                  array( 
                      'taxonomy' => $tax1,
                      'field' => 'slug',
                      'terms' => $tax1_get,
                  ), array(
                      'taxonomy' => $tax2,
                      'field' => 'slug',
                      'terms' => $tax2_get,
                  ),
              ),
          );
          $wp_query = new WP_Query();
          $wp_query->query( $args );
          while ( $wp_query->have_posts() ) : $wp_query->the_post(); 
      ?>    
      <div class="post">
      <h1><?php the_title( $post->ID ); ?></h1>
      <div class="date">
      <?php 
          $date = get_post_meta( $post->ID, 'gamedate', true );
           echo date("Y/m/d",strtotime( $date ));
      ?>
      </div>
      </div>
      <?php endwhile; ?>
      <div class="page-navigation">
          <div class="older"><?php previous_posts_link( '« 前へ' ); ?></div>
          <div class="newer"><?php next_posts_link( '次へ »'); ?></div>
      </div>

    • ku

      Oct 9, 2014

      早速のご回答、ありがとうございます!

      上記記述をpage-aaa.phpに記述して試したのですが、
      21行目の

      echo '<a href="'.$thisurl.'?'.$tax2.'='.$term- rel="nofollow">slug.'" title="'.$term->name.'" class="'.$current.'" rel="' .$term->slug. '">' .$term->name. '</a>'. "\n";

      の部分が「Parse error: syntax error, unexpected ‘=’, expecting ‘,’ or ‘;’ 」というエラーが出ます。

      あとエラーが出て見れてないのですが、説明がうまく伝わっていないかもしれないです。
      http://www.wasedabbc.org/game/tokyo-6-spring/
      上記サイトのように、例えばタームaの内容(上記サイトだと春季リーグ戦)をgameyear(2014、2015)ごとに表示したいです。
      その際、表示した内容の上側にカスタムタクソノミーgameyearのタームの名前「2014年」「2015年」とリンク表示させたいです。
      タームごとの年別表示をしたいのですが、調べてもできないようなので、年度のカスタム分類を作ったのです。
      それをうまく表示させる理想のものがこちらの記事でした。
      どうぞよろしくお願いいたします。

    • Mizuho Ogino

      Oct 9, 2014

      笑)wordpressのnofollowフィルターが掛かってるんですね。

      ご覧の通り「$term->slug」に「 rel=”nofollow”」が無理矢理挟まってます。
      で、そのエラーの箇所が2014 2015とリンクを吐き出すところです。ちょちょっとマークアップすれば参考サイトのようにセレクタにもできるかと思います。

      ひとつ前のコメント内のコードを見直して上書きしておきました。お試しください。

    • ku

      Oct 10, 2014

      すぐに回答していただきありがとうございました。

      バッチリと表示されました。
      思うようにできず、1か月ほど試行錯誤していたので本当に助かりました。
      本当に本当にありがとうございます!!!

      それでまた質問なんですが、2014年の内容が表示されているときに「2014年」、2015年の内容が表示されているときに「2015年」と内容の上に表示させたいのですが、

      <h3><?php echo esc_html( $term->name ); ?>オープン戦</h3>

      だとどちらも「2015年」と表示されてしまいます。

      それと。。。
      >ちょちょっとマークアップすれば参考サイトのようにセレクタにもできるかと思います。
      ご教授いただけるとありがたいです。

      質問ばかりで申し訳ないのですが、どうぞよろしくお願いいたします。

    • Mizuho Ogino

      Oct 10, 2014

      表示中のtax2(gameyear)は$tax2_getで取得していますので、その$tax2_getが取得されているところより下であればgameyearのタイトルも出力できます。

      ただし$tax2_getはスラッグですので、再度「get_term_by( ‘slug’, $tax2_get, $tax2 )」としてカテゴリ情報を取得する行程が必要です。以下、動作未検証です。

      <?php
          $this_url = get_permalink( $post->ID );
          $tax1 = 'gamelist'; //TAX1に自由なタクソノミ名を設定
          if (is_page( 'aaa' )){
              $tax1_get = 'a';
          } elseif (is_page( 'bbb' )){
              $tax1_get = 'b';
          } elseif (is_page( 'ccc' )){
              $tax1_get = 'c';
          }
          $tax2 = 'gameyear'; //TAX2に自由なタクソノミ名を設定
          if ( isset( $_GET[$tax2] ) ) $tax2_get = $_GET[$tax2]; //URLパラメータを取得
          $terms = get_terms( $tax2, '&hide_empty=true' );
          if ( $terms ){ 
              $select = '<select name="yearselect" onChange="location.href=value;">'. "\n";
              foreach( $terms as $term ){
                  $selected = '';
                  if ( empty ( $tax2_get ) ) $tax2_get = $term->slug; //未指定の場合、タームの最上位をデフォルトに設定
                  if ( $tax2_get == $term->slug ) $selected = ' selected="selected"';
                  $select .= "\t".'<option value="'.$thisurl.'?'.$tax2.'='.$term->slug.'"'.$selected.'>' .esc_html($term->name). '</option>'. "\n";
              }
              $select .= '</select>'. "\n";
          }
          echo $select;
      ?>
      <h3><?php echo esc_html(get_term_by( 'slug', $tax2_get, $tax2 )->name); ?>オープン戦</h3>
      <?php //以下略 ?>

    • KU

      Oct 10, 2014

      迅速に対応していただいてありがとうございました!

      バッチリどちらも表示されました。
      もっとこちらに早くいきついていたらなあ。。。と思うくらい理想的な表示ができました。
      本当にありがとうございました。
      また分からないことがあったらお世話になるかもしれませんが、よろしくお願いいたします。