[WP]カスタムフィールドの値で記事を並び替える

質問された、カスタムフィールドで設定した値で記事を並び替えて表示するサンプルを晒してみる。
オススメ度とかでランキングっぽいことしたい時に使えるのか・・・な?
やってることはarray_multisortによる多次元配列のソートです。

サンプル関数の使い方は次の通りです。

  1. 記事にソート用のカスタムフィールドを作成
  2. 10進数の半角数字で値を入力
  3. テンプレートの表示したいところにサンプルのコードを入れる

以上。
サンプルソースは用途に応じて適当に変更するといいと思います。

参考ページ

追加

  1. 他のカスタムフィールドも表示したい場合
  2. ページナビゲーションによる分割表示

functions.phpとか

function sort_post_meta($m,$c){
	$myposts = get_posts('numberposts=5&cat='.$c);
	foreach ($myposts as $post){
		$meta = get_post_custom_values($m,$post->ID);
		$out[] =array('id'=>$post->ID,'title'=>$post->post_title,'guid'=>$post->guid,'rate'=>$meta[0]);
		$ar[] =$meta[0];
	}
	array_multisort($ar,SORT_NUMERIC,SORT_DESC,$out);
	return $out;
}

sort_post_meta($meta_key,$category_id)
$meta_key:カスタムフィールドのキー(文字列)
$category_id:カテゴリーID(整数)

get_postsで指定カテゴリの記事IDを取得して、get_post_custom_valuesでカスタムフィールドの値を取得します。
先頭だけ取得して配列に入れるので、複数在る場合は他の値が無視されます。
return用の配列に記事のタイトルとか入れて、array_multisortでカスタムフィールドの値を元に並び替え、
ソートし終わったら返す。という感じ。

配列に入れてる記事情報はID・タイトル・URLだけですが、get_posts()関数で返されるオブジェクトにあるものなら何でも追加できます。
面倒なら$out[]=$post;とかにしても良い。(この場合オブジェクトになるので出力の書き方がちと変わる)
また、並び替える基準も新しくソート用の配列を作れば「カスタムフィールドの値が重複した場合にタイトルを基準にする」、とかいうことも出来ます。
その辺は用途に応じてお好みでー。
なお、日本語の場合漢字が混じってるとソートの順序が微妙なので、並び替える基準とする値はひらがな・カタカナや半角英数が良いと思います。

index.phpとかのテンプレートファイル内

$array =sort_post_meta("star",7);

foreach ($array as $arr){
	print "★$arr[rate] <a href=\"$arr&#91;guid&#93;\">".$arr[title]."</a><br />";
}

出力結果▼
カスタムフィールドの値で並び替え・サンプル出力結果

カスタムフィールドの値を数値にしとけば、下記のように応用が利く。

星の数で表現する例▼

$array =sort_post_meta("star",7);
$star = array('-','★','★★','★★★','★★★★','★★★★★');
foreach ($array as $arr){
	print "★".$star[$arr[rate]]." <a href=\"$arr&#91;guid&#93;\">".$arr[title]."</a><br />";
}

他のカスタムフィールドも表示したい場合

ソートとは別に”sample”というカスタムフィールドを記事に追加したので、これも一緒に表示したいとします。

上記のサンプルではカスタムフィールドのキーを並び替え用のものだけに限定してるので、
他のカスタムフィールドの値はどう頑張っても取得出来ません。
ですので他のカスタムフィールドも出力したい場合は以下のように変更します。

function sort_post_meta2($c){
	$myposts = get_posts('numberposts=5&cat='.$c);
	foreach ($myposts as $post){
		$meta = get_post_custom($post->ID);
		$out[] =array('id'=>$post->ID,'title'=>$post->post_title,'guid'=>$post->guid,'rate'=>$meta["rate"][0],'sample'=>$meta["sample"][0]);
		$ar[] =$meta["rate"][0];
	}
	array_multisort($ar,SORT_NUMERIC,SORT_DESC,$out);
	return $out;
}

一番重要な変更点はget_post_custom()です。
最初のサンプルで使用しているget_post_custom_value()はキー指定による値だけ返す関数でしたが、
get_post_custom()は記事に設定されているカスタムフィールドを全て配列形式で返します。

※キーの指定をしなくなるので、関数の引数はカテゴリー($c)だけになります。

get_post_customの出力結果

この配列は$metaに代入されるので、
あとは出力用の配列$outに入れる配列へ欲しいやつだけ追加すればおk。

'sample'=>$meta["sample"][0]

出力サンプル

$array =sort_post_meta2(8);
foreach ($array as $arr){
	print "★$arr[rate] <a href=\"$arr&#91;guid&#93;\">".$arr["title"]."</a><br />".$arr["sample"];
}

ページナビゲーションによる分割表示

すごい今更ですが思い出しついでに書いてみたので晒しときます…。
上のソースをベースにしてますが、ナビゲーション表示する関係で出力も全部関数内に移してあります。

//$c=カテゴリID $ppp=1ページあたりの表示数
function sort_post_meta3($c,$ppp=5){
	$myposts = get_posts('numberposts=-1&cat='.$c);
	foreach ($myposts as $post){
		$meta = get_post_custom($post->ID);
		//表示したいデータ($post=記事 $meta=カスタムフィールド)
		$out[] =array('id'=>$post->ID,'title'=>$post->post_title,'guid'=>$post->guid,'rate'=>$meta["rate"][0],'sample'=>$meta["sample"][0]);
		$ar[] =$meta["rate"][0];
	}
	$total = count($out);
	
	array_multisort($ar,SORT_NUMERIC,SORT_DESC,$out);
	
	$spm = wp_html_excerpt($_GET["spm"],3);
	$start = 0;
	$max = $ppp;
	
	if(isset($spm)&&$spm>=2){
		$start =($spm-1)*$ppp;
		$max = $s+($ppp);
		$out = array_slice($out,$start,$max);
	}else{
		$out = array_slice($out,$start,$max);
	}
	
	//出力
	foreach ($out as $arr){
		print "★$arr[rate] <a href=\"$arr&#91;guid&#93;\">".$arr["title"]."</a><br />";
	}
	
	global  $wp_rewrite;
	$paginate_base = '%_%';
	if (strpos($paginate_base, '?') || ! $wp_rewrite->using_permalinks()) {
		$paginate_format = '';
		$paginate_base = add_query_arg('spm', '%#%');
	} else {
		$paginate_format = (substr($paginate_base, -1 ,1) == '/' ? '' : '/') .
		user_trailingslashit('spm/%#%/', 'spm');
		$paginate_base .= '%_%';
	}
	//ナビゲーション
	echo paginate_links( array(
	'base' => $paginate_base,
	'format' => $paginate_format,
	'total' => $total/$ppp,
	'current' => ($spm ? $spm : 1),
	));
}

yurikoさんが書いたソースまるっと流用してますん。

2番目の引数(1ページあたりの表示数)は省略可

sort_post_meta3(8);

あんまり検証してないのでおかしいところがあったら教えてください

1件のコメント

  1. 早速のお返事ありがとうございました。
    凄い短いコードで実現していて凄いです。
    うまく動作しています、ありがとうございました。

    出力する記事の数が多い場合に、「前ページへ」や「次ページへ」(もしくはWP-PageNaviなど)を使用して
    記事を分割したいのですが無理でしょうか?

    の中に

    $array =sort_post_meta(“star”,7);
    foreach ($array as $arr){
    print “★$arr[rate] “.$arr[title].”“;
    }

    を記述すると、1つ1つの記事の中にカスタムフィールドの記事が全部含まれてしまいます。

    $myposts = get_posts(‘numberposts=5&cat=’.$c);

    みたいに表現出来たら良いのですが。
    よろしくお願いします。

    Reply
  2. すいません、codeタグ使えないの忘れてました。

    早速のお返事ありがとうございました。
    凄い短いコードで実現していて凄いです。
    うまく動作しています、ありがとうございました。

    出力する記事の数が多い場合に、「前ページへ」や「次ページへ」(もしくはWP-PageNaviなど)を使用して
    記事を分割したいのですが無理でしょうか?

    if (have_posts()) :
    while (have_posts()) : the_post();

    の中に

    $array =sort_post_meta(“star”,7);
    foreach ($array as $arr){
    print “★$arr[rate] “.$arr[title].”“;
    }

    を記述すると、1つ1つの記事の中にカスタムフィールドの記事が全部含まれてしまいます。

    $myposts = get_posts(‘numberposts=5&cat=’.$c);

    query_posts(‘cat=5&posts_per_page=10’);if (have_posts()) :
    while (have_posts()) : the_post();

    みたいに表現出来たら良いのですが。
    よろしくお願いします。

    Reply
  3. チョッパーさん>
    それはまあ、while文に入れれば繰り返されるでしょうね・・・。

    上のサンプルの関数は配列を返すので
    掲示板のページ分割処理と同じ要領でやれなくはないと思うんですが
    すごく・・・面倒ですw
    連休に入りますし、フリーのBBS等(WP-PageNaviでもいいかもしれない)を参考にソース改変するか
    プラグイン使うかする方が、私がやる気出すよりも早いかもしれませんー

    追加するとしたら連休明けになると思いますが、
    気が乗らないといつまでもやらないので、正直わかりません

    Reply
  4. こんばんは。
    すごく面倒ですか・・・。
    面倒なことを質問してしまったみたいで申し訳ありませんでした。
    get_postsにposts_per_pageがあればよかったんですけど。

    >掲示板のページ分割処理
    http://www.yuriko.net/arc/2008/08/06/navigation-2/
    ここは参考になるでしょうか?

    連休明けでも来月でも構いませんので、気が乗ったらよろしくお願いします。
    ちなみに、Tenderfeelさんの気を乗らす方法って何ですかw

    Reply
  5. チョッパーさん>

    おおーこれは便利な関数ですな!
    まだソース見てないファイル&Function Referenceに載ってない関数だったので知りませんでした。
    さすがyurikoさん、と言うべきでしょうかw
    多分使えると思うんですが試してみない事にはなんとも。

    自分に必要になると早いんですが、そうでないと全くやる気が出ません(´ー`)
    3時間くらい白紙の時間貰えたらテンション上がりますw

    Reply
  6. お返事遅くなってすいません。
    年末に向けて休みなしモードでつらいところです。
    3時間くらいの白紙の時間あったらいいですねぇ・・・。

    使えそうな関数でよかったです。
    テンションが上がったらよろしくお願いします。

    Reply
  7. こちらの記事を参考にさせていただいたのですが、1点だけどうしてもわからない部分がありますので良ければアドバイスいただきたいのですが、

    記事のソートはうまくいったのですが、ただ、表示したい項目カスタムフィールドも含めたくさんあるため、全部の項目を配列に追加するのも面倒(&カスタムフィールドを追加する方法がわからない)なので、たぶん記事中の

      面倒なら$out[]=$post;とかにしても良い。
      (この場合オブジェクトになるので出力の書き方がちと変わる)

    の部分で何とかできそうかなと思い、いろいろやってみたのですが、プログラムはほぼ素人なものでまったくうまくいきませんでした。
    「オブジェクトになるので出力の書き方がちと変わる」
    という部分、具体的にどうすればいいものでしょうか?

    Reply
  8. きうさん>>「オブジェクトになるので出力の書き方がちと変わる」件について

    関数からの返り値をvar_dump()などで全て表示してみたとき、
    arrayと出れば配列、objectと出ればオブジェクトです。

    配列とオブジェクトは構造は似たような感じなのですが、値得る時の書き方がそれぞれ以下の様に異なります。

    *配列の場合
    $var[key] = $配列が入ってる変数名 [ 配列内のキー ]

    *オブジェクトの場合
    $var->key = $オブジェクトが入ってる変数名 -> オブジェクトのキー

    中には次のように、配列にオブジェクトが入ってる場合もありますが

    Array
    (
      [post]=>Object
      (
        [id] => 4
        [title] => Welcome Themes Making
        [guid] => http://localhost/wordpress/?p=4
        [rate] => 6
      )
      ….
    )

    上記の配列を$arrayという変数に入れた場合、
    $array[post]->title と書けば値を得ることが出来ます。

    Reply
  9. ご解答ありがとうございます!
    しかし・・・
    やってみましたがうまくいきませんでした。。。。。

    初歩的な質問ばかりで申し訳ありません。

    ▼function.php

    function sort_post_meta($n,$m,$c){
    $myposts = get_posts(‘numberposts=’.$n.’$n&cat=’.$c);
    foreach ($myposts as $post){
    $meta = get_post_custom_values($m,$post->ID);
    $out[] =array(‘id’=>$post->ID,’title’=>$post->post_title,’guid’=>$post->guid,’customfieldsort’=>$meta[0]);
    $ar[] =$meta[0];
    }
    array_multisort($ar,SORT_STRING,SORT_ASC,$out);
    return $out;
    }

    以下のように、ソートに使用した以外のカスタムフィールドや、その他の項目をhtmlに表示したい場合どのようにすればよろしいでしょうか?ご教授いただければ幸いです。

    foreach ($array as $arr){
    <h1><a href=”パーマリンク”>タイトル</a></h1>
    <p>カスタムフィールド(キー:a)</p>
    }

    Reply
  10. ああ…なるほどwそのソースじゃ無理ですね。
    説明ちょっと長くなるので記事に追記しときます。

    Reply
  11. わざわざご親切にありがとうございます!

    参考にさせていただきがんばってみます。

    ほんとありがとうございました!

    Reply

Leave a Comment.