サポート » 使い方全般 » カスタムフィールドのソート

  • こんにちは。

    1つのカスタムフィールドの値(cf_point)でソートしていたのですが、グループ(cf_group)でソートさせた後にcf_pointでソートさせたいと思っています。

    現在のコードは下記です。まだグループでソートできていません。

    <?php
       query_posts(
      		array(
    		'post_type' => 'shop',
            'paged' => get_query_var('paged'),
                    'orderby'=>'meta_value',
                    'meta_key'=>'cf_point',
                    'order'=>'DESC'
    		));
      while (have_posts()) :
        the_post();
        get_template_part('top-shop');
      endwhile;
      wp_reset_query();
    ?>

    この並び替えに加えグループの並び替えを加えたいです。

    cf_point cf_group
    10 A
    24 B
    32 C
    43 B
    34 A
    64 B
    43 C

    こちらを Aグループから順に ポイントが高い順に並べたいと考えています。
    cf_point cf_group
    34 A
    10 A
    64 B
    43 B
    24 B
    43 C
    32 C

    その際どのように記述すればよいでしょうか。
    よろしくお願い致します。

10件の返信を表示中 - 1 - 10件目 (全10件中)
  • できればquery_postsを使いたいですが、そもそも仕様上無理なのでしょうか、うまくいきません。。。全く違うやり方でも、うまく並び替えできればと考えております。
    引き続きご指導いただければ幸いです。

    「グループ(cf_group)」って、どこに入っているのですか。これもカスタムフィールドですか?

    +---------+----------+------------+
    | post_id | meta_key | meta_value |
    +---------+----------+------------+
    | 1       | cf_point | 10         |
    +---------+----------+------------+
    | 1       | cf_group | A          |
    +---------+----------+------------+
    | 2       | cf_point | 24         |
    +---------+----------+------------+
    | 2       | cf_group | B          |
    +---------+----------+------------+

    こんな感じに読めるのですが… 合ってますか?

    cf_groupもカスタムフィールドです。こちらの表現で合っています。宜しくお願い致します。

    MySQL の機能としては、簡単です。が、それを WordPress にやらせるにはどうしたらいいのか…

    上の形式で保存されているデータを、

    +---------+----------+------------+----------+------------+
    | post_id | meta_key | meta_value | meta_key | meta_value |
    +---------+----------+------------+----------+------------+
    | 1       | cf_point | 10         | cf_group | A          |
    +---------+----------+------------+----------+------------+
    | 2       | cf_point | 24         | cf_group | B          |
    +---------+----------+------------+----------+------------+

    のような形で取得できれば、どのカラムを使ってもソートできます(meta_value はインデックスがないので、不利ですが)。これは同じテーブルを 2 回 JOIN で連結すれば実現できます。たとえば、

    SELECT
        p.ID,
        m.meta_key AS grp,
        m.meta_value AS grpval,
        mm.meta_key AS pnt,
        mm.meta_value AS pntval
    FROM
        $wpdb->posts AS p
    INNER JOIN
        $wpdb->postmeta AS m ON m.post_id=p.ID
    INNER JOIN
        $wpdb->postmeta AS mm ON mm.post_id=p.ID
    WHERE
        (p.post_type='shop' AND p.post_status='publish')
    AND
        m.meta_key='cf_group'
    AND
        mm.meta_key='cf_point'
    GROUP BY
        p.ID
    ORDER BY
        m.meta_value ASC, mm.meta_value DESC

    みたいな文を使います。グループ昇順、ポイント降順でソートされた並びになると思います。問題は、これを WordPress にどうやって作らせるかですよねぇ…

    一応、

    $sql = "上の文"; // ダブルクォートを使ってください
    $res = $wpdb->get_results($sql);
    print_r($res);

    してみて、お望みの順番になっているかどうか確認してみてください。タイプミスがあるかもしれません。WordPress の方は、後で。

    kjmtshさま、ご回答いただきありがとうございます!

    $sql =  "SELECT
        p.ID,
        m.meta_key AS grp,
        m.meta_value AS grpval,
        mm.meta_key AS pnt,
        mm.meta_value AS pntval
    FROM
        $wpdb->posts AS p
    INNER JOIN
        $wpdb->postmeta AS m ON m.post_id=p.ID
    INNER JOIN
        $wpdb->postmeta AS mm ON mm.post_id=p.ID
    WHERE
        (p.post_type='shop' AND p.post_status='publish')
    AND
        m.meta_key='cf_group'
    AND
        mm.meta_key='cf_point'
    GROUP BY
        p.ID
    ORDER BY
        m.meta_value ASC, mm.meta_value DESC";
    $res = $wpdb->get_results($sql);
    print_r($res);

    と入力したところ、実行したSQLのメッセージで

    #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '$sql = "SELECT
        p.ID,
        m.meta_key AS grp,
        m.meta_value AS grpval,
        ' at line 1

    と表示されました。ロリポップサーバーのphpMyAdminにログインして実行しております。
    データベース初心者のため、コードエラーの原因がわかりません。どのようなエラーが考えられますでしょうか。よろしくお願い致します。

    phpMyAdmin にこれをそのまま入れちゃだめですぅ。下をコピーして使ってくださいませ。「テーブルの接頭辞」が “wp_” でない場合は、そこを書き換えてね。

    SELECT
        p.ID,
        m.meta_key AS grp,
        m.meta_value AS grpval,
        mm.meta_key AS pnt,
        mm.meta_value AS pntval
    FROM
        wp_posts AS p
    INNER JOIN
        wp_postmeta AS m ON m.post_id=p.ID
    INNER JOIN
        wp_postmeta AS mm ON mm.post_id=p.ID
    WHERE
        (p.post_type='shop' AND p.post_status='publish')
    AND
        m.meta_key='cf_group'
    AND
        mm.meta_key='cf_point'
    GROUP BY
        p.ID
    ORDER BY
        m.meta_value ASC, mm.meta_value DESC;

    接頭辞をwp3_に変更して希望の並び替え順となりました!

    WordPress に実行させるコードです。

    functions.php に以下を書きます。

    function my_query() {
        add_filter('posts_fields_request', 'my_fields');
        add_filter('posts_where_request', 'my_where');
        add_filter('posts_groupby_request', 'my_groupby');
        add_filter('posts_join_request', 'my_join');
        add_filter('posts_orderby_request', 'my_orderby');
        $posts_per_page = 5;
        $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
        $args = array(
            'posts_per_page' => $posts_per_page,
            'paged'          => $paged,
        );
        $the_query = new WP_Query($args);
        return $the_query;
    }
    function my_fields($fields) {
        global $wpdb;
        $fields = "$wpdb->posts.*, m.meta_key AS grp, m.meta_value AS grpval, mm.meta_key AS pnt, mm.meta_value AS pntval";
        return $fields;
    }
    function my_where($where) {
        global $wpdb;
        $post_type = 'shop';
        $meta_key1 = 'cf_group';
        $meta_key2 = 'cf_point';
        $where = "AND $wpdb->posts.post_type='{$post_type}' AND $wpdb->posts.post_status='publish'";
        $where .= " AND m.meta_key='{$meta_key1}' AND mm.meta_key='{$meta_key2}'";
        return $where;
    }
    function my_groupby($groupby) {
        global $wpdb;
        $groupby = "$wpdb->posts.ID";
        return $groupby;
    }
    function my_join($join) {
        global $wpdb;
        $join = "INNER JOIN $wpdb->postmeta AS m ON m.post_id=$wpdb->posts.ID";
        $join .= " INNER JOIN $wpdb->postmeta AS mm ON mm.post_id=$wpdb->posts.ID";
        return $join;
    }
    function my_orderby($orderby) {
        $orderby = "m.meta_value ASC, mm.meta_valu DESC";
        return $orderby;
    }

    テンプレートファイルでの使い方。

    $the_query = my_query(); // 引数は全て functions.php で処理する
    if ($the_query->have_posts()) :
        while ($the_query->have_posts()) :
            $the_query->the_post();
            the_title(); // 通常のテンプレートタグはそのまま使う
            echo $post->grp; // カスタムフィールドには echo が必要
            echo $post->grpval;
            echo $post->pnt;
            echo $post->pntval;
        endwhile;
    endif;
    wp_reset_postdata();

    ページングは通常どおり行われますので、functions.php の posts_per_page で指定してください。タイプミスがあるかもしれません。

    kjmtshさま、ご回答ありがとうございます。
    function.phpは転写し、エラー等ありませんでした。

    テンプレートファイルでの使い方ですが、私の場合

    <?php
       query_posts(
      		array(
    		'post_type' => 'shop',
            'paged' => get_query_var('paged'),
                    'orderby'=>'meta_value',
                    'meta_key'=>'cf_point',
                    'order'=>'DESC'
    		));
      while (have_posts()) :
        the_post();
        get_template_part('top-shop');
      endwhile;
      wp_reset_query();
    ?>

    の記述部分をどのように変更させればよいでしょうか。質問ばかり恐縮です。宜しくお願い致します。

    こんな感じでいいでしょうか。カラーリングできるエディタに張り付けて、コメントを読んでください。

    <?php
    // $the_query 変数に投稿データとメソッドをセットする(必須)
    $the_query = my_query();
    // if 条件判定
    // have_posts() のかわりに、$the_query->have_posts() を使う
    if ($the_query->have_posts()) :
    // ループ開始
    // have_posts() のかわりに $the_query->have_posts() を使う
    while ($the_query->have_posts()) :
    // the_post() のかわりに $the_query->the_post() を使う
    // テンプレート関数が使えるようにするためには必須
    $the_query->the_post();
    /*
     * テンプレートタグ
     * 表示したい場所で使う
     */
    the_ID, the_title(); the_content(); the_excerpt();// etc...
    /*
     * カスタムフィールドの出力 1
     * the_meta() の出力は、'cf_group: A' 形式でカスタマイズできない
     */
    the_meta();
    /*
     * カスタムフィールドの出力 2
     * get_post_meta($post->ID, 'meta_key', true) の出力は、
     * meta_value の値 A, B, など echo が必要
     */
    echo get_post_meta($post->ID, 'cf_group', true);
    /*
     * $post->meta_key はキーを、$post->meta_value は値を出力
     * echo が必要
     */
    echo $post->grp;
    echo $post->grpval;
    echo $post->pnt;
    echo $post->pntval;
    // ループ終了
    endwhile;
    // if 条件終了
    endif;
    // 投稿データ制御をメインループに戻す
    wp_reset_postdata();
    ?>

    query_posts() は必要ありません。imanishi さんの場合、top-shop.php を読み込んで、ループ内の表示を制御しているので、そのファイル内で、cf_point の値を表示したいところで、echo $post->pntval を、cf_group の値を表示したいところで、echo $post->grpval を書いてください。

    ちゃんとしたものにしたい場合は、これらを使って、テンプレート用の関数を一つ定義するのがスマートなのですが、今、時間がないので、これでご勘弁を。

10件の返信を表示中 - 1 - 10件目 (全10件中)
  • トピック「カスタムフィールドのソート」には新たに返信することはできません。