it-swarm.com.de

WP_Query orderby custom field dann post_date in einer Abfrage

Ich muss die ersten drei Beiträge nach einem benutzerdefinierten Feld und die nachfolgenden Beiträge nach post_date in einer Abfrage sortieren - zum Beispiel:

  • Beitrag 4 (field_order: 1)
  • Beitrag 3 (field_order: 2)
  • Beitrag 2 (field_order: 3)
  • Beitrag 1 (field_order: null)
  • Beitrag 0 (field_order: null)

Post 1 und Post 0 müssen von post_date bestellt werden.

Ich kann problemlos nach benutzerdefiniertem Feld bestellen, aber wenn ich einen Beitrag ohne benutzerdefiniertes Feld (Beitrag 1 & 0) hinzufüge, wird dieser nicht in der Abfrage angezeigt.

Unten ist die Abfrage, die ich derzeit versuche:

    $args = array(
        'post_type' => 'insights',
        'posts_per_page' => '9',
        'meta_query' => array(
            array(
                'key' => 'field_order',
                'value'   => '0',
                'compare' => '>'
            )
        ),
        'orderby' => array(
            'field_order' => 'ASC',
            'post_date' => 'ASC',
        ),
        'order' => 'ASC'
    );
5
londonfed

Mehrere meta_query-Argumente mit ORname__

Sie können das Argument 'relation' => 'OR' in meta_query mit zwei Gruppen von field_order-Argumenten verwenden: eines mit meta_value >= '0' und das andere mit NOT EXISTS, um die Hauptabfrage zu generieren.

        'meta_query'     => array(
            'relation'   => 'OR',
            field_order' => array(
                'key'       => 'field_order',
                'value'     => '0',
                'compare'   => '>=',
                'type'      => 'NUMERIC'
            ),  
            'field_order_withnulls' => array(
                'key'       => 'field_order',
                'compare'   => 'NOT EXISTS',
                'type'      => 'NUMERIC'
            )
        )

Ordnungsgemäße Bestellung bis

Wir können 'field_order_withnulls' => 'ASC' verwenden. Aufgrund des LEFT JOIN gibt es jedoch Zeilen mit nullfield_order Werten und solche, die vor numerischen field_order Werten in ASCorderby stehen.

Um das zu beheben, verwenden wir den Trick ORDER BY -field_order DESC wie beschrieben hier .

Dadurch wird die Reihenfolge korrigiert, indem DESCin ASCinvertiert wird, die Zeilen jedoch mit null-Werten nach den numerischen Werten beibehalten werden.

Implementieren des Operators - (inverse) in orderbyname__

Das Problem ist, dass WordPress keine direkte Möglichkeit zum Festlegen des Operators - (invers) in orderbybietet. Daher führen wir ein benutzerdefiniertes Attribut WP_Query mit dem Namen _inverse_order ein und implementieren es anschließend mit dem Filter posts_orderby.

Beispielcode:

    // posts_orderby filter callback function
    // place this function in theme's functions.php file or in a custom plugin
    function wpse311227_inverse_orderby( $orderby, $query ) {
        remove_filter( 'posts_orderby', 'wpse311227_inverse_orderby', 10, 2 );
        $idx = (int) $query->get( '_inverse_order' ) - 1;
        if( $idx >= 0 ) {
            $orders = preg_split( "/(?<=ASC|DESC),[\s]*/i", $orderby );
            if( $idx < count( $orders ) ) {
                $orders[$idx] = '-' . $orders[$idx];
            }
            return implode( $orders, ', ' );
        }

        return $orderby;
    }


    // adding the posts_orderby filter to implement the custom '_inverse_order' attribute
    // this should be placed just before the WP_Query call
    add_filter( 'posts_orderby', 'wpse311227_inverse_orderby', 10, 2 );
    $args = array(
        'post_type'      => 'insights',
        'posts_per_page' => '9',
        'meta_query'     => array(
            'relation'   => 'OR',
            field_order' => array(
                'key'       => 'field_order',
                'value'     => '0',
                'compare'   => '>=',
                'type'      => 'NUMERIC'
            ),  
            'field_order_withnulls' => array(
                'key'       => 'field_order',
                'compare'   => 'NOT EXISTS',
                'type'      => 'NUMERIC'
            )
        ),
        'orderby' => array(
            'field_order_withnulls' => 'DESC',
            'post_date'             => 'ASC'
        ),
        // this custom attribute is implemented in wpse311227_inverse_orderby() function
        // to correct the ordering by placing a '-' operator
        // value of _inverse_order attribute is the position of the
        // orderby attribute to be be inversed,
        // (position starts with 1)
        // in this case, since: 'field_order_withnulls' => 'DESC'
        // is in position 1 of 'orderby' attribute array, so:
        '_inverse_order'  => 1
    );
    $query = new WP_Query( $args );

Dadurch werden alle Posts mit field_order > 0 und die Posts ohne field_order-Metadaten in der erwarteten Reihenfolge erstellt.

Hinweis:Sie müssen in meta_query einen nicht leeren valuenamen__ übergeben, um NOT EXISTS zu überprüfen, ob die WordPress-Version unter 3.9 liegt. Überprüfen Sie diese Anmerkung aus dem Codex :

Aufgrund des Fehlers # 23268 ist ein Wert erforderlich, damit NOT EXISTS-Vergleiche vor 3.9 ordnungsgemäß funktionieren. Sie müssen eine Zeichenfolge für den Parameter value angeben. Ein leerer String oder NULL wird NICHT funktionieren. Bei Verwendung von NOT EXISTS wird jedoch eine beliebige andere Zeichenfolge den Trick ausführen und NICHT in Ihrem SQL-Code angezeigt.


Warnung:Dieser WP_Query verwendet zwei LEFT JOIN, was nicht sehr effizient ist. Auch wenn dies für einige tausend Beiträge erträglich ist. Ich habe mit mehr als 15.000 Posts getestet und die Abfrage dauert durchschnittlich ca. 0,3 Sekunden. Wenn Sie jedoch über Millionen oder sogar Hunderttausende von Posts verfügen, müssen Sie die Abfrage optimieren oder eine effizientere Methode finden, um dasselbe Ergebnis zu erzielen.

5
Fayaz