web-dev-qa-db-ja.com

Wp_queryを使用すると、分類法で並べ替えることができますか?

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

今私の問題は私が分類法で順序付けしたいのですが、ドキュメンテーションとウェブの検索から私は解決策を見つけることができません。

WP_Queryのorderbyでは、カスタムメタフィールドでもたくさんのフィールドで並べ替えることができますが、分類法をサポートしているようには見えません。

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

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

48
yeope

いいえ、分類法で注文することは不可能です。特定の種類の観点からすると、実際にはあまり意味がありません。

分類法は、物事をまとめる方法です。したがって、投稿に分類法を適用することのポイントは、実際には、その分類法に含まれる用語を投稿間で共有することです。分類法にそれぞれ1つのポストでしか使用されない用語がある場合、それは分類法を無意味にするでしょう。また、用語が本来の状態で共有されている場合は、それを並べても特に有用なものはありません。

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

編集:それは言った、あなたはフィルタを使用してカスタムSQLクエリを作ることによって分類法で注文することができます、あなたはそれを変更されていないWP_Queryから行うことはできません: http://scribu.net/wordpress/sortable-taxonomy-columns html

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

分類法は、用語をそれらに割り当てることによって物事をグループ化します。そのグループ化は分類法の全体的なポイントであり、用語はグループ化における単なる見栄えの良いものです。投稿に割り当てる意味のあるメタデータがある場合は、代わりに投稿メタを使用する必要があります。 post metaはキーと値の両方を使って情報を保存しているので、あなたは can で並べることができます。分類法では、実際にはキーを保存するだけで、その値はその用語でまとめられた投稿になります。

正しいアプローチを使えば、長期的には物事は簡単になります。分類法で奇妙なことをすることはできないと言っているわけではありませんが、長期的には、間違った方法で使用することで、物事を困難にしているだけです。

13
Otto

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

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

これらの語句に対して正しい順序で並べ替え、投稿をさまざまなカテゴリに分類してフロントエンドに適切に表示するには、結果セットをループ処理してから、それぞれの投稿をクエリする必要があります。その用語を見つけて現在の用語と比較し、配列にフィルターをかけ、そしてずっと続けるための結果セット。それからあなたは再び表示のために新しい配列をループしなければなりません。これは生産的ではありません。

WPに "post__in"オプションのように "tax__in" orderbyオプションがあればいいでしょう。 orderbyメソッドを調整して用語を結果セットに追加するには、それぞれ 'posts_orderby'フィルタと 'posts_join'フィルタを使用してクエリを自分でカスタマイズします。または、それらの用語に関連するhtmlセクション内で、フィルタリングしている各用語に対して新しいクエリを作成する必要があります。

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

43
Aryan Duntley

はい、でもかなり複雑です。

テーマの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 );

これはいくつかの見つけたものと私が自分でしたものからの率直さです。説明はかなり難しいのですが、肝心なのはこれを実行していることです。

15
Drew Gourley

私はここでゲームに遅刻しています、しかしこれをするためのもっと単純なもっと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があなたに代わってJOINなどを作成するのに役立ちます。あなたはJOINからのフィールドの1つで注文する必要があります。

9

さて、カスタム投稿タイプをカテゴリ/分類別に並べ替えた経験を公開したいと思います。

ウェブ

  1. WordPressで運営されている旅行代理店のウェブサイト
  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 、次の3つのフィルタを使ってfunctions.phpファイルにクエリをフックしました:posts_fields、posts_join、posts_orderby。

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');

これが誰かに役立つことを願っています

2
Xavier Caliz

私が対処したのと非常によく似た問題を抱えていました。私はカスタムの分類法(issue)でカスタムのポストタイプアーカイブ(雑誌記事)を注文したいのです。私は私のサイトで直接SQL問い合わせをしたことはありません - そして、あなたがこれらの他の答えのようなものであれば - あなたはあなたのアプローチを再考する必要があります。

問題点

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

2)Wordpressでは、orderbyがポストタイプのWP_Queryに分類法を使用することを許可していません(Ottoが綴っているとおり)。

解決策:

1)分類法のソートは、現時点では Custom Taxonomy Order NE で行うのが最善です。それはあなたがwp-adminでWYSIWYGを通して分類法を注文することを可能にします、それは私がそれをする方法ではありませんが、私はより良い何かを見つけていません。

プラグインを設定すると、ここで行ったことと似たようなものになります。オプションAuto-sort Queries of this Taxonomyを書き留めます - これをCustom Order as Defined Aboveに設定します。これにより、必要な順序になります。スクリーンショット

Custom Taxonomy Order NE display 

2)ソートされた分類法が整っていれば、各用語を処理する一連のWP_Query呼び出しを作成して、分類法に従って順序付けされたアーカイブを効果的に作成できます。 get_terms()を使用してすべての税条件の配列を作成してから、各条件に対してforeachを実行します。これにより、各用語項目に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
staypuftman

私がここでのすべての解決策がなぜそれをやりすぎているのかわからない。さて、それは半年前のことですが、私は現在以下のコードを実行しているだけで動作します。

   <?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の分類をアルファベット順にそしてそれらの分類グループ内のアルファベット順に分類順によって最初に分類します。

1
user3135691

これが私がこの特定の問題に対して使った解決策です。この解決策は、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.*GROUP BY p.IDに変更します。

1
CodeShaman

これはクエリの前のクエリに似ていますが、あまり多くの投稿をクエリしていないのであれば気にしないでください。ループ...

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' );
0
Marcelo Viana