wp_queryを使用すると、分類順に並べることができますか?


49

私の質問は簡単です。WP_Queryを使用して、tax_queryを使用した分類法によってフィルタリングされたカスタムタイプの投稿を取得しています。

今、私の問題は、分類法で注文したいのですが、ドキュメントやウェブでの検索から、解決策を見つけることができません。

WP_Queryのorderbyを使用すると、カスタムメタフィールドも含めて多数のフィールドで注文できますが、分類法をサポートしていないようです。

正しい方向へのポインタはありますか?

皆さん、ありがとうございました。

回答:


12

いいえ、特定のタイプの観点からは実際にはあまり意味がないので、分類法で注文することはできません。

分類法は、物事をグループ化する方法です。そのため、投稿にタクソノミーを設定するポイントは、投稿間で共有されるタクソノミーに用語を設定することです。分類法にそれぞれ1つの投稿でのみ使用される用語がある場合、分類法は無意味になります。また、用語が本来あるべきように共有されている場合、それによる順序付けは特に有用なものを生成しません。

このような状況で使用する必要があるのは、ポストメタです。投稿メタで注文することができ、それは各投稿に固有です。

編集:つまり、フィルターを使用してカスタムSQLクエリを作成することで、分類法で並べ替えることができます。変更されていないWP_Queryからはできません:http ://scribu.net/wordpress/sortable-taxonomy-columns.html

ただし、この種のことを行う必要がある場合は、そもそもデータ設計構造が間違っています。分類法の「用語」は、実際の「データ」ではありません。用語自体には固有の意味はありません。それらは説明している特定のグループの単なるラベルです。それらを意味のあるデータとして扱っている場合、根本的な設計上の欠陥があります。

分類法は、用語を割り当てて分類します。そのグループ化は分類法の全体的なポイントであり、用語はグループ化のほんの一面にすぎません。投稿に割り当てる意味のあるメタデータがある場合は、代わりに投稿メタを使用する必要があります。また、ポストメタは情報を保存するためにキーと値の両方を使用するため、注文することができます。分類法では、キーのみを保存し、その値はその用語でグループ化された投稿になります。

正しいアプローチを使用すれば、長い目で見れば簡単になります。タクソノミーでは奇妙なことはできないと言っているわけではありませんが、間違った使い方をすることで、長い目で見れば自分を難しくしているだけです。


こんにちは、オットー、答えてくれてありがとう。私はあなたの主張を見て、たぶん私はこれで間違った道を進んでいます。テレビ番組のサイトの例では、シリーズ1、セリエ2、セリエ3などの分類があります。したがって、シリーズ番号ごとにすべての異なるテレビ番組をグループ化できます。それから、エピソード、エピソード01、エピソード02などにも同じことが言えます。すべてのエピソードのリストを表示して、エピソードとセリエの順に並べたいと思います。分析し、メタフィールドとカスタムフィールドを投稿します。オットーありがとう
-yeope

@yeope分類はシリーズで、用語はシリーズ1、シリーズ2などである必要があります。エピソードでは、シリーズには複数のエピソードが含まれているため、同じ分類「シリーズ」を使用できます。エピソード2などには、親用語「シリーズx」があります。その後、エピソードを順番に並べて、シリーズ全体を順番に照会できます。
Chris_O

@Chris_Oなるほど、あなたはそこにお金があるかもしれません!私が見ることができる唯一の問題は、シリーズごとに「エピソード1」、「エピソード2」という用語を繰り返さなければならないという事実です。また、シリーズに依存しないすべてのエピソード1をグループ化することもできませんが、おそらくそれを回避する方法があると思います。ありがとうChris_O
yeope

2
エピソードに分類法を使用しても、実際にはあまり意味がありません。グループ化する価値がないからです。用語として「エピソード1」がある場合は、エピソード1を他のすべてのテレビ番組のエピソード1ごとにグループ化しています。エピソードとシリーズ番号は、特定のショーに固有のものであり、グループとしては役に立たないため、post_metaとしてより意味があります。テレビ番組の名前は、テレビ番組の分類法の用語として役立ちます。これは、番組全体をグループ化するためです。
オットー

1
Ottoは興味深いブログ記事でこれをフォローアップしました:Custom Taxonomyを使用する(しない)場合
ヤンファブリー

47

この質問に対する受け入れられた答えは受け入れられません。税による注文は「意味をなさない」と仮定するのは非論理的です。彼が与えた答えは意味をなさない。

メニュー投稿タイプを持つことを検討してください。次に、「FoodCategories」のカスタム税があります。FoodCategories税には、「朝食」、「昼食」、および「夕食」という用語があります。tax_queryパラメータを使用してクエリを送信すると、すべての用語を含む結果セットが得られますが、それらは投稿日順に並べられます。

これらの用語に関連して正しい順序を取得し、投稿をさまざまなカテゴリに分けてフロントエンドに適切に表示するには、結果セットをループしてから、各投稿をクエリする必要があります結果セットを検索して現在の用語と比較し、配列にフィルターをかけて全体を通して続行します。次に、表示のために新しい配列を再度ループする必要があります。これは生産的ではありません。

WPに "post__in"オプションと同様に "tax__in" orderbyオプションがあればいいのですが、ないので、上記のとんでもないプロセスを実行する必要があります。orderbyメソッドを調整し、用語を結果セットに追加するために、「posts_orderby」フィルターと「posts_join」フィルターを使用して自分でクエリをカスタマイズします。または、それらの用語に関連するhtmlセクション内でフィルタリングする各用語に対して新しいクエリを作成する必要があります。

最も効率的なのは、フィルターを使用してクエリ文字列を変更することです。最も簡単な方法は、3つの個別のクエリを実行することです。WP APIは、税による注文、または制限的なクエリパラメーターを処理する必要があります。特定の条件に基づいてクエリを制限している場合、多くの人が同じ条件で並べ替える必要がある可能性が高くなります。


2
申し訳ありませんが、あなたは間違っています。分類法による順序付けも、あなたの場合には意味がありません。何を見せたいですか?最初にすべての朝食、次にすべての夕食、そしてすべての昼食が続きますか?必要なものとその順序を選択する必要がありますが、分類法は単なるグループ化ラベルです。注文すべき意味のある「データ」ではありません。そうである場合、それは分類法の用語ではなく、代わりにポストメタにする必要があります。
オットー14年

15
もちろん、分類用語で投稿を注文したい場合がいくつかあります。別の例は、レーティング分類を使用した映画投稿タイプです。映画のリストでは、Gレーティング、PGレーティングなどのすべての映画が一番上に表示されるように、レーティングによって映画のリストを注文したい人を想像するのは非常に簡単です。(この例と食事の例では、名前の代わりにterm_idで並べ替えることができます。)メタではなく、おそらく分類法が最も役立つインスタンスの大きな灰色の領域がありますが、おそらく、その分類法が順序であるためにも役立ちますできる。
SeventhSteel

2
PGおよびGの評価などは、特定の映画に関するデータであることを除いて、適切な分類選択です。したがって、それらはメタです。それらはデータであり、カテゴリではありません。選択肢が限られているだけでは、分類は行われません。ソートが必要な場合は、メタにするか、タクソノミー固有のコードを介してタクソノミーによるソートを強制します。ところで、NC17はPGの後に来ます。したがって、とにかくその順序付けを行うコードが必要です。
オットー

私はこのコメントでパーティーに遅れていることを知っていますが、これにぶつかっただけです。分類法による順序付けは、状況によっては意味をなす場合があります。1つのプロジェクトに職種を投稿タイプとして設定し、次に職種が州および市に分類されます。それらを簡単にグループ化できるようにして(州内のすべてのジョブを表示するか、都市内のすべてのジョブを表示する)、分類法が最良のソリューションでした。同時に、最初にタイトルで、次に州で、次に都市で並べ替える一般的な求人検索があります。
デニスプザック

別のユースケース:クライアントには多数の記事があり、それぞれにカテゴリがあります。クライアントは、すべての記事を一覧表示するページが必要であり、アルファベット順、日付、またはカテゴリ別に並べ替えることができます。カテゴリもフィルタリングできますが、すべての記事をカテゴリ別にアルファベット順にリストすることは、ユースケースに夢中ではなく、かなり頻繁にポップアップ表示されます。
ウィルソンビッグス

15

はい、しかしかなり複雑です...

テーマのfunctions.phpに追加します。

function orderby_tax_clauses( $clauses, $wp_query ) {
    global $wpdb;
    $taxonomies = get_taxonomies();
    foreach ($taxonomies as $taxonomy) {
        if ( isset( $wp_query->query['orderby'] ) && $taxonomy == $wp_query->query['orderby'] ) {
            $clauses['join'] .=<<<SQL
LEFT OUTER JOIN {$wpdb->term_relationships} ON {$wpdb->posts}.ID={$wpdb->term_relationships}.object_id
LEFT OUTER JOIN {$wpdb->term_taxonomy} USING (term_taxonomy_id)
LEFT OUTER JOIN {$wpdb->terms} USING (term_id)
SQL;
            $clauses['where'] .= " AND (taxonomy = '{$taxonomy}' OR taxonomy IS NULL)";
            $clauses['groupby'] = "object_id";
            $clauses['orderby'] = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC) ";
            $clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get('order') ) ) ? 'ASC' : 'DESC';
        }
    }
    return $clauses;
}

    add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );

これはいくつかの発見されたものと私が自分でやったものからフランケンシュタインです。説明するのは非常に難しいですが、一番下の行はこれを実行することです。


Drewに感謝します。SQLを実行して、少し編集する必要がありますが、うまくいくかもしれません。私の唯一の問題は、オットーが指摘したように間違った方向に進む可能性があることです。ドリュー、ありがとう。編集-編集する必要はありません私はそれが微調整が必​​要な場所を見ることができます:)ありがとう
-yeope

あなたが最後の2分以内にそれをつかんだ場合、それは動作しません、先に進んで今すぐつかんでください、私はそれを修正しました。2つの特定の分類法に合わせて設定されました。登録されたすべての分類法で動作するようにコードを改善しました。
ドリューゴーリー

改めてありがとうございます。念のため、あなたのソリューションを試してみたところ、うまくいきました。また、他の誰かがそれを使用したい場合はadd_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );add_filter('posts_clauses', 'todo_tax_clauses', 10, 2 );ありがとうに変更する必要があります:)
yeope

はい、これはコードブロックで修正されました。作業中のプロジェクトから取得し、フックで変更したにもかかわらず、関数の名前を変更するのを忘れていました。
ドリューゴーリー

1
名前ではなくIDで分類法を注文できるかどうか知っていますか?IDで分類グループを並べ替えて同じ結果を取得しようとしています
ハビエルビジャヌエバ

9

私はここでゲームに遅れて来ていますが、これを行うより簡単なWordPressyの方法があります。

通常のように税クエリを作成します。

$tax_query = array();
$tax_query['relation']="OR";
$tax_query[] = array(
    'taxonomy' => 'product_cat',
    'field'    => 'slug',
    'terms'    => $cat_terms,
);
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;

query_postsまたはWP_Queryの引数を設定します

$args = array(
    'post_type'=>'post',
    'posts_per_page'=>12,
    'paged'=>$paged,
    'tax_query' => $tax_query,
);

query_posts / WP_Query呼び出しを行う前に、orderbyフィルターにフックしてオーバーライドします

add_filter('posts_orderby', 'edit_posts_orderby');
function edit_posts_orderby($orderby_statement) {
    $orderby_statement = " term_taxonomy_id ASC ";
    return $orderby_statement;
}
query_posts($args);
remove_filter('posts_orderby', 'edit_posts_orderby');

後でフィルターを削除することを忘れないでください...

これは、b / c tax_queryが結合などを作成するために機能します。結合のフィールドの1つで並べ替えるだけです。


2
term_taxonomy_idの代わりに名前で注文する方法に関するアイデアはありますか?orderby_statementでterm_taxonomy_idを変更すると、エラーがスローされます
tehlivi

これは、興味のある人には正しい答えです!
M

2

さて、カスタム投稿タイプをカテゴリ/分類法でソートした経験を公開したいと思います。

ウェブ

  1. WordPressで実行されている旅行代理店のWebサイト
  2. 「ruta」と呼ばれるカスタム投稿タイプの主なコンテンツ
  3. この構造を持つ分類法旅行の種類>大陸>国

ケース

アーカイブカテゴリリストページでは、クライアントは投稿を次のようにソートすることを望んでいました。

  1. 各大陸のルート数で並べられた大陸。
  2. アルファベット順に並べられた国。

手順

最初に、変更されていないアーカイブページクエリからのリクエストをキャッチします。

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 
FROM wp_posts 
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) 
WHERE 1=1 
AND ( wp_term_relationships.term_taxonomy_id IN (5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,25,26,28,29,31,32,33,35,38,95,101,102,193) )
AND wp_posts.post_type IN ('ruta', 'nav_menu_item') 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 45 
AND wp_posts.post_status = 'private') 
GROUP BY wp_posts.ID 
ORDER BY wp_posts.post_date DESC LIMIT 0, 20

第二に、私のニーズに合うように、データベースに対してSequel ProでSQLコードを編集しました。私はこれを思いつきます(はい、おそらく改善できます:MySQLについての私の知識は傑出していません):

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID, tt1.parent AS pare,
    (
    SELECT COUNT(*) 
    FROM  wp_posts
    INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
    INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id =      wp_term_relationships.term_taxonomy_id )
    INNER JOIN wp_term_taxonomy AS tt2 ON ( tt2.term_taxonomy_id =  tt1.term_taxonomy_id )
    WHERE 1=1  
    AND tt1.parent = pare
    ) AS Total
FROM  wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id =      wp_term_relationships.term_taxonomy_id )
INNER JOIN wp_terms ON ( tt1.term_id = wp_terms.term_id )
WHERE 1=1  
AND ( wp_term_relationships.term_taxonomy_id IN (5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,25,26,28,29,31,32,33,35,38,95,101,102,193) ) 
AND wp_posts.post_type IN ('ruta', 'nav_menu_item') 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 45 
AND wp_posts.post_status = 'private') 
GROUP BY wp_posts.ID 
ORDER BY
total DESC,
wp_terms.name  

3番目に、posts_fields、posts_join、posts_orderbyの3つのフィルターを使用して、functions.phpファイルにクエリをフックしました。

functions.phpのコード:

function xc_query_fields( $fields ) {

   $fields = "wp_posts.ID, wp_posts.post_title, wp_terms.name, tt1.parent AS pare,
    (
    SELECT COUNT(*) 
    FROM  wp_posts
    INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
    INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
    INNER JOIN wp_term_taxonomy AS tt2 ON ( tt2.term_taxonomy_id = tt1.term_taxonomy_id )
    WHERE 1=1  
    AND tt1.parent = pare
    )
    AS Total";
     return $fields;
}


function xc_query_joins( $join ) {
$join .= "INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
   INNER JOIN wp_term_taxonomy AS tt1 ON ( tt1.term_taxonomy_id = wp_term_relationships.term_taxonomy_id )
   INNER JOIN wp_terms ON ( tt1.term_id = wp_terms.term_id )";
 return $join;
}


function xc_query_orderby( $join ) {
    $join = "total DESC, wp_terms.name ";
    return $join;
 }

最後に、いくつかの条件に従ってpre_get_postフックからフィルターをトリガーしました

function filtra_queries( $query )
{

  if (  is_archive()  && $query->is_main_query() && !is_admin()  ) {

$rutes = array('viajes-privados', 'asia', 'africa', 'oceania', 'america', 'oriente-proximo');

if  ( in_array( $query->get('category_name'), $rutes ) ) 
  {
  add_filter( 'posts_fields', 'xc_query_fields' );
  add_filter( 'posts_join', 'xc_query_joins' );
  add_filter( 'posts_orderby', 'xc_query_orderby' );
}// end if in_array

  }// end if is_archive

}
 add_filter('pre_get_posts', 'filtra_queries');

これが誰かを助けることを願っています


すばらしい作業です。この量のコードを使用して、分類法で何かをソートするのはばかげています。WPの大きな問題。
serraosays

2

私が扱った非常によく似た問題がありました:カスタム分類(問題)でカスタム投稿タイプアーカイブ(雑誌記事)を注文したいです。自分のサイトで直接SQLクエリを実行することはありません。通常、これらの他の回答が好きな場合は、アプローチを再考する必要があります。

問題点:

1)Wordpressでは、分類法をインテリジェントな方法で注文することはできません。

2)Wordpressはorderby、post-type WP_Queryでの分類法の使用を許可していません(Ottoによって記述されています)。

解決策:

1)分類法のソートは、現時点ではCustom Taxonomy Order NEプラグインによって最適に実行されます。WYSIWYGを介して分類法を注文することができます。wp-adminこれは、私がそれを行う方法ではありませんが、より良いものは見つかりませんでした。

プラグインをセットアップすると、ここで行ったことに似たものが得られます。オプションに注意してくださいAuto-sort Queries of this Taxonomy-これをに設定してくださいCustom Order as Defined Above。これにより、必要な順序を取得できます。スクリーンショット:

カスタム分類順序NE表示

2)分類された分類法を使用して、各用語を実行する一連のWP_Query呼び出しを作成し、分類法によって順序付けられたアーカイブを効果的に作成できます。を使用get_terms()して、すべての税条件の配列を作成し、foreach各条件に対してa を実行します。これにより、WP_Query特定の用語のすべての投稿を返す用語ごとのアイテムが作成され、効果的に分類用語順に並べられたアーカイブが作成されます。これを実現するコード:

  // Get your terms and put them into an array
  $issue_terms = get_terms([
    'taxonomy' => 'issues',
    'hide_empty' => false,
  ]);

  // Run foreach over each term to setup query and display for posts
  foreach ($issue_terms as $issue_term) {
    $the_query = new WP_Query( array(
      'post_type' => 'post',
      'tax_query' => array(
        array(
          'taxonomy' => 'issues',
          'field' => 'slug',
          'terms' => array( $issue_term->slug ),
          'operator' => 'IN'
        )
      )
    ) );

    // Run loop over each query
    while($the_query->have_posts()) :
      $the_query->the_post();

      // YOUR TEMPLATE OUTPUT FOR EACH POST

    endwhile;
  }

このサイトの関連資料: すべての投稿をカスタム分類でグループ化されたカスタム投稿タイプで表示します


2

ここでのすべてのソリューションがそれをほとんどやりすぎている理由はわかりません。OK、それは半十年前ですが、私は現在次のコードを実行しているだけで、動作します:

   <?php // Default
    $wheels_args = array(
        'post_type' => 'wheels',
        'posts_per_page' => '96',
        'orderby' => 'taxonomy, name', // Just enter 2 parameters here, seprated by comma
        'order'=>'ASC'
    );
    $loop = new WP_Query($wheels_args);
    ?>

これにより、最初にCPTの分類法がアルファベット順に分類され、これらの分類グループ内でアルファベット順に分類されます。


@yeopeなぜこれが受け入れられた答えなのか!?私がスクロールした神に感謝します
フアン・ソラノ

1

この特定の問題に使用した解決策を次に示します。このソリューションは、pre_get_postsフィルターを使用できず、クエリに既存のページネーションが存在する極端な場合(例:WooCommerce)の場合です。

global $wpdb;

$taxonomies = array('my-tax-1', 'my-tax-2', 'my-tax-3');

$orderby = "'".implode("', '", array_keys($taxonomies))."'";
$id_sql = $GLOBALS['wp_query']->request;

$id_sql = preg_replace('/LIMIT\s+\d+\s?,?\s\d*/', '', $id_sql);
$id_sql = str_replace('SQL_CALC_FOUND_ROWS', '', $id_sql);

$term_sql = "SELECT
  tt.taxonomy AS `taxonomy`,
  t.name AS `term_name`,
  t.slug AS `term_slug`,
  count(*) AS `term_count`
FROM ({$id_sql}) p 
JOIN wp_term_relationships tr
  ON p.ID = tr.object_id
JOIN wp_term_taxonomy tt
  ON tr.term_taxonomy_id = tt.term_taxonomy_id
JOIN wp_terms t
  ON tt.term_id = t.term_id
WHERE tt.taxonomy IN ({$orderby})
GROUP BY t.slug
ORDER BY
  FIELD(tt.taxonomy, {$orderby})"; // Add further specific ordering here

$results = $wpdb->get_results($term_sql, ARRAY_A);

これを使用して、分類法、用語、および用語ごとの投稿数順に並べられたナビゲーションメニューを作成しました。

単に投稿が必要な場合は、クエリをSELECT p.*andに変更しますGROUP BY p.ID


0

クエリの前のクエリに似ていますが、あまり多くの投稿をクエリしていない場合は気にしません...ループ...

function grouped_by_taxonomy_main_query( $query ) {

    if ( $query->is_home() && $query->is_main_query() ) { // Run only on the homepage

        $post_ids = array();

        $terms = get_terms('my_custom_taxonomy');

        foreach ( $terms as $term ) {
            $post_ids = array_merge( $post_ids, get_posts( array( 
                'posts_per_page' => 4, // as you wish...
                'post_type' => 'my_custom_post_type', // If needed... Default is posts
                'fields' => 'ids', // we only want the ids to use later in 'post__in'
                'tax_query' => array( array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id, )))) // getting posts in the current term
            );
        }

        $query->query_vars['post_type'] = 'my_custom_post_type'; // Again, if needed... Default is posts
        $query->query_vars['posts_per_page'] = 16; // If needed...
        $query->query_vars['post__in'] = $post_ids; // Filtering with the post ids we've obtained above
        $query->query_vars['orderby'] = 'post__in'; // Here we keep the order we generated in the terms loop
        $query->query_vars['ignore_sticky_posts'] = 1; // If you dont want your sticky posts to change the order

    }
}

// Hook my above function to the pre_get_posts action
add_action( 'pre_get_posts', 'grouped_by_taxonomy_main_query' );
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.