ワードプレスのカスタムフィールドの配列の値での投稿の取得とソート
今回は、なかなかマニアックなネタになります。僕が作っているワードプレステーマは、なるべくデータベースを散らかしたくないので独自のデータ(カスタムフィールド値など)はなるべく配列でデータベースに保存するようにしています。
それはいいのですが、カスタムフィールドの配列の中の1つの値でソートして投稿データを取得したいシチュエーションが出てきて少しハマりました。既存のワードプレス関数のget_postsに少し工夫をしたのでそれを紹介したいと思います。ネタバレですが、get_postsを2回使います。
Contents
1、下準備としてget_postでmeta_keyを指定して全件とる
まずは下準備。meta_key、numberpostsのみを指定してget_postsします。
例として、「hoge」というカスタムフィールドが設定されていて、その中の配列に「foo」というキーが設定されているとしましょう。こんな感じですね。
array( 'hoge' => array( 'foo' => 値; ) )
まずは、meta_valueが配列であることは忘れましょう。僕も最初meta_queryなどを使って配列を比較しようとしたんですが、配列がシリアライズされた文字列を比較することになるので挫折しました。
$key = 'hoge'; $posts = get_posts( array( 'numberposts' => -1, 'meta_key' => $key ));
こーすることで、とりあえず$postsには「hoge」というカスタムフィールドが設定されている投稿全部が入っていますよね。うんうん。
ここまではOKですよね?次がポイントです。
2、取ってきたもので連想配列を作る
投稿IDと並び替えたい値のみのシンプルな連想配列を作成します。これにさっきの$postsを使います。
foreach( $posts as $post ){ $foo = get_post_meta( $post->ID, $key, true ); if( isset( $foo['foo'] ) ) $id[$post->ID] = $foo['foo']; }
こうすることで、「投稿ID」と「foo」が連想配列として関連づけされます。
$idの中身はこうなっているはずです。
$id = array( '投稿ID' => 'fooの値', '投稿ID' => 'fooの値', '投稿ID' => 'fooの値', '投稿ID' => 'fooの値', . . . );
3、配列を並び替えて任意の長さにカットし文字列にする
今度は、先ほどの連想配列からカンマ区切りのソートされた投稿IDの文字列を作成します。
手順は以下の通りです。
- phpの配列ソート系の関数を使って(今回はarsortを使用)並び替えします。
- 並び替えたら値は不要なので、array_keysでキーのみの配列に変換します。
- array_sliceで任意の長さにカットします。
- implodeでカンマ区切りの文字列に変換します。
arsort( $id ); $id = array_keys( $id ); $id = array_slice( $id, 0, $numberposts, true ); $id = implode( ',', $id );
これで準備は整いました。
4、includeとpost__inを使ってもう一回get_postsする!
ここでもう一回get_postsしましょう!
先ほどの$idはカンマ区切りのソートされた投稿IDの文字列なので、それをincludeに突っ込みます。orderbyにpost__inを入れているのは、includeの順に並べる意味です。
$posts = get_posts( array( 'orderby' => 'post__in', 'include' => $id ));
これで$postsの中身は、この記事のタイトル通り、カスタムフィールドの配列の値ソートされた投稿が入っているはずです。あとは、foreachで回すなり自由にできるはずです。
まとめ
とりあえず、一連の流れをおさらい。
$key = 'hoge'; $posts = get_posts( array( 'numberposts' => -1, 'meta_key' => $key )); foreach( $posts as $post ){ $foo = get_post_meta( $post->ID, $key, true ); if( isset( $foo['foo'] ) ) $id[$post->ID] = $foo['foo']; } arsort( $id ); $id = array_keys( $id ); $id = array_slice( $id, 0, $numberposts, true ); $id = implode( ',', $id ); $posts = get_posts( array( 'orderby' => 'post__in', 'include' => $id ));
ポイントは一回でget_postsしてしまおうとしないことですかね。