web-dev-qa-db-ja.com

pre_get_posts:特定の投稿タイプに対してのみtax_queryを使用する

デフォルトの投稿タイプの投稿(投稿タイプ:post)とカスタム投稿タイプの投稿(投稿タイプ:cpt)があります。後者には分類法があります(cpt_tag)。

自分のフロントページに、デフォルトの投稿タイプの投稿(フィルタなし)、、およびいくつかのcpt投稿タイプの投稿を、cpt_tagがある場合にのみ表示します。

コードは次のとおりです。

add_action( 'pre_get_posts', 'get_posts_plus_cpt_with_certain_tag' );

function get_posts_plus_cpt_with_certain_tag( $query ) {
   if ( $query->is_home() && $query->is_main_query() ) {

        $taxquery = array(
            array(            
               'taxonomy' => 'cpt_tag',
               'field' => 'term_id',
               'terms' => 27
               )
            );      
        $query->set( 'tax_query', $taxquery );                 
        $query->set( 'post_type', array( 'post', 'cpt' ) );
    }
}

問題は$query->set( 'tax_query', $taxquery );cpt投稿だけでなくpost投稿にも適用されることです。 cpt投稿をフィルタリングし、post投稿をフィルタリングせずにtax_queryを使用するにはどうすればよいですか。

任意の助けがいただければ幸いです。ありがとうございます。

(これは 私の以前の質問 の明確化されたバージョンです。)

1
pot63

理解できるように、cpt_tagはカスタム投稿タイプcptにのみ割り当てられます。これにより、作業がはるかに簡単になり、複雑さが軽減されます。 2つのクエリは必要なく、何もマージする必要はありません

計画は次のとおりです。

  • cpt投稿タイプからホームページに表示する必要がある用語を知る必要があります

  • get_terms()およびexcludeパラメーターを使用して、cpt投稿タイプから投稿を表示するために必要な用語を除外します。 get_terms()から返される配列には、表示したくないすべての用語が保持されます。また、fieldsパラメーターをidsに設定して、用語IDの配列を取得します。

  • この配列は、tax_querypre_get_postsに渡されます。これは除外する必要がある用語なので、operatorパラメーターをNOT INに設定して、これらの用語を含む投稿を除外します

この作業を行うには、コードを少し調整するだけです

ここに例があります

add_action( 'pre_get_posts', 'get_posts_plus_cpt_with_certain_tag' );

function get_posts_plus_cpt_with_certain_tag( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {

        /*
        * Change 110 to the term id you need to display posts from from cpt post type
        */
        $terms = get_terms( 'cpt_tag', array( 'exclude' => 110, 'fields' => 'ids' ) );
        if ( $terms && !is_wp_error( $terms ) ) {
            $taxquery = array(
                array(            
                    'taxonomy'  => 'cpt_tag',
                    'field'     => 'term_id',
                    'terms'     => $terms,
                    'operator'  => 'NOT IN'
                )
            );      
            $query->set('tax_query', $taxquery); 
        }   
        $query->set( 'post_type', array( 'post', 'cpt' ) );

    }
}

編集1

私は安全性を含めませんでしたshould最初にget_termsから結果を得るかどうかを使用する前にチェックしてください。これをコードに含めました

編集2

上記のソリューションは機能しますが、コメントで指摘されているように小さな不具合があります

... cpt_tagsをまったく持たないcpt投稿タイプの投稿がある場合、tax_queryはそれらを除外せず、少なくとも1つのcpt_tagを持つcpt投稿タイプの投稿のみを除外します...

問題は、通常の投稿タイプpostがデフォルトで割り当てられたuncategorizedという用語を持っているのと同じように、用語が割り当てられていない場合、デフォルトでカスタム投稿タイプの投稿にデフォルトの用語が割り当てられていないという事実で発生します用語がそれに割り当てられます

用語が割り当てられていない場合は用語との関係がないため、カスタム投稿タイプの投稿はwp_term_relationshipsテーブルに表示されず、通常のtax_queryには表示されません

この問題を回避するには、元のワークフローをわずかに変更する必要があります。この問題に取り組む方法は次のとおりです

  • post投稿タイプに割り当てられているすべての用語を取得します。デフォルトでは、post投稿タイプのすべての投稿には、この動作が他の抜本的なコードによって変更されない限り、少なくとも1つの用語が割り当てられます。したがって、ここでは99.999%安全です。

  • 前と同じ戦略を使用しますが、少し変更します。 fieldsパラメーターをidsに設定したget_terms()を引き続き使用しますが、ここではすべての用語を取得します。 category投稿タイプにデフォルトのビルドイン分類法postを使用していると仮定します。

  • cpt_tagincludeに必要な用語IDをtax_queryに渡すだけで、ここでは特別なことはできません。

  • relationタクソノミーのすべての用語を持つ投稿が必要なため、ORパラメーターをcategoryに設定することを忘れないでくださいまたはcpt_tagタクソノミーの特定の用語を持つすべての投稿。 relationパラメーターを省略すると、デフォルトでANDになります。これは、categoryタクソノミーに用語を持つ投稿を検索するため、クエリに失敗しますおよびcpt_tagタクソノミー

それをコードに入れましょう:

再び110の用語に用語ID cpt_tagを使用しますが、それに応じて変更します

add_action( 'pre_get_posts', 'get_posts_plus_cpt_with_certain_tag' );

function get_posts_plus_cpt_with_certain_tag( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {

        /*
        * Change 110 to the term id you need to display posts from from cpt post type
        */
        $terms = get_terms( 'category', array( 'fields' => 'ids' ) );
        if ( $terms && !is_wp_error( $terms ) ) {
            $taxquery = array(
                'relation' => 'OR',
                array( // Includes all terms (categories) for post post type          
                    'taxonomy'  => 'category',
                    'field'     => 'term_id',
                    'terms'     => $terms,
                ),
                array( // Include the terms you need to display from cpt_tag           
                    'taxonomy'  => 'cpt_tag',
                    'field'     => 'term_id',
                    'terms'     => array( 110 ),
                ),

            );      
            $query->set('tax_query', $taxquery); 
        }   
        $query->set( 'post_type', array( 'post', 'cpt' ) );

    }
}
3
Pieter Goosen