【バグ?】タグのカスタムフィールドで並び替えが効かない

【バグ?】タグのカスタムフィールドで並び替えが効かない

先日タグに「views数」のカスタムフィールドを設けて、get_tagsで取得時に並び替えして取得しようとしたら上手くいかなかったときのお話です。

使う機会としては少ないのですが、かなり時間消費したので同じように困った人のためにメモしておきます。

前提

  • 通常の投稿タグ「post_tag」
  • カスタムフィールド「term_meta」でタグにviews数計測している
  • 干渉しそうなプラグインは使用していない。

想定している動作

想定している動作は以下のコードで「views数」の上位3件が取得できることです。

$args = [
    'number'         => 3,
    'hide_empty'     => false,
    'meta_query'     => [
        [
            'key'     => 'view',
            'value'   => '0',
            'compare' => '>'
            'type'    => 'numeric'
        ]
    ],
    'meta_key'       => 'view',
    'orderby'        => 'meta_value',
    'order'          => 'DESC'
];

$tags = get_tags( $args );

「meta_query」でカスタムフィールドの値が「0より大きい」ものを取得しています。

さらに、指定したカスタムフィールドの値で並び替え、降順にするというものです。

実際の動き

「meta_query」は動きますが、並び替えは動作しませんでした。

なので取得されるのは「meta_query」の条件を満たした、「name」降順で最初の3つです。

かなり調べて、コアのコードも見たりしていたのですが、原因がわかりませんでした。(結構急いでいたので、見落としがあったかもしれないです。)

対処

とりあえずオプションではどうにもならなさそうなので、全部取得してからソートする方法にしました。

(termの取得、カスタムフィールドの取得は時間がかかります。実際に使用する場合にはtransientなどで内部的にタグ情報をキャッシュしておくとよいです。)

変更&並び替えのポイントは以下の通りです。

  • 「meta_query」はそのままに取得件数を全取得に変更
  • foreachでget_term_metaで「view」数を取得し、配列へ格納
  • array_multisortでソート
  • ループで回して、カウンターでループ抜け

実際にコードでも見ていきます。

最後のループは省略しています。

$args = [
    'number'         => 0,
    'hide_empty'     => false,
    'meta_query'     => [
        [
            'key'     => 'view',
            'value'   => '0',
            'compare' => '>'
            'type'    => 'numeric'
        ]
    ],
];

$tags = get_tags( $args );

if ( $tags ) {
    $tag_view = [];
    foreach ( $tags as $tag ) {
        $tag_view[] = get_term_meta( $tag->ID, 'view', true );
    }

    array_multisort( $tag_view, SORT_DESC, $tags );
}

今回「number」は0にすることで全件取得しています。

array_multiソートは第一引数の配列を並び変えると、その動きに併せて第3引数の配列も並び替えてくれるという便利な関数です。

詳細はドキュメントで確認してください。

後は「$tags」でループさせて今回の例であれば3つ取得したところで、breakさせればOKです。

まとめ

久々になかなか解決できないもやもやしたのに当たりました。。。

面倒くさがって違うやり方に移ろうとしたいと時間はあっという間に過ぎていきます。

上記で悩んだ方は早めに他の切り口を考えてみましょう。(投稿のカスタムフィールドにしたり、オプションにしたりと意外と使えるものがあるかもしれません。)