web-dev-qa-db-ja.com

異なる投稿をクエリ投稿

私はカテゴリーをランダムに並べ替えて投稿しようとしていますが、作者がそれ自体を繰り返さないようにしています。

だから私は意図したとおりに動作するこのクエリを持っていますが、著者がそれらの4つの投稿で繰り返す可能性があります。だから私はそれがそうではないことを確認することができる方法はありますか?

私は$ wpdbを使うことを考えていましたが、もっと直接的な解決策を望んでいました。

$args = array (
'post_type'              => 'post',
'post_status'            => 'publish',
'category_name'          => 'premium',
'orderby'                => 'Rand',
'posts_per_page'         => 4,
'post__not_in'           => get_option( 'sticky_posts' ),
'date_query'             => array(
    array(
         array(
                'before' => 'this week'
        ) 
    ),
),
);
$query = new WP_Query( $args );

編集:

私はこれをループの中で試しています。しかし、何らかの理由で1つの投稿のみが表示され、$ temp配列にはすべての重複が表示されたままになります。

$temp=array();

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

 $author_id = the_author_meta( 'ID' );
 if( !in_array($author_id, $temp) ):
  array_Push($temp, $author_id);
  //loop stuff
 endif;
endwhile;endif;wp_reset_query();
3
CiprianD

あなたが頼んでいることで、それがまた信頼できるものである高性能の簡単な方法を思いつくことは本当に難しいです。 @birgireがすでに述べたように、彼の解決策は信頼できませんが、テストによると、平均約0.015秒で2 dbクエリで最も速くクロッキングするようです。

彼の答え へのコメントでの@ birgireと私の間の簡単な議論から、私はWordpressが提供するものでそれを試してみることにしました。これは最も信頼性の高い方法ですが、平均価格が約0.05秒で20 dbのクエリで実行されるため、ある程度のコストがかかります。

本当の大きな問題は、ランダムな結果を求める要求のために、どんな種類のキャッシュも使用できないことです。そのため、時間とdb呼び出しを削減するための他の方法を検討する必要がありました。

最初のセクションでは、 この解決法 を使って、ランダムに必要な作者の数だけを取得するためにpre_user_queryのSQLクエリを変更するためにWP_User_Queryを使用します。コードのこの部分は本当に速いです。パフォーマンスを向上させるために、著者IDのみを取得するようにWP_User_Queryを設定しました。これですべてが必要になりました。このセクションでは、2 dbの時点で0.002秒のクエリが発生します。

各作者から1つの投稿を受け取るには、それぞれに1つのWP_Queryを実行する必要があります。これは、合計で4つのケースに相当します。これは機能のかなり高価な面です。クエリを本当に遅くする要因は、ランダムな順序が必要で、ジョイン句を使用するtax_queryを実行しているという事実です。

このセクションをスピードアップできる唯一の方法は、投稿IDも取得することでした。全体として、これは投稿IDを取得してから別のWP_Queryを実行するよりも、投稿全体を取得して表示するよりも早くなりました。私は7つのクエリでWP_Queryの追加のインスタンスを実行することを少なくしました

わかりました、十分な話、ここに機能はあります:(多少の微調整を使用できます

function wpse177162_random_author_posts($number = 4, $args = [])
{

    function my_pre_user_query( $q )
    {

        $limit = preg_replace( '/[^\d]/', '', $q->query_limit );

        $from   = 'WHERE 1=1';
        $to     = sprintf( 'WHERE Rand()<(SELECT ((%d/COUNT(*))*10) FROM %susers)', 
                            $limit, 
                            $GLOBALS['wpdb']->prefix 
                 );

        $q->query_where   = str_replace( $from, $to, $q->query_where );
        $q->query_orderby = ' ORDER BY Rand() ';

        // remove the hook    
        remove_action( current_filter() , __FUNCTION__ );
    }

    $user_query_args = [
        'who'    => 'authors',
        'fields' => 'ID',
        'number' => $number,
    ];

    add_action( 'pre_user_query', 'my_pre_user_query' );
    $user_query = new WP_User_Query($user_query_args);
    remove_action( 'pre_user_query', 'my_pre_user_query' );

    $users = $user_query->results;
    $post_ids = '';
    if ($users) {

        foreach ($users as $user) {

            $user_args = [
                'author' => $user,
                'fields' => 'ids',
             'no_found_rows' => true
        ];
            $combined_args = wp_parse_args($args, $user_args);
            $q = new WP_Query($combined_args);

            $q_posts[] = $q->posts;

        }

        foreach ($q_posts as $q_post) {

            foreach ($q_post as $v ) {

                $post_ids[] = $v;

            }

        }

    }
    return (array) $post_ids;

}

機能に関するいくつかの注意事項

  • 最初のパラメータ$numberは、取得する作者の数です。

  • 2番目のパラメータは$argsで、これはWP_Queryで使用されるパラメータと同じであり、クエリ引数としてWP_Queryに直接渡されます。これとまったく同じ方法でこれを使用できますが、1つの例外を除いて、作成者パラメータを設定しないでください。これは関数を壊します。

それがどのように使用されるかに来るために、あなたはそれからあなたのテンプレートの中でそれをこのように使うでしょう

$author_posts = wpse177162_random_author_posts(4, array('posts_per_page' => 1, 'cat' => 1, 'orderby' => 'Rand'));
$q = new WP_Query(array('post__in' => $author_posts));

すでに述べたように、追加のWP_Queryの理由はパフォーマンスのためです。これを行うとテストでより良い数値が得られたためです。

編集

@birgireからの推薦で、私はdb呼び出しを節約するためにno_found_rowsで上記のコードを更新しました。パフォーマンスはわずかに向上しましたが、テストでは4 dbの呼び出しを節約できましたが、時間は基本的に同じです。

update_post_meta_cacheupdate_post_term_cacheは、実際にはクエリを完了するのにかかる時間を2倍にし、クエリはずっと20に固定されたままです。だから行く方法ではありません:-)

1
Pieter Goosen

好奇心から、私は静的SQLクエリで遊んだし、これはうまくいくようだった:

SELECT r.post_author, r.ID, r.post_title FROM (
    SELECT  p.post_author, p.ID, p.post_title
    FROM wp_posts p 
    INNER JOIN wp_term_relationships tr ON ( p.ID = tr.object_id ) 
    WHERE    p.post_date < '2015-02-05 00:00:00'
         AND p.ID NOT IN (10,20) 
         AND tr.term_taxonomy_id IN (1)
         AND p.post_type = 'post' 
         AND p.post_status = 'publish' 
    ORDER BY Rand() 
) as r 
GROUP BY r.post_author
LIMIT 0,4

最初に私はpost_authorフィールドで直接グループ化し、Rand()で順序付けしようとしましたが、それから集約されていないフィールドはそれと一緒には働きませんでした。

しかしもちろんこれはあまり柔軟ではありません;-)

2
birgire

動作するように縫い合わせる別の解決策が説明されています: ここ

クエリの前にフィルタを追加します。

function filter_authors($groupby) {
 global $wpdb;
 $groupby = " {$wpdb->posts}.post_author";
 return $groupby;
}

add_filter('posts_groupby','filter_authors');

あとで削除するのを忘れないでください。

remove_filter('posts_groupby','filter_authors');

この解決策は非常にうまく機能するようにつながっています。

0
CiprianD