かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

もっと簡単版!WordPress 投稿の並び順の条件(orderby)を複数にして、それぞれの並べ方(order)を別々に指定したい。

以前、pre_get_posts内で独自の値を$wp_queryにセットしてorderbyを複数にして、それぞれ別のorderにする方法を書いていました。

最近検索していたら、実はもっと簡単に実装できたことが判明しました。

orderbyに配列で条件と並べ方を渡すことができた!

以前のコード

<?php //function.php
function change_posts_query( $query ) {
  if( is_archive() ) {
    $query->set('meta_key', 'release_time');
    $query->set('orderby', 'meta_value_num date');
    $query->set('order', 'DESC');
    // 独自のキーを作って orderを指定する
    // orderby の指定の仕方と合わせて スペース区切りにすることにします
    $query->set('my_orders', 'ASC DESC');
  }
}
add_action('pre_get_posts', 'change_posts_query');

// ORDER BY節を変更するフィルター
add_filter( 'posts_orderby','change_posts_orderby', 10, 2 );
function change_posts_orderby($orderby, $query) {
  $orders = array_filter( explode(' ', strtoupper( $query->get('my_orders') )) );
  if( count($orders) > 0 ) {
    $orderby_arg = array();
    $order_arg = array('DESC', 'ASC');
    // $orderby文のDESC, ASC を削除して , で分割
    foreach( explode(',', str_replace($order_arg, '', $orderby)) as $i => $the_orderby ) {
      if( isset($orders[$i]) && in_array($orders[$i], $order_arg) ) {
        // 対応する order がある時
        $orderby_arg[] = trim($the_orderby) . ' ' . $orders[$i];
      } else {
        // 対応する order が無い あるいは DESC, ASCでない場合は デフォルト値 DESC を使う
        $orderby_arg[] = trim($the_orderby) . ' DESC';
      }
    }
    // それぞれの orderby の入った配列を , で連結した文字列にする
    $orderby = implode(',', $orderby_arg);
  }  
  return $orderby;
}

↓ もっと簡単にできた版

<?php //function.php
function change_posts_query( $query ) {
  if( is_archive() ) {
    $query->set('meta_key', 'release_time');
    // orderby に orderby => order 形式の配列で条件と並び順を渡してあげればOK
    $query->set('orderby', array('meta_value_num' => 'ASC', 'date' => 'DESC') );
    // order は不要
    // $query->set('order', 'DESC');
  }
}
add_action('pre_get_posts', 'change_posts_query');

実はすごく簡単にできたのでした...
当時 order の方に配列で渡してみて上手く動作しなかったのでできないのか―。と思ったのですが、まさかorderbyの方に配列で渡しておけばよかったとは...

各記事(Single)ページで前後のページのリンクもアーカイブの並び順にしたい場合

先のコードをfunction.phpに書いておけば、アーカイブページではorderbyに渡した値通りに並んで表示されますが、並び順の条件によっては各記事(Single)ページの前の記事・後の記事のリンクはこの並び順にはなっていません。
この前後ページのリンクもアーカイブと同じ順番にしたい時は次の記事を参考にnext previousのリンクを作成する部分をfilterを使って頑張るしか無さそうです。


[参考]