web-dev-qa-db-ja.com

WP_Query:スティッキーポストがループの最初のアイテムではないのはなぜですか?

私はmeta_value変数に基づくカスタムWP_Queryループを持っています。

$meta_cat = get_sub_field('category');
$posts = new WP_Query( array(
    'cat' => $meta_cat,
    'posts_per_page' => get_sub_field('recent_ppp'),
) );

しかし、どういうわけか私が投稿をスティッキーにすると、whileループの最初の項目として表示されません。

ignore_sticky_postsはデフォルトでfalseに設定されているので、変更する必要はありません。また、de order_byのドキュメントを参照してみてください 何らかの値がスティッキポストに関連しているがそうではない場合。

order_by => 'post__in'は近いかもしれませんが:

Post__in配列で与えられた投稿IDの順序を保持する

しかし、私がpost__in => get_options('sticky_posts') - only と設定した場合、スティッキーポストが表示されます。

2つのカスタムループを作成しなくてもこれは可能ですか。1つはスティッキポストを扱い、もう1つは他のポスト用です。すべてのカテゴリにスティッキポストが含まれているわけではないので、これは本当に悪いことです。

5
ronnyrr

スティッキーが含まれているソースコードを見た場合、WP_Queryがスティッキー投稿を含めるようになる前に、次の条件が見つかります。

if (    $this->is_home 
     && $page <= 1 
     && is_array($sticky_posts) 
     && !empty($sticky_posts)  
     && !$q['ignore_sticky_posts'] 
) {

大物はis_home状態です。 WP_Query内の条件は、渡された引数に従って設定され、クエリが行われるページではありません。 catを引数として渡すので、is_homeはfalseに設定され、is_categoryはtrueに設定されます。 is_homeがfalseに設定されているため、上記の条件は失敗し、スティッキは含まれません。

考えられる回避策 - 未テスト

できることは、is_homeを使って手動でpre_get_postsをtrueに設定することです。必要なのは、'wpse_is_home' => true,をカスタムのWP_Queryインスタンスに渡すことだけです。

それから、pre_get_postsアクションを以下のように実行します。

add_action( 'pre_get_posts', function ( $q )
{
    if ( true === $q->get( 'wpse_is_home' ) ) 
        $q->is_home = true;
});

編集

私たちはおそらく質問されたカテゴリに関連性があるスティッキーズを見せたいだけでしょう。その場合は、特定の照会カテゴリに属さないスティッキを削除する必要があります。

pre_get_postsアクションの中で、次のことを試すことができます。

add_action( 'pre_get_posts', function ( $q )
{
    remove_action( current_action(), __FUNCTION__ );

    if ( true !== $q->get( 'wpse_is_home' ) )
        return;

    // Make sure get_sub_field exists, if not, bail
    if ( !function_exists( 'get_sub_field' ) )
        return;

    // Lets query everything to keep code clean
    $meta_cat = get_sub_field( 'category' ); // Copied from your code
    $meta_cat = filter_var( $meta_cat, FILTER_VALIDATE_INT );
    // Make sure we have a value, if not, bail
    if ( !$meta_cat )
        return;

    $q->set( 'cat', $meta_cat );

    // Set pagination if recent_ppp exists
    $ppp = get_sub_field( 'recent_ppp');
    $ppp = filter_var( $ppp, FILTER_VALIDATE_INT );
    if ( $ppp )
        $q->set( 'posts_per_page', $ppp );      

    // Set is_home to true 
    $q->is_home = true;

    // Get all stickies
    $stickies = get_option( 'sticky_posts' );
    // Make sure we have stickies, if not, bail
    if ( !$stickies )
        return;

    // Query the stickies according to category
    $args = [
        'post__in'            => $stickies,
        'posts_per_page'      => -1,
        'ignore_sticky_posts' => 1, // Ignore stickies
        'cat'                 => $meta_cat,
        'orderby'             => 'post__in',
        'order'               => 'ASC',
        'fields'              => 'ids' // Get only post ID's
    ];
    $valid_sticky_ids = get_posts( $args );

    // Make sure we have valid ids
    if ( !$valid_sticky_ids ) {
        $q->set( 'post__not_in', $stickies );
        return;
    }

    // Remove these ids from the sticky posts array
    $invalid_ids = array_diff( $stickies, $valid_sticky_ids );

    // Check if we still have ids left in $invalid_ids
    if ( !$invalid_ids )
        return;

    // Lets remove these invalid ids from our query
    $q->set( 'post__not_in', $invalid_ids );
});

カスタムクエリを実行する前に、get_sub_fieldが存在すること、そして最も重要なことにget_sub_field( 'category' )が設定され有効であることを確認する必要があります。これは、すべての投稿が返されることにつながる壊滅的な失敗を回避します。

WP_Queryを渡すだけでよいので、あなたの'wpse_is_home' => trueは次のようになります。

if (    function_exists( 'get_sub_field' )
     && filter_var( get_sub_field( 'category' ), FILTER_VALIDATE_INT )
) {
    $args = [
        'wpse_is_home' => true
    ];
    $posts_array = new WP_Query( $args ); // DO NOT USE $posts

    // Run your loop as normal
}

最後の編集

コードはテストされ、期待通りに動作しています

4
Pieter Goosen