web-dev-qa-db-ja.com

異なるカテゴリからのランダムな投稿を問い合わせる

私はカスタムではなく6つの通常のカテゴリーを持っています(各カテゴリーは5から10の投稿を持っています)そして私はページ上の各カテゴリーから1つのランダムな投稿を表示しようとしています。

出力に関する問題はランダムな投稿を取得することですが、いくつかの投稿は私がしたくない同じカテゴリから取得されます。これが私が使っているコードです:

$args_ = array(
    'posts_per_page' => 6,
    'orderby' => 'Rand',
    'exclude' => $postid , // the current post ID
    'category' => $cat_id_array // here is the array of categories
);

$myposts = get_posts( $args_ );
//var_dump($myposts); // I have duplicate category here

foreach ( $myposts as $post ) : setup_postdata( $post ); ?>
    <div class="col-md-4">
        <?php the_post_thumbnail( 'medium', array( 'class' => 'img-responsive' ) );?><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
    </div>
<?php endforeach;
wp_reset_postdata();

任意の助けがいただければ幸いです。

1
cadobe

ランダムな順序付けはSQLでは非常に高価な操作であり、非常に大きなサイトでは頭痛の種になる可能性があります。 6つのカテゴリのカテゴリからランダムな投稿を取得すると、6つの別々のクエリを実行する必要が生じる可能性があります。それぞれのクエリはランダムに並べられます。これは本当に銀行を破り、あなたを破産させる可能性があります。

あなたの答えとあなたがあなたが30の質問を実行していると言ったという事実を見ることから、これは非常に明白です。また、投稿のサムネイルはカスタムクエリ用にキャッシュされないため、投稿のサムネイルをクエリするたびにdb呼び出しを行うことになります。

別のアプローチを試してみましょう。もし私たちが賢いなら、私たちはあなたのクエリをほとんど何もしないように減らすことができます。これが私たちがやることです

  • データベースからすべての投稿を問い合わせます。これは非常に高価な操作であるため、ここで私たちは賢い必要があります。私たちが投稿から本当に必要とする唯一のものはそれらのIDです、それで私たちは投稿IDだけを問い合わせるでしょう、そしてそれは劇的にdb問い合わせと問い合わせを実行するのに費やす時間を減らすでしょう

  • すべての投稿IDを取得したら、カテゴリ別に並べ替えます

  • 次に、ソートされた配列から6つのランダムなIDをカテゴリごとに1つ選び、これを投稿を出力する「メイン」クエリに渡します。

最初の2つの操作は2つか3つのクエリしか必要としません、これはあなたがのようなプラグインで確認することができますQuery Monitor

いくつかのコードを見てみましょう:(注:すべてのコードはテストされていないのでPHP 5.4 +

質問

// Lets get all the post ids
$args = [
    'posts_per_page' => -1,
    'fields'         => 'ids' // Only get the post ID's
];
$ids_array = get_posts( $args );

// Make sure we have a valid array of ids
if ( $ids_array ) {
    // Lets update the post term cache
    update_object_term_cache( $ids_array, 'post' );

    // Loop through the post ids and create an array with post ids and terms
    $id_and_term_array = [];
    foreach ( $ids_array as $id ) {
        // Get all the post categories
        $terms = get_the_terms( $id, 'category' );

        // Make sure we have a valid array of terms
        if (    $terms
             && !is_wp_error( $terms )
        ) {
            // Loop through the terms and create our array with post ids and term
            foreach ( $terms as $term )
                $id_and_term_array[$term->term_id][] = $id;
        }
    }

    // TO BE CONTINUED......
}

$id_and_term_arrayは、キーがterm idで値がpost idの配列である配列を含む配列を含むべきです。私達は銀行を壊すことなくこれらすべてを作り出しました。クエリモニタをチェックすると、これらすべてがほんの2時間で2 dbの呼び出ししか必要としないことがわかります。私達は記憶をわずかに乱用したが、後に記憶を使い果たすことを避けるために何かを調べる。

ランダムIDの選択

次に行うことは$id_and_term_arrayをループ処理し、各term id配列からランダムな投稿IDを選ぶことです。また、現在の投稿IDを除外し、投稿が複数の用語に属している場合は必ず重複する投稿IDを避ける必要があります。

それでは、最後に配置した場所を続行します....

// Make sure we have a valid array
if ( $id_and_term_array ) {
    // Get the current post ID
    $current_post_id = get_the_ID();
    // If this is a single post page, we can do
    // $current_post_id = $GLOBALS['wp_the_query']->get_queried_object_id();

    // Lets loop through $id_and_term_array
    $unique_Rand_array = [];
    foreach ( $id_and_term_array as $value ) {
        // Shuffle the $value array to randomize it
        shuffle ( $value );

        // Loop through $value and get the first post id
        foreach ( $value as $v ) {
            // Skip the post ID if it mathes the current post or if it is a duplicate
            if ( $v == $current_post_id )
                continue;

            if ( in_array( $v, $unique_Rand_array ) )
                continue;

            // We have a unique id, lets store it and bail
            $unique_Rand_array[] = $v;

            break;
        }
    }
}

$unique_Rand_arrayに格納されているx個の一意の投稿IDを持つ配列ができました。これで、そのIDの配列を最後のクエリに渡すことができます

ファイナルクエリ

// First see if we have post ids in array
if ( $unique_Rand_array ) {
    // Lets run our query
    $final_args = [
        'posts_per_page' => 6,
        'post__in'       => shuffle( $unique_Rand_array ), // Randomize posts
        'orderby'        => 'post__in' // Keep post order the same as the order of post ids
    ];
    $q = new WP_Query( $final_args );

    // Lets cache our post thumbnails
    update_post_thumbnail_cache( $q );

    while ( $q->have_posts() ) :
        $q->the_post();

        ?>
        <div class="col-md-4">
            <?php the_post_thumbnail( 'medium', array( 'class' => 'img-responsive' ) );?>
            <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
        </div>
        <?php

    endwhile;
    wp_reset_postdata();
}

過渡期

最後にできることは、最初のクエリの結果を一時的に保存することです。これは、ページが読み込まれるたびにそのクエリを実行したくないためです。これにより、メモリの悪用が減り、回避されます。新しい投稿を公開したときにも、一時的な記事は削除されます

今すぐ全部

すべてをまとめましょう。

// Check if we have a transient
if ( false === ( $id_and_term_array = get_transient( 'random_term_post_ids' ) ) ) {

    // Lets get all the post ids
    $args = [
        'posts_per_page' => -1,
        'fields'         => 'ids' // Only get the post ID's
    ];
    $ids_array = get_posts( $args );

    // Define the array which will hold the term and post_ids
    $id_and_term_array = [];
    // Make sure we have a valid array of ids
    if ( $ids_array ) {
        // Lets update the post term cache
        update_object_term_cache( $ids_array, 'post' );

        // Loop through the post ids and create an array with post ids and terms
        foreach ( $ids_array as $id ) {
            // Get all the post categories
            $terms = get_the_terms( $id, 'category' );

            // Make sure we have a valid array of terms
            if (    $terms
                 && !is_wp_error( $terms )
            ) {
                // Loop through the terms and create our array with post ids and term
                foreach ( $terms as $term )
                    $id_and_term_array[$term->term_id][] = $id;
            }
        }
    }
    // Set our transient for 30 days
    set_transient( 'random_term_post_ids', $id_and_term_array, 30 * DAYS_IN_SECONDS );
}

// Make sure we have a valid array
if ( $id_and_term_array ) {
    // Get the current post ID
    $current_post_id = get_the_ID();
    // If this is a single post page, we can do
    // $current_post_id = $GLOBALS['wp_the_query']->get_queried_object_id();

    // Lets loop through $id_and_term_array
    $unique_Rand_array = [];
    foreach ( $id_and_term_array as $value ) {
        // Shuffle the $value array to randomize it
        shuffle ( $value );

        // Loop through $value and get the first post id
        foreach ( $value as $v ) {
            // Skip the post ID if it mathes the current post or if it is a duplicate
            if ( $v == $current_post_id )
                continue;

            if ( in_array( $v, $unique_Rand_array ) )
                continue;

            // We have a unique id, lets store it and bail
            $unique_Rand_array[] = $v;

            break;
        }
    }

    // First see if we have post ids in array
    if ( $unique_Rand_array ) {
        // Lets run our query
        $final_args = [
            'posts_per_page' => 6,
            'post__in'       => shuffle( $unique_Rand_array ), // Randomize posts
            'orderby'        => 'post__in' // Keep post order the same as the order of post ids
        ];
        $q = new WP_Query( $final_args );

        // Lets cache our post thumbnails
        update_post_thumbnail_cache( $q );

        while ( $q->have_posts() ) :
            $q->the_post();

            ?>
            <div class="col-md-4">
                <?php the_post_thumbnail( 'medium', array( 'class' => 'img-responsive' ) );?>
                <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
            </div>
            <?php

        endwhile;
        wp_reset_postdata();
    }
}

最後に、次のコードがあなたの関数ファイルに入ります。これは、新しい投稿が公開されたとき、投稿が削除されたとき、更新されたとき、または削除されていないときに一時的なデータを消去します。

add_action( 'transition_post_status', function () 
{
   delete_transient( 'random_term_post_ids' );
});
2
Pieter Goosen

私はちょうど私達のようなbueltgeの燻製を使ってそれを修正します:

foreach ( $cat_id_array as $cat ) :

    $args =  array( 'posts_per_page' => 1, 'cat' => $cat );
    $myposts = get_posts( $args );
    //var_dump($myposts);

    foreach($myposts as $posts) :
         var_dump($posts->ID);

    endforeach;
endforeach;

これは現在うまくいっています。ヘッドアップをありがとう。この特定のコードのクエリ数を減らすことはできますか? 30件のクエリとして表示されています

1
cadobe