WP_Query: Erhalte 3 zufällige Beiträge von 10 neuesten

7

Wenn ich auf einer Site mit vielen Posts arbeite, muss ich 3 Posts aus einer bestimmten Kategorie anzeigen, aber alle müssen aus den letzten 10 auf der Site veröffentlichten Posts stammen. Ich kann entweder 3 völlig zufällige Beiträge greifen (was dazu neigt, sehr alte Beiträge zu ziehen) oder 10 Beiträge greifen (aber ich weiß nicht, wie ich dann die Reihenfolge zufällig festlegen und nur 3 anzeigen soll).

Bisher habe ich diese Frage:

$args = array(
    'post_type' => 'post',
    'category_name' => 'mycategory',
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC',
    'meta_key' => '_thumbnail_id',
    'no_found_rows' => 'true'
);
$query = new WP_Query( $args );

zusammen mit diesem Versuch, 3 zufällige Beiträge von den 10 abgefragten zu erhalten:

$randomPosts = shuffle( $query ); 
$randomPosts = array_slice( $randomPosts, 0, 3 );

Die Behandlung der Ergebnisse als Array funktioniert jedoch nicht, da es sich tatsächlich um ein Objekt handelt.
Mein einziger anderer Gedanke ist, 'posts_per_page' = 3mit 'orderby' => 'rand'3 zufällige Beiträge zu greifen und einen hinzuzufügen 'date_query', um ihn auf die letzten 6 Monate zu beschränken. Das wäre nah, aber es wäre vorzuziehen, die Abfrage auf die 10 neuesten Beiträge zu beschränken (sie können alle vor 3 Tagen oder vor 5 Monaten veröffentlicht werden, sie werden zusammen in ungleichmäßigen Schüben veröffentlicht).

Was ist der beste Ansatz?
Fragen Sie die 10 neuesten Beiträge ab, konvertieren Sie das Objekt dann in ein Array, mischen und schneiden Sie es und konvertieren Sie es zurück in ein Objekt. Gibt es eine einfachere und effizientere Möglichkeit, das Ziel zu erreichen?

WebElaine
quelle

Antworten:

12

Es gibt einen Weg mit:

$args = [
    'post_type'             => 'post',
    'posts_per_page'        => 10,
    'orderby'               => 'date',
    'order'                 => 'DESC',
    'no_found_rows'         => 'true',
    '_shuffle_and_pick'     => 3 // <-- our custom argument
];

$query = new \WP_Query( $args );

Dabei wird das benutzerdefinierte _shuffle_and_pickAttribut von diesem Demo-Plugin unterstützt:

<?php
/**
 * Plugin Name: Support for the _shuffle_and_pick WP_Query argument.
 */
add_filter( 'the_posts', function( $posts, \WP_Query $query )
{
    if( $pick = $query->get( '_shuffle_and_pick' ) )
    {
        shuffle( $posts );
        $posts = array_slice( $posts, 0, (int) $pick );
    }
    return $posts;
}, 10, 2 );
Birgire
quelle
Fantastisch, das hat genau das getan, was ich brauchte. Vielen Dank!
WebElaine
Ich
bin
Das ist eigentlich ganz einfach und ordentlich. Ich hoffe, meine Kunden werden Ihnen nie begegnen, da ich wahrscheinlich arbeitslos sein werde. haha
Christine Cooper
1
Das ist großartig - funktioniert wie ein Zauber, danke! Übrigens - ist der Backslash vor WP_Queryeinem Tippfehler oder ein hilfreicher Trick, den ich nicht kenne.
Squarecandy
1
@squarecandy danke für deinen Kommentar. Wenn wir in unserem Plugin einen benutzerdefinierten Namespace verwenden, müssen wir die WP_Query-Klasse "zurücksetzen", da es keinen speziellen WordPress-Namespace gibt.
Birgire
5

Sie können natürlich alle Beiträge übernehmen und das Ergebnis mit PHP randomisieren, wie in dieser Antwort gezeigt . Sie können die Randomisierung auch mit SQL durchführen.

Behandlung der Randomisierung in der Datenbank:

Es gibt keine eingebaute WordPress-Funktion (oder kein Argument), um dies zu erreichen. Sie können jedoch den posts_requestFilter verwenden, um die ursprüngliche SQL-Abfrage zu ändern, indem Sie WP_Querydie Randomisierung allein aus der Datenbank erreichen.

Sie können den folgenden CODE in der functions.phpDatei des aktiven Themas oder als neues benutzerdefiniertes Plugin verwenden:

<?php
/**
 *  Plugin Name: Randomize Posts
 *  Plugin URI: https://wordpress.stackexchange.com/a/260877/110572
 *  Description: Randomize posts basd on '_randomize_posts_count' query argument
 *  Author: Fayaz
 *  Version: 1.0
 *  Author URI: http://fmy.me/
 */

function wpse260713_randomize_posts( $sql_query, $query ) {
    $rand = (int) $query->get( '_randomize_posts_count' );
    if( $rand ) {
        $found_rows = '';
        if( stripos( $sql_query, 'SQL_CALC_FOUND_ROWS' ) !== FALSE ) {
            $found_rows = 'SQL_CALC_FOUND_ROWS';
            $sql_query = str_replace( 'SQL_CALC_FOUND_ROWS ', '', $sql_query );
        }
        $sql_query = sprintf( 'SELECT %s wp_posts.* from ( %s ) wp_posts ORDER BY rand() LIMIT %d', $found_rows, $sql_query, $rand );
    }
    return $sql_query;
}
add_filter( 'posts_request', 'wpse260713_randomize_posts', 10, 2 );

Dann können Sie die Abfrage wie folgt verwenden:

$args = array(
    'post_type' => 'post',
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC',
    'meta_key' => '_thumbnail_id',
    'no_found_rows' => 'true',
    '_randomize_posts_count' => 3
);
$query = new WP_Query( $args );

Vergleichende Analyse:

  • Diese Methode bringt nur die maximale Anzahl von Posts, die von _randomize_posts_countaus der Datenbank definiert wurden , anstatt alle Ergebnisse und Randomisierungen auf PHP-Seite zu bringen. Daher ist es besser für die Datenkommunikation mit der Datenbank optimiert. Dies ist besser, wenn Ihr Datenbankserver von Ihrem Webserver getrennt ist.

  • Wenn der Abfragecache nicht aktiviert ist , ist diese Lösung viel schneller, wenn der Unterschied zwischen der Anzahl der angezeigten zufälligen Beiträge und der Gesamtzahl der ausgewählten Beiträge groß ist. Beispiel: Wenn Sie 3 zufällige Beiträge aus den letzten 200 Beiträgen anzeigen, ist diese Methode viel schneller.

  • Wenn der Abfragecache aktiviert ist , ist die Methode von Birgire schneller, da spätere SQL-Anforderungen vermieden werden. Bei größeren Stichproben kann es jedoch immer noch langsamer sein, da Sie viele Informationen im Abfragecache speichern müssen.

  • Am besten, wenn Sie die Stichprobengröße sorgfältig abwägen und die Lösung auswählen, die besser zu Ihrem Anwendungsfall passt.

Hinweis: Zufällige Methoden sind im Vergleich zum allgemeinen CODE sehr langsam (und häufig nicht skalierbar). Seien Sie also unabhängig von der gewählten Methode besonders vorsichtig, wenn Ihre Stichprobengröße für die Randomisierung beträchtlich groß ist (z. B. Tausende).

Fayaz
quelle
1
Schön, andere Ansätze zu sehen. ps: es gibt viele interessante Problemumgehungen für langsame zufällige Reihenfolge. Ich erinnerte mich an nur mit einem spielen hier basierend auf einem interessanten Artikel hier von Josh Hartman. Ein weiterer Ansatz besteht darin, (nicht zu viele) IDs mit der Transienten-API zu speichern und die zufälligen von dort auszuwählen
;-)
1
Ich muss einige Zeit damit verbringen, herauszufinden, welche Option am effizientesten ausgeführt wird. Ich schätze das tolle Detail, das Sie aufgenommen haben!
WebElaine
Vielen Dank für diese Links @birgire, wird für viele Menschen nützlich sein.
Fayaz
3

Großartige Arbeit von Fayaz und Birgire - viel erfahrener als ich es mir vorgestellt hätte - aber ich denke, es gibt einen einfacheren Weg, es sei denn, ich verstehe die Frage nicht (durchaus möglich!): 1) benutze get_posts () oder am einfachsten , wp_get_recent_posts (), die beide standardmäßig Arrays zurückgeben, akzeptieren WP Query $ args und verwenden standardmäßig no_found_rows = true, 2) mischen das Array, 3) schneiden dann drei ab.

Auf diese Weise habe ich ein ähnliches Problem für mich selbst gelöst, an einem Punkt, an dem ich so gut wie nichts verstanden habe, verglichen mit meinem derzeitigen Verständnis, wie nahe ich nichts verstanden habe. Der Code von Birgire und Fayaz ist jedoch cool, also zögern Sie nicht, mit dem einen oder anderen zu gehen!

CK MacLeod
quelle
Vielen Dank, dass Sie diesen alternativen Ansatz hinzugefügt haben. Alle 3 Antworten erfüllen das Ziel und ich mag die Tatsache, dass für Ihre keine neue Funktion zum Thema hinzugefügt werden muss!
WebElaine