2014
6
19
WordPressのアーカイブページを人気順などで並び替えるボタンをつける

カテゴリやタグの記事一覧(アーカイブ)ページは、デフォルトでは公開日が新しい順に並んでいますが、公開日の古い順や、WP-PostViewsというプラグインを利用した閲覧数順などの並べ替えボタンをつけてみよう!という内容です。


この記事をスマホで読む

完成図

140619-1

カテゴリとタグのアーカイブページに4種類の並び替えボタン(CSSでテキストリンクっぽくしてます)をつけてみました。

140619-2

スマホ版はこんな感じになっています。

きっかけ

記事終わりにカテゴリ別の人気記事を置くために一時期使っていたこちらのプラグインなのですが、WordPress.comの統計情報を使うほうが理想に近かったため、途中で切り替えてしまいました。

しかしながら、ダッシュボードの投稿一覧に閲覧数が出たり、並び替えられたりと管理面で気に入っていたので、稼働させたままでした。

そんな折、この記事を拝見しまして。

なっ…!(( ゚д゚)ガタッ

インストールして有効化するだけで、あとは get_posts() で自由に…!?そ、そんなことが出来るのかッ…!一生懸命ダッシュボードのプラグイン編集からサムネイルが出るようにカスタマイズとかしてた…!こっちとこっちで違う画像の大きさにしたいから片方はCSSで画像サイズ整えたりとかしてた…w

などと恥ずかしい思い出が噴出するなか調べてみたところ、このプラグインは at_wp_postmeta というテーブル内の meta_key に views というフィールドを作り、そこの meta_value にカウント数を格納していってくれるのだそう。ほうほう。

テーブル構造を図で見てみると勉強になります。
140619-3

phpMyAdminで、at_wp_postmeta テーブルを ‘meta_key’=’views’ で絞ってみた結果のキャプチャ。こんな感じで格納されているわけですね!これを使って WP_Query()get_posts() などで、

array(
	'meta_key' => 'views',
	'orderby' => 'meta_value_num'
);

こんな感じのパラメータを指定してあげれば閲覧数の多い順に取り出せる、と…。なんて便利なんだ。並び順はデフォルトで降順なので、「’order’ => ‘DESC’」は省略できるんですね。

ところで、フィールド名は meta_value なのに、meta_value_num というのはどこから出てきたのだろう、と疑問に思ったのですが。

こちらに書いてありました。英語だったのでざっくり解釈するに、meta_value_num と書くことで、meta_value を数値として扱えるようになるみたいです。確かにテーブル構造では meta_value は LONGTEXT 型でした。

などなど、かなり使い勝手が良さそうな WP-PostViews の metaデータ。これを使ってアーカイブを並び替える方法を紹介しているこちらの記事も拝見し、

これ良いな…!こういうの、やってみたかった…!わたしはこれを、

pre_get_posts() でやってみたーい!!!\\└(‘ω’)┘//

と思ったという、ここまでが前置きです。すごい長くてすみません。

事前準備

パーマリンクはデフォルト以外で

今回はGET変数を使った方法を紹介しますので、http://xxx.com/?p=1 という形のパーマリンクではうまく動きません。「?」の入ったパーマリンクを使いたい方(若しくは、並び替えたときURLに「?sort=newer」などとつくのが嫌な方)はPOST変数を使うと実装できると思います。

構成を決める

まずは Codex を見て、どのページに並び替えボタンを適用させたいのかということを決定します。今回はこのブログに実装したものを例にして

  • カテゴリアーカイブ … is_category()
  • タグアーカイブ … is_tag()

このふたつだけで紹介しますが、他にも日付や作成者のアーカイブ、検索ページにも実装が可能です。

アーカイブページのカスタマイズ

140619-4

並び替えからはちょっと逸れるのですが、ついでに特定のアーカイブページを表示したときに「○件」と表示されるようにしちゃいます。

こちらを参考にさせていただいて、アーカイブページで読み込まれるテンプレート(一般的には index.php か、header.php あたりでしょうか)の、メインループ外にこのように書いてみました。

<?php
if ( is_archive() || is_search() ) { //アーカイブか検索ページだったら
	global $wp_query;
	$total_results = $wp_query->found_posts; //件数を取得しておく
}
?>

<?php if ( is_archive() ): //アーカイブページ ?>
	<?php if ( is_category() || is_tag() ): //カテゴリ,タグアーカイブ ?>
		<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 endif; ?>
			//並び替えボタンの実装
		</div>
	<?php elseif( is_date() ): //日付アーカイブ ?>
		<div class="result">
			<?php if( $year ): echo $year ?>年<?php endif; ?>
			<?php if( $monthnum ): echo $monthnum ?>月<?php endif; ?>
			<?php if( $day ): echo $day ?>日<?php endif; ?>
			:<?php echo $total_results; ?>件
		</div>
	<?php endif; ?>
<?php endif; ?>

<?php if ( is_search() ): //検索 ?>
	<div class="result">"<?php the_search_query(); ?>" で検索した結果:<?php echo $total_results; ?>件</div>
<?php endif; ?>

カテゴリ・タグ・日付アーカイブと、検索結果ページに件数が出るようにしています。ハイライト部分に後で並び替え用のボタンを実装する予定ですが、ボタン無しならとりあえずこのままでも動くと思います。

ちなみに is_archive() にはカテゴリ、タグ、日付の他に作成者のページが含まれますが、このブログでは作成者はひとりしかいないので、上記コードでは作成者ページには特に何もしていません

並び替えボタンの実装

GET変数の動き

まずは仕組みの説明のために、例として上記コードのハイライト部分に

<form method="get" action="">
	<input type="hidden" name="sort" value="sample"/>
	<input type="submit" value="サンプル" />
</form>

こう書いて、試しにカテゴリアーカイブを見てみると、ボタンができてます。

140619-5

このボタンを押すと、URLがこのように遷移します。

http://ateitexe.com/category/xxx/
 ↓
http://ateitexe.com/category/xxx/?sort=sample

3行目の value がボタン内の文字列で、1行目の action で指定した URL(空欄の場合は同じページ)に遷移します。このとき、2行目の内容が変数としてURLの最後にくっつきます。

<form method="get" action="">
	<input type="submit" name="sort" value="サンプル" />
</form>

ちなみに、これだけでも http://ateitexe.com/category/xxx/?sort=サンプル という形で使えるのですが、URLに日本語が入るのが個人的に気持ち悪くて、hidden要素を持たせています。お好みでどうぞ。ボタン内の文字列を英語にしてもいいかも。

$sortset = $_GET['sort'];

URL末尾の「?sort=○○○」はこのように書くことで取得できますが、信頼できない変数なので、

$sortset = isset($_GET['sort']) && is_string($_GET['sort']) ? $_GET['sort'] : '';

このようにチェック処理をして取得します。上記の例だと sample という文字列が入ることになります。

こちらを参考にさせていただいています

こんな要領で、最終的には並び替えたい条件の数だけボタンを作り、そのボタンごとに違う文字列を持たせて、それを使って条件分岐させていきます。

  • 日付が新しい順 … newer
  • 日付が古い順 … older
  • 閲覧数が多い順 … popular
  • 閲覧数が少ない順 … unpopular

今回はこんな想定で実装しようと思います!(不人気記事は需要ないかもしれませんが、一応w)

遷移先を指定

このブログの場合、カテゴリとタグのアーカイブページのURLは、それぞれ

http://ateitexe.com/category/xxx/
http://ateitexe.com/tag/xxx/

で、これが2ページ目以降になると

http://ateitexe.com/category/xxx/page/2/

このようになります。form の遷移先を空欄にしたまま、この場所から並び替えボタンを押すと、

http://ateitexe.com/category/xxx/page/2/?sort=older

のように、同じURLに遷移してしまうので、違う並び順を選んでも、いきなり2ページ目に行ってしまうんです。これは気持ち悪いよなーと思ったので、2ページ目以降でボタンを押されても、1ページ目に飛ぶようにURLを指定します。

<?php
$url = explode('/', $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
$url_str ='http://'.$url[0].'/'.$url[1].'/'.$url[2].'/';
?>
<form method="get" action="<?php echo $url_str ?>">
	<input type="hidden" name="sort" value="newer"/>
	<input type="submit" value="新しい順" />
</form>

こう書いてみます。2行目で( http:// を抜いた)現在のURLを「/」で分割して $url という配列に格納しています。

$url[0] → ateitexe.com
$url[1] → category(tag)
$url[2] → xxx(スラッグ)
$url[3] → (あれば)page
$url[4] → (あれば)2など

すると配列の中身はこのようになるので、$url[2] までを使ってURLを組み立てて $url_str という変数に入れておき(3行目)、そいつを action の遷移先に指定(5行目)してやれば、現在地が1ページ目でも2ページ目以降でも、アーカイブのトップに遷移できます。

違うパーマリンク設定の場合や、子カテゴリなどがあると構造が違うかもしれませんので適宜変更してください。

CSSでテキストリンク風に

140619-6

ボタンのままでも良いのですが、テキストリンクっぽくしてみました。

<?php
$url = explode('/', $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
$url_str ='http://'.$url[0].'/'.$url[1].'/'.$url[2].'/';
$sortset = isset($_GET['sort']) && is_string($_GET['sort']) ? $_GET['sort'] : '';
?>
<form method="get" action="<?php echo $url_str ?>">
	<input type="hidden" name="sort" value="newer"/>
<?php if ( $sortset == 'newer' ): ?>
	<input type="submit" class="sort_current" value="新しい順" />
<?php else: ?>
	<input type="submit" value="新しい順" />
<?php endif; ?>
</form>

4行目でGET変数を取得して、8行目にて現在地かどうかを判別します。一致したときだけ sort_current というクラスを付加する形で、ボタンを出し分けます。

style.css

.result form{display: inline!important;}
.result input[type="submit"]{
	color: #aa9a85;
	padding: 0;
	margin: 0;
	box-shadow: none!important;
	background: none!important;
	border: none!important;
	font-size: 95%;
	text-decoration: underline;
	cursor: pointer;
}
.sort_current{
	font-weight: bold!important;
	text-decoration: none;
}

全体を div class=”result” で括っているので、その中に入っている form に適用する、という形で書いてみます。元のボタンのCSSを打ち消す形になるのでテーマによって違うとは思いますが、わたしの環境ではこんな感じで。現在位置は太字で下線なしにしました。

最終コード

ボタンを4つつけて、それぞれの区切りに「|」を入れてみます。

<?php
$url = explode('/', $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
$url_str ='http://'.$url[0].'/'.$url[1].'/'.$url[2].'/'; //URL生成
$sortset = isset($_GET['sort']) && is_string($_GET['sort']) ? $_GET['sort'] : ''; //取得
?>
並び替え:
<form method="get" action="<?php echo $url_str ?>">
	<input type="hidden" name="sort" value="newer"/>
<?php if ( $sortset != 'older' && $sortset != 'popular' && $sortset != 'unpopular' ): ?>
	<input type="submit" class="sort_crt" value="新しい" />
<?php else: ?>
	<input type="submit" value="新しい" />
<?php endif; ?>
</form>
|
<form method="get" action="<?php echo $url_str ?>">
	<input type="hidden" name="sort" value="older"/>
<?php if ( $sortset == 'older' ): ?>
	<input type="submit" class="sort_crt" value="古い" />
<?php else: ?>
	<input type="submit" value="古い" />
<?php endif; ?>
</form>
|
<form method="get" action="<?php echo $url_str ?>">
	<input type="hidden" name="sort" value="popular"/>
<?php if ( $sortset == 'popular' ): ?>
	<input type="submit" class="sort_crt" value="閲覧多" />
<?php else: ?>
	<input type="submit" value="閲覧多" />
<?php endif; ?>
</form>
|
<form method="get" action="<?php echo $url_str ?>">
	<input type="hidden" name="sort" value="unpopular"/>
<?php if ( $sortset == 'unpopular' ): ?>
	<input type="submit" class="sort_crt" value="閲覧少" />
<?php else: ?>
	<input type="submit" value="閲覧少" />
<?php endif; ?>
</form>

ハイライト部分は「日付が新しい順」にするか判別する部分ですが、さっきは

<?php if ( $sortset == 'newer' ): ?>

でしたが、ここでは変えています。GET変数は性質上ユーザーが容易に変更できてしまうものですし、ボタン以外からアーカイブページに遷移してきたときは空白になるなど、指定した4種類以外の値をとる可能性が十分考えられるため、「older, popular, unpopular ボタンのどれでもないとき」という条件にしています。「日付が新しい順」をデフォルトとする、という感じでしょうか。

pre_get_posts() で並び替え

ここまでで、やっとボタンができました!後はボタンを押したときの変数に合わせて並び替えをしてあげるだけです。

こちらを参考にさせていただいています。このページもう何回読んでることか…!いつもありがとうございます!

functions.php

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

	if ( $query->is_category() || $query->is_tag() ) {
		$sortset = isset($_GET['sort']) && is_string($_GET['sort']) ? $_GET['sort'] : '';
		if ( $sortset != 'older' && $sortset != 'popular' && $sortset != 'unpopular' ) {
			$query->set( 'orderby', 'date' );
		} elseif ( $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' );
		}
		return;
	}
}
add_action( 'pre_get_posts', 'SortArchive' );

このように書いてみました。(記述がおかしかったらご指摘くださると有難いです!)

5行目はカテゴリとタグのアーカイブページに適用するという意味で、6行目で変数を取得、7行目ハイライトが先述した「デフォルト」の条件分岐になります。あとは、それぞれ変数の中身に従って並び替える条件を変えてあげる、という形になっています。

以上です!いかがでしたでしょうか。もうちょっと手を加えれば、コメントの多い順とか少ない順とか、かなり色々できると思いますので興味のある方は試してみてくださいー!

公開日:

  • RSSを登録
  • 346 follow us in feedly
  • このエントリーをはてなブックマークに追加



コメントを残す




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


back to top