it-swarm.com.de

Zufällige Sortierung innerhalb einer bereits sortierten Abfrage

Ich habe eine funktionierende Abfrage, die eine Reihe von benutzerdefinierten Posts zurückgibt, die nach ihrer Paket-ID (ASC) sortiert sind. Für eine Abfrage mit 9 Ergebnissen kann dies beispielsweise Folgendes zurückgeben:

4 Beiträge (Beitrags-IDs 1,2,3,4) mit Paket-ID 1

3 Beiträge (Beitrags-IDs 5,6,7) mit Paket-ID 2

2 Beiträge (Beitrags-IDs 8,9) mit Paket-ID 3

Wenn diese Beiträge angezeigt werden, sind sie immer in derselben Reihenfolge. Mit anderen Worten, sie werden in der Reihenfolge von Post-ID 1 bis Post-ID 9 angezeigt.

Ich versuche, die Ergebnisse jeder Teilmenge (definiert durch die Paket-ID) nach dem Zufallsprinzip zu sortieren. Auf diese Weise würden die Beiträge als solche angezeigt:

Zufällige Anzeige der Post-IDs 1 bis 4 (zB 2,1,4,3)

Zufällige Anzeige der Post-IDs 5 bis 7 (zB 6,5,7)

Zufällige Anzeige der Post-IDs 8 bis 9 (zB 8,9)

Die Posts werden weiterhin nach der Paket-ID gruppiert, die Posts in den einzelnen Paketen werden jedoch zufällig angezeigt.

So sieht meine aktuelle Abfrage aus:

$args = array( 
    'post_type' => 'custom_post_type',
    'post_status' => 'publish',
    'posts_per_page' => 9,
    'meta_key' => 'pkg_id',
    'orderby' => 'pkg_id',
    'order' => 'ASC'
);

Was ich dachte, könnte funktionieren, aber nicht:

$args = array( 
    'post_type' => 'custom_post_type',
    'post_status' => 'publish',
    'posts_per_page' => 9,
    'meta_key' => 'pkg_id',
    'orderby' => array( 'pkg_id' => 'ASC', 'Rand' )
);

Irgendwelche Vorschläge, da ich völlig ratlos bin!

6
David Clough

Es ist nicht erforderlich, eine überbewertete Anzahl von Abfragen durchzuführen, um dies zu erreichen. Sie können immer noch only eine Abfrage, the_posts filter und einige PHP verwenden, um Ihren Code nach Bedarf zu sortieren.

Ich gehe davon aus, dass dies eine benutzerdefinierte Abfrage ist, die ich in Ihrer Frage gelesen habe, sodass wir Folgendes tun können:

  • Zunächst möchten wir einen benutzerdefinierten WP_Query-Parameter einführen, damit wir diesen Parameter als Auslöser für unseren the_posts-Filter verwenden können. Wir nennen diesen Parameter n wpse_custom_sort und er nimmt den Wert true an, um den Filter auszulösen

  • Als nächstes werden wir den the_posts-Filter verwenden, um die Beiträge nach benutzerdefinierten Feldern zu sortieren, diese Beiträge dann zufällig nach benutzerdefinierten Feldern zu sortieren und schließlich die sortierten Beiträge zurückzugeben

DER CODE

Nur ein paar Notizen

  • Der Code ist ungetestet und benötigt mindestens PHP 5.4

  • Ich habe get_post_meta() verwendet, um die benutzerdefinierten Feldwerte pro Beitrag zurückzugeben, da Sie ACF verwenden. Möglicherweise müssen Sie dies anpassen, um get_field() zu verwenden. Ich bin nicht mit ACF vertraut, daher müssen Sie diesen Teil sortieren. Die Logik würde jedoch immer noch dieselbe bleiben

  • Denken Sie daran, dass das Abfragen benutzerdefinierter Felder keine zusätzlichen Abfragen zur Folge hat, da sie zwischengespeichert werden. Dies ist eine sehr schlanke und optimierte Methode, um Ihr Endziel zu erreichen

Hier ist der Code für die benutzerdefinierte Abfrage. Sie müssen lediglich den zusätzlichen Parameter zu Ihren Abfrageargs in Ihrer benutzerdefinierten Seitenvorlage hinzufügen

// Run your query normally
$args = [
    'wpse_custom_sort' => true, // This parameter will trigger or the_posts filter
    // Your query args here
];
$q = new WP_Query( $args );

// Your loop as normal

Jetzt werden wir unseren Filter ausführen ( dies geht in functions.php oder vorzugsweise in ein benutzerdefiniertes Plugin )

/**
 * Function to flatten a multidimentional array (for later use)
 * 
 * Credit to zdenko
 * @link https://Gist.github.com/kohnmd/11197713
 */
function flatten_array( $arg ) 
{
    return is_array( $arg ) 
        ? 
        array_reduce( $arg, function ( $c, $a ) 
            { 
                return array_merge( $c, flatten_array( $a ) ); 
            }, [] ) 
        : 
        [$arg];
}

// The the_posts filter
add_filter( 'the_posts', function ( $posts, $q )
{
    // First we need remove our filter
    remove_filter( current_filter(), __FUNCTION__ );

    // Check if our custom parameter is set and is true, if not, bail early
    if ( true !== $q->get( 'wpse_custom_sort' ) )
        return $posts; 

    // Before we do any work, and to avoid WSOD, make sure that the flatten_array function exists
    if ( !function_exists( 'flatten_array' ) )
        return $posts;

    // Our custom parameter is available and true, lets continue
    // Loop through the posts
    $major_array = [];
    foreach ( $posts as $p ) {
        $meta = get_post_meta(
            $p->ID,
            'pkg_id',
            true
        );

        // Bail if we do not have a $meta value, just to be safe
        if ( !$meta )
            continue;

        // Sanitize the value
        $meta = filter_var( $meta, FILTER_SANITIZE_STRING );

        // Lets build our array
        $major_array[$meta][] = $p;
    }

    // Make sure we have a value for $major_array, if not, bail
    if ( !$major_array )
        return $posts;

    // Lets randomize the posts under each custom field
    $sorted = [];
    foreach ( $major_array as $field ) 
        $sorted[] = shuffle( $field );

    // Lets flatten and return the array of posts
    $posts = flatten_array( $sorted );

    return array_values( $posts );
}, 10, 2 );
6
Pieter Goosen

Nicht möglich mit einer einzelnen Abfrage, müssten Sie 3 separate Abfragen durchführen, die jeweils auf die verschiedenen "Paket-IDs" abzielen und diese Abfragen als Rand ordnen.

$args1 = array(
    'post_type' => 'custom_post_type',
    'orderby' => 'Rand',
    'meta_query' => array(
        array(
            'key' => 'pkg_id',
            'value' => 1, // you will have to check if this is correct
        )
    )
);

$args2 = array(
    'post_type' => 'custom_post_type',
    'orderby' => 'Rand',
    'meta_query' => array(
        array(
            'key' => 'pkg_id',
            'value' => 2, // you will have to check if this is correct
        )
    )
);

$args3 = array(
    'post_type' => 'custom_post_type',
    'orderby' => 'Rand',
    'meta_query' => array(
        array(
            'key' => 'pkg_id',
            'value' => 3, // you will have to check if this is correct
        )
    )
);

Dadurch werden Ihre Posts in ihre "Paket-IDs" unterteilt und jeder Satz wird in zufälliger Reihenfolge angeordnet

1
ngearing

Wenn wir verwenden:

$args = array( 
    'post_type'      => 'custom_post_type',
    'post_status'    => 'publish',
    'posts_per_page' => 9,
    'meta_key'       => 'pkg_id',
    'orderby'        => array( 'pkg_id' => 'ASC', 'Rand' => 'DESC' )
);

dann bekommen wir den bestellungsteil als:

ORDER BY wp_postmeta.meta_value ASC, Rand() DESC

Dies scheint zu funktionieren, aber der DESC wird nicht benötigt.

Beachten Sie jedoch, dass die Bestellung nach Rand() nicht gut skaliert. In diesem Fall ist die Methode von @PieterGoosen möglicherweise besser für Sie geeignet.

1
birgire

Eine Ergänzung zu Pieter Goosen Antwort.

Ich musste seinen Code am Ende ändern, da shuffle ($ field) einen Boolen zurückgibt, nicht das gemischte Array selbst. Also habe ich eine Reihe von Booleschen Werten, keine Reihe von (Post-) Arrays. Um das erwartete Ergebnis zu erzielen, habe ich Folgendes getan:

  //Instead of 
    foreach ( $major_array as $field ) 
        //Shuffle returns boolean, so $sorted will be a
        $sorted[] = shuffle( $field );  

 // I went with
    foreach ( $major_array as $field ) {
        shuffle( $field );   // 1. Shuffle $field, which is an array
        $sorted[] = $field;  // Then add this 
    }
0
chrwald