web-dev-qa-db-ja.com

カテゴリー内のすべての投稿を表示し、特定のタグ投稿を上部に表示

質問を言い換える

私のカテゴリcarのループ内で投稿を注文する必要があります。 carのカテゴリページにアクセスする場合、最初に表示するにはBMWとタグ付けされたすべての投稿が必要です。それからタグBMWとタグ付けされていない他の投稿が必要です。

私のposts_per_pageが10の投稿を表示するように設定されていて、私が1ページ目にあり、10のうち3つの投稿がBMWとタグ付けされている場合、これら3つの投稿は最初に現れなければなりません。をクリックして2ページ目に進むと、同じことが当てはまります。 BMWとタグ付けされたこれら10の投稿のうち5つがある場合、それらも他の5つの投稿の前に最初に表示されなければなりません。

それは可能ですか?

3
PreeT

loop_startフックを使用して@PieterGoosenと@ialocinの両方の良い答えを単純化したものを次に示します。

add_action( 'loop_start', function( $q ) {
    if( $q->is_main_query() && $q->is_category( 'car' ) )
        usort( $q->posts, function( $a, $b ){
            return -1 * has_tag( 'bmw', $a ) + 1 * has_tag( 'bmw', $b );            });
}, 10, 2 );

the_postsフィルタにも同じ方法を使用できます。

更新:

ホームページの投稿を最初のカテゴリ名で並べ替えるには、たとえば次のようにします。

add_action( 'loop_start', function( $q ) {
    if( $q->is_main_query() && $q->is_home() )
        usort( $q->posts, function( $a, $b ){
            return strcasecmp( 
                get_the_category( $a->ID )[0]->name, 
                get_the_category( $b->ID )[0]->name 
            );
        });
}, 10, 2 );

大文字と小文字を区別しない文字列比較のために strcasecmp を使用します。

5
birgire

ループ内でこの種のソートはできません。しかし、あなたはあなた自身の関数を書くことによってすることができます

これが私の解決策です: PS!ニーズPHP 5.4+

STEP 1

wpse161553_loop_sort($tag='')という名前の関数を作成します。これはメインのクエリで単一のタグで動作します。

STEP 2

あなたはメインのクエリーからpostオブジェクトを取得する必要があります。それらはすでに利用可能で、$wp_query->posts;によってアクセスすることができます。 (利用可能なオブジェクトの完全なリストとそれらへのアクセス方法については、 WP_Post を参照してください。).

STEP 3

新しいカウンターを作成して開始します。このカウンタは後で配列キーを$wp_query->posts;から変更するために使用されます。

STEP 4

バックエンドに設定されているposts_per_pageオプションを取得します。この値は、目的のタグを持たないすべての投稿のカウンタに追加されます。これにより、これらすべての投稿が目的のタグ投稿を超えて進みます。

STEP 5

ループ内で、 has_tag() を使用して各投稿を目的のタグと照合します。投稿に目的のタグがある場合は、現在のカウンタ値をそのまま配列($c)にプッシュします。投稿に目的のタグがない場合は、現在のカウンタの値にposts_per_pageの値を加えて$cにプッシュします。

STEP 6

2つの配列を結合するには array_combine を使用してください。新しく作成された配列$cは、投稿の配列の配列キーを置き換えます

STEP 7

array_combineで作成した新しい配列を新しいキーに従ってソートするには、 ksort を使用します。これにより、投稿が投稿日順にソートされるように配列がソートされます。また、目的のタグの投稿が最初に表示され、次に残りの投稿が表示されます。

ステップ8

array-values を使用してキーをリセットし、0から開始して数値を1ずつ増やします。

STEP 9

ループを巻き戻すために、ループを巻き戻します。

STEP 10

$wp_query->posts内の元の配列の設定を解除して、作成した新しい配列と置き換えます。 $wp_query->postsは新しく順序付けされたポストオーダーを持つ配列を保持します

ALL TOGETHER NOW !!

次のコードはあなたのfunctions.phpに入ります

function wpse161553_loop_sort($tag='') {
    global $wp_query;
    $posts = $wp_query->posts; // Gets all post data from the main query

    $c = []; // Going to hold an array of new keys for later use
    if ( have_posts() ) {
        $count = 0; //Start the counter
        $ppp = get_option('posts_per_page'); // Gets the backend posts per page option set. Will be used in conjustion with the counter

        while ( have_posts() ) {
            the_post();
                if( '' != $tag && has_tag($tag)) { // This will be the tag to test against, your desired tag
                    $c[] = $count++;
                }else{
                    $c[] = $ppp + $count++; // Adds posts per page value to each count to advance posts without desired tag past desired tag
                }
        }
    } 

    $posts_reordered  = array_combine( $c, $posts ); // Reset each post from main query's key with the new keys created by $c
        $posts_sorted = ksort($posts_reordered); // Sort the new array according to key
    $posts_reordered  = array_values($posts_reordered); // Reset keys to start at zero and increment by one

    rewind_posts(); // Reset the loop so we can run the loop again

    unset($wp_query->posts); //unset the original $wp_query->posts object array
    $wp_query->posts = $posts_reordered; // Set $wp_query->posts to the new reordered array

}

ITの使い方

あなたのcategory.php、あるいはそれに関してはどんなテンプレートでも、ループのすぐ上に以下を貼り付けてください。他に何も変更する必要はありません。

wpse161553_loop_sort( 'NAME OF THE TAG TO APPEAR FIRST' );

NAME OF THE TAG TO APPEAR FIRSTは投稿が最初に現れる希望のタグの名前です。

3
Pieter Goosen

アイデアのドラフトを簡単に概説しているだけなので、私はこれをまったく考えてテストしていないことに注意してください。あなたがこのようにソートアクションを実行できることは確かですが。さて、私が考えていたのは、なぜthe_postsにフックしてソートをするためにusortを使わないのかということです。それ以外のすべて、特に条件は、これがすべてのクエリで実行されるわけではなく、実際の使用例に依存することを確認するためのものです。

add_action(
    'the_posts',
    'wpse161553_posts_with_tags_on_top_of_category',
    10,
    2
);
function wpse161553_posts_with_tags_on_top_of_category(
    $posts,
    $wp_query
) {
    // we want this for one specific category
    $the_category = 'abc';
    // we want the post with this tag on top 
    $the_tag      = 'xyz';

    if (
        $wp_query->is_main_query()
        && is_category( $the_category )
    ) {
        // getting an array of post ids from category with tag
        $posts_with_tag = new WP_Query(
            array(
                'category_name' => $the_category,
                'tag'           => $the_tag,
                'fields'        => 'ids'
            )
        );  
        // performing usort on referenced posts object
        usort(
            $posts,
            function (
                $post
            ) use (
                $posts_with_tag
            ) {
                // puts posts from the $posts_with_tag->posts array to the top
                if(
                    in_array (
                        $post->ID,
                        (array) $posts_with_tag->posts 
                     )
                ) {
                    return -1;
                } else {
                    return 1;
                }
            }
        );
    }

    return $posts;
} 
2
Nicolai