WordPressでカスタムフィールドの値を元に自然順っぽく並び替えする方法

注意

厳密な自然順の並び替え(ナチュラルソート)ではありません。WordPressで利用されているMySQL自体にナチュラルソートの機能がないようなので、あくまで擬似的なものと捉えてください。上手くいかないパターンもあると思います。

やりたいこと

テキスト型のカスタムフィールドの値を元に、各投稿をナチュラルソートしたい。

通常の昇順でやった場合

コード例

$posts= get_posts(
    array(
        'post_type' => array('custom_post_type'),
        'meta_key' => 'custom_field_key',
        'orderby' => 'meta_value',
        'order' => 'asc'
    )
);

結果
A-1
A-10
A-11
A-2
A-3
...

単純にorderをascとした場合、上記のような残念な結果となります。

ちなみに、カスタムフィールドが数値型の場合は
'orderby' => 'meta_value_num'
とすればナチュラルソートされます。

やりたい昇順

A-1
A-2
A-3
...
A-10
A-11

こんな並びにしたい。

結論

// 以下をfunction.phpに記載
function custom_orderby($orderby) {
    global $wpdb;
    $orderby = "LENGTH(".$wpdb->prefix."postmeta.meta_value) ASC, ".$wpdb->prefix."postmeta.meta_value ASC";
    return $orderby;
}

// 以下をナチュラルソートしたい箇所に記載
add_filter('posts_orderby', 'custom_orderby', 10,2);
$posts= get_posts(
    array(
        'post_type' => array('custom_post_type'),
        'meta_key' => 'custom_field_key',
        'suppress_filters' => false
    )
);

考え方

自然順っぽくするには、まずテキストの長さでソートし(桁で揃える)、その後に値でソートすることで実現できそうです。

コード上のポイント

function.phpにて、posts_orderbyをフックして独自のSQLを実行させる関数を記載します。add_filterを個別に記載しているのは、全ての投稿取得で利用するわけではないケースが多いだろう、という予測から。

また、get_posts内にて
'suppress_filters' => false
というオプションを追加しています。

get_postsで取得する場合、このオプションを記載しないとposts_orderbyのフックが有効化されないため、忘れずに記載しましょう。get_posts以外(query_postsやWP_Query)で取得する場合は自動的に有効化されるので記載不要です。

この記事が気に入ったらサポートをしてみませんか?