質問: ### 実現したいこと wordpressですが、`wp_query`等を使い、次の **条件** で記事を表示したいです。 ### 条件 **カスタムフィールド`number`の値ごとに、最新1件ずつ** ### 例 たとえば次のような投稿ならば、表示したいのは、「記事B」と「記事C」です。「記事A」は表示しません。 | 記事 | 投稿日 | `number` | 表示 | | --- | --- | --- | --- | | 記事A | 4/1 | 1 | × | | 記事B | 4/2 | 1 | 〇 | | 記事C | 4/3 | 2 | 〇 | ### なぜか なぜ「記事A」を表示しないのかというと、**同じ`number`の記事は最新1件しか表示しない**という条件なので、`number`が「1」の最新の記事として、「記事A」でなく「記事B」を表示します。 そして「記事C」は`number`が「2」ですがこれは1つしかないので表示します。 以上の条件で記事を取得する方法がわかる方がいたら、どうかご指導をお願い致します。
回答: 残念ながら wp_posts や WP_Query で、条件に含まれる各項目から n 件ずつ取り出すという動作を簡単に実行することは難しいです。 WordPressの WP_Query で行うとしたら 1. カスタムフィールドに含まれる値一覧の配列を用意 2. カスタムフィールドの値を1つずつループさせて WP_Query でデータ取得 という処理を書く必要があります。 たとえば、$values にカスタムフィールドの値一覧を用意しておいて、foreach でカスタムフィールドの項目を1項目ずつ WP_Query に渡して カスタムフィールドの値ごとに1回ずつ検索する必要があります。 ``` $values = array( '001', '002', '009', '050', '100', '999' ); // カスタムフィールドの全項目一覧 foreach( $values as $value ) { $args = array( 'posts_per_page' => 1, 'meta_key' => 'number', 'meta_value' => $value, 'meta_compare' => '=', 'order' => 'DESC', 'orderby' => 'date', ); $query = new WP_Query( $args ); if ( $query->have_posts() ) { echo ''; while ( $query->have_posts() ) { $query->the_post(); echo '' . get_the_title() . ''; } echo ''; wp_reset_postdata(); } else { // no posts found } } ``` 関数リファレンス/WP_Query 参照 もし、SQLが、書けるのであれば、 * カスタムクエリ を利用して、WP_Query の条件を SQL で設定したり * 関数リファレンス/wpdb_Class を利用して、直接、SQLで検索したり することもできます。 (追記 2019.04.23 11:25) カスタムクエリで対応する例 まず、条件分岐タグ を使って、どのテンプレートの場合に実行するのか条件を決めます。 条件分岐タグで、使用場所を指定しない場合、全ての SQL に適用されることになります。 内容によっては、ログインできなくなったり、一切の投稿が表示されなくなったりしますので、注意してください。 詳細がわかりませんので、アーカイブのメインクエリーと仮定します。 希望する内容が取得できる SQL を考えます。 質問の内容から推測して ``` SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id INNER JOIN ( SELECT wp_postmeta.meta_value as number, max(wp_posts.post_date) as max_date FROM wp_posts INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id WHERE wp_postmeta.meta_key = 'number' GROUP BY wp_postmeta.meta_value ) AS j2 ON wp_postmeta.meta_value =j2.number AND wp_posts.post_date = j2.max_date ``` のような感じでしょうか。 作成した SQL を WordPress の HOOK で実行できるように構築しなおして、functions.php に記載します。 INNER JOIN は `posts_join`フックを、絞り込み条件がある場合の WHERE や AND は `posts_where`フックを使用します。 ``` function my_posts_join_tt184471( $join ) { global $wpdb; if( ! is_admin() && is_archive() && is_main_query() ) { $join .= "INNER JOIN ". $wpdb->postmeta ." ON ". $wpdb->posts .".ID = ". $wpdb->postmeta .".post_id "; $join .= "INNER JOIN ( "; $join .= " SELECT ". $wpdb->postmeta .".meta_value as number, max(". $wpdb->posts .".post_date) as max_date "; $join .= " FROM ". $wpdb->posts; $join .= " INNER JOIN ". $wpdb->postmeta ." ON ". $wpdb->posts .".id = ". $wpdb->postmeta .".post_id "; $join .= " WHERE ". $wpdb->postmeta .".meta_key = 'number' "; $join .= " GROUP BY ". $wpdb->postmeta .".meta_value "; $join .= " ) AS j1 "; $join .= " ON ". $wpdb->postmeta .".meta_value = j1.number AND ". $wpdb->posts .".post_date = j1.max_date "; } return $join; } add_filter('posts_join', 'my_posts_join_tt184471' ); ``` 使用している条件分岐タグは、下記です。 * `! is_admin()` 管理画面を除く( ! で否定 ) * `is_archive()` アーカイブテンプレート * `is_main_query()` メインクエリー カスタムクエリの場合、表示まわりは、標準の archive.php のままで OK です。 -- 参考: * カスタムクエリ * posts_join * posts_where