web-dev-qa-db-ja.com

各カテゴリの "スティッキー"投稿(archive.php)

私は各カテゴリーに付箋を貼ることができる必要があります。これを行う最も簡単な方法は、ページ上に2つのループを作成することです。これは私が書いたものです:

<?php
//Custom "sticky" loop
$sticky_posts = new WP_Query(array(
    'post__in' => get_option('sticky_posts')
));

if ($sticky_posts->have_posts()) :
    while ($sticky_posts->have_posts()) : $sticky_posts->the_post();

        get_template_part('post-formats/content', 'sticky');

    endwhile; endif;

// CLEAR DATA
wp_reset_postdata();

if (have_posts()) : 
// Normal loop

while (have_posts()) : the_post(); 

    $format = get_post_format();
    if (false === $format) {
        $format = 'standard';
    }
    get_template_part('post-formats/content', $format);

endwhile; 

残念ながらそれは期待通りに動作しません:

  1. これは、そのカテゴリに属しているかどうかにかかわらず、スティッキーアイテムをすべてのカテゴリの最上位に配置します。
  2. 何よりも奇妙なことに、スティッキーな投稿がない場合は、すべての投稿が「スティッキー」ループで表示され、次に通常のループで繰り返されます。変です!

私は何をしましたか。私はスティッキーな投稿が2回表示されることを認識しています(1回は上部に、もう1回は通常の位置に表示されます)。 : - /

2

これをより完全にするために、手元の質問に答えて私がコメントで言ったことはここにあります

簡単に説明すると、WP_Queryは空の配列がそのパラメータの一部に渡される場合に壊滅的に失敗します。予想どおりに空の配列も返すのではなく、WP_Queryはすべての投稿を返します。前述したように、正しいスティッキを取得するためには、現在のカテゴリIDを取得し、それを使用してスティッキ投稿をフィルタリングする必要があります。覚えておいて、あなたのアプローチでは、あなたがメインクエリからスティッキー投稿を削除する必要がありますそうでなければあなたは重複するでしょう

メインクエリでフックとフィルタを使用し、 類似の質問/回答 から作業する別の解決策として、これが私が思いついたものです:(コードはよくコメントされているので追うことができます)注意:これはまだテストされていないため、少なくともPHP 5.4+)が必要です。

function get_term_sticky_posts()
{
    // First check if we are on a category page, if not, return false
    if ( !is_category() )
        return false;

    // Secondly, check if we have stickies, return false on failure
    $stickies = get_option( 'sticky_posts' );

    if ( !$stickies )
        return false;

    // OK, we have stickies and we are on a category page, continue to execute. Get current object (category) ID
    $current_object = get_queried_object_id();

    // Create the query to get category specific stickies, just get post ID's though
    $args = [
        'nopaging' => true,
        'post__in' => $stickies,
        'cat' => $current_object,
        'ignore_sticky_posts' => 1,
        'fields' => 'ids'
    ];
    $q = get_posts( $args );

    return $q;
}

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // IMPORTANT, make sure to target front end only
         && $q->is_main_query() // IMPORTANT, make sure we only target the main query
         && $q->is_category() // Only target category archives
    ) {
        // Check if our function to get term related stickies exists to avoid fatal errors
        if ( function_exists( 'get_term_sticky_posts' ) ) {
            // check if we have stickies
            $stickies = get_term_sticky_posts();

            if ( $stickies ) {
                // Remove stickies from the main query to avoid duplicates
                $q->set( 'post__not_in', $stickies );

                // Check that we add stickies on the first page only, remove this check if you need stickies on all paged pages
                if ( !$q->is_paged() ) {

                    // Add stickies via the the_posts filter
                    add_filter( 'the_posts', function ( $posts ) use ( $stickies )
                    {   
                        $term_stickies = get_posts( ['post__in' => $stickies, 'nopaging' => true] );

                        $posts = array_merge( $term_stickies, $posts );

                        return $posts;
                    }, 10, 1 );
                }
            }
        }
    }
});

注意事項:

  • これはデフォルトのcategory分類法でのみ機能します。分類法とその関連用語を使用するために、コードを簡単に変更することができます(それを実行してください。必要に応じて変更してください)。

  • これをfunctions.phpに追加するだけです。テンプレートファイルを変更したり、カスタムクエリを使用したりする必要はありません。必要なのは、デフォルトのループを持つメインクエリーだけです。

編集

上記のコードは現在テストされており、Wordpress 4.2.1とPHP 5.4以降で動作しています。

3
Pieter Goosen

評判のせいでPieter Goosenの回答をコメントすることはできません/ - :

現在のコードは現在のwordpress 4.8(2018年3月)に副作用があり、存在しないページにアクセスするとスティッキポストが表示され、代わりに404エラーが発生します。 "asd"が存在しない "www.example.com/asd"のように。同じ問題それ "WP - 管理者"。これは、その場合「asd」または「wp-admin」がカテゴリ名として$ qに保存されているためです。ただし、これは既存のカテゴリではありません。

修正:上記のコードにこのコードの最後の行を追加して、渡されたカテゴリが本当に存在するかどうかを確認します。

if (    !is_admin() // IMPORTANT, make sure to target front end only
     && $q->is_main_query() // IMPORTANT, make sure we only target the main query
     && $q->is_category() // Only target category archives         
     && $q->is_tax(get_query_var ( 'category_name')) // Only target existing category names   
3
bz-mof

両方の問題に対する答えは非常に簡単でした。

  1. 現在のカテゴリに制限するためにWP_Queryに引数を追加するだけです。
  2. スティッキーな投稿が実際にない限り、WP_Queryが実行されないようにしてください。

そのようです:

<?php
// Get sticky posts
$sticky_ids = get_option( 'sticky_posts' );

// BEGIN Custom "sticky" loop

// If sticky posts found...
if(!empty($sticky_ids)) {
    $args = array(
        'post_type' => 'post',
        'category__in' => get_query_var('cat'), // Get current category only
        'post__in' => get_option('sticky_posts') // Get stickied posts
    );

    $sticky_posts = new WP_Query($args);

    if ($sticky_posts->have_posts()) :
        while ($sticky_posts->have_posts()) : $sticky_posts->the_post();

            get_template_part('post-formats/content', 'sticky');

    endwhile; endif;
// END Custom "sticky" loop

    // Reset post data ready for next loop
    wp_reset_postdata();
}

if (have_posts()) :

    /* Start the Loop */
    while (have_posts()) : the_post();

        $format = get_post_format();
        if (false === $format) {
            $format = 'standard';
        }
        get_template_part('post-formats/content', $format);

    endwhile; endif; ?>
2