it-swarm.com.de

Nach mehreren Metafeldern sortieren

Ich habe zwei benutzerdefinierte Felder:

  • meta_key1 ist boolesch (0 oder 1).
  • meta_key2 ist ein Datumswert - 20150623 zum Beispiel.

Nicht alle meta_key2 Felder haben einen expliziten Wert. Es sieht so aus, als würden sie als leere Zeichenfolge '' behandelt.

Ich möchte alle Posts finden, deren meta_key2 (Datums-) Wert größer als heute ist oder deren meta_key1-Wert wahr ist.

Dies ist die Reihenfolge, in der sie angezeigt werden sollen.

  1. key2.meta_value >= today ASC
  2. key1.meta_value = TRUE ordered by date ASC (mit zuerst angegebenen Daten).

Ein Teil des Problems besteht darin, dass Felder mit einem leeren Datumsparameter als 0 behandelt werden und daher in der Reihenfolge ASC an erster Stelle stehen. Ich habe versucht, COALESCE zu verwenden, um dies zu erklären, und hatte einige Erfolge, aber ich habe an einem Teil aufgehängt. Ich kann die Posts, die key1.meta_value = FALSE und key2.meta_value is >= today enthalten, nicht in der Reihenfolge ASC anzeigen.

Hier ist meine Frage:

$meta_key1 = 'prog_ongoing';
$meta_key2 = 'prog_date_start';
$start_date = date('Ymd');

$postids = $wpdb->get_col( $wpdb->prepare( 
"
SELECT      DISTINCT key1.post_id
FROM        $wpdb->postmeta key1
INNER JOIN  $wpdb->postmeta key2
            ON key2.post_id = key1.post_id
            AND key2.meta_key = %s
WHERE       key1.meta_key = %s
            AND key1.meta_value is TRUE
            OR key2.meta_value >= %d
ORDER BY    COALESCE(NULLIF(key1.meta_value, 0), 0) DESC, COALESCE(NULLIF(key2.meta_value, ''), $start_date) ASC, key2.meta_value ASC 
",
$meta_key2,
$meta_key1,
$start_date
) );

Ich bin nicht sicher, ob meine COALESCE-Anweisung für key1.meta_value etwas bewirkt. Vielen Dank für jeden Einblick.

2
eleclair

Ein Problem bei der Abfrage besteht darin, dass die Selbstverknüpfung mit der mehrdeutigen WHERE ein gekreuztes Dataset ergibt (das von der DISTINCT maskiert wird). Daher ist es einfacher, wp_post als Basis für das Anhängen der Verknüpfungen zu verwenden, die genau den Schlüsseln entsprechen. z.B

    SELECT      p.ID, key1.meta_value as prog_ongoing, key2.meta_value as prog_date_start
    FROM        $wpdb->posts p
    INNER JOIN  $wpdb->postmeta key1
                ON key1.post_id = p.ID
                AND key1.meta_key = %s
    INNER JOIN  $wpdb->postmeta key2
                ON key2.post_id = p.ID
                AND key2.meta_key = %s

dies ergibt einen linearen Datensatz. Dann könnten Sie die WHERE-Klausel hinzufügen (oder nicht), um die Daten einzuschränken:

    WHERE       key1.meta_value IS TRUE OR key2.meta_value >= %d

und für den ORDER BY eine CASE Anweisung verwenden, sortiere einzelnes Feld:

    ORDER BY    CASE
                    WHEN key2.meta_value >= %d THEN CONCAT('A', key2.meta_value)
                    WHEN key1.meta_value AND key2.meta_value THEN CONCAT('B', key2.meta_value)
                    WHEN key1.meta_value THEN 'C'
                    ELSE 'D'
                END ASC

oder etwas ähnliches, wobei die prepare args sein müssen:

    $meta_key1,
    $meta_key2,
    $start_date, $start_date

Sie können den Filter posts_orderby verwenden, um mit WP_Query etwas Ähnliches zu tun (obwohl eine Methode verwendet wird, die gekreuzte Datasets erzeugt und die die Verwendung eines GROUP BY erfordert, was zu Komplikationen führen kann). Zum Beispiel

$args = array(
    'posts_per_page' => -1,
    'post_type' => 'cpt_program',
    'meta_query' => array(
        'ongoing' => array(
            'key' => 'prog_ongoing',
        ),
        'start_date' => array(
            'key' => 'prog_date_start',
        )
    ),
);

add_filter( 'posts_orderby', $func = function ( $orderby, $query ) {
    $start_date = date('Ymd');
    global $wpdb;
    $orderby = $wpdb->prepare(
        "
        CASE
            WHEN mt1.meta_value >= %d THEN CONCAT('A', mt1.meta_value)
            WHEN {$wpdb->postmeta}.meta_value AND mt1.meta_value THEN CONCAT('B', mt1.meta_value)
            WHEN {$wpdb->postmeta}.meta_value THEN 'C'
            ELSE 'D'
        END ASC
        "
        , $start_date
    );
    return $orderby;
}, 10, 2 );
$query = new WP_Query( $args );
remove_filter( 'posts_orderby', $func, 10, 2 );
2
bonger

Erster Durchgang für eine Lösung. Es verwendet die neue Metasortierung, die in 4.2 eingeführt wurde:

 <?php
    $args = array(
        'posts_per_page' => -1,
        'meta_query' => array(
            'relation' => 'OR',
            'ongoing' => array(
                'key'     => 'prog_ongoing',
                'value'   => 1
            ),
            'start_date' => array(
                array(
                    'key' => 'prog_date_start',
                    'value'   => date('Ymd'),
                    'type'    => 'numeric',
                    'compare' => '>='
                )
            )
        ),
        'orderby' => 'start_date ongoing',
        'order'   => 'ASC',
    );

    $programs = new WP_Query($args);
    ?>
    <?php while($programs->have_posts()): $programs->the_post(); ?>
        <h1><?php the_title(); ?></h1>
    <?php endwhile; ?>

Ich denke, ich habe die Logik richtig verstanden, aber lass es mich wissen, wenn es anders ist

BEARBEITEN

Sie können die neue Syntax ausprobieren, um sie in Wordpress 4.2 nach mehreren benutzerdefinierten Feldern zu sortieren

3
Manny Fleurmond

Warum nicht WP_Query() benutzen? Viel einfacher so:

    <?php
    $args = array(
        'posts_per_page' => -1,
        'meta_query' => array(
            'relation' => 'OR',
            array(
                'key'     => 'prog_ongoing',
                'value'   => 1
            ),
            array(
                'relation' => 'AND',
                array(
                    'key' => 'prog_date_start',
                    'value'   => date('Ymd'),
                    'type'    => 'numeric',
                    'compare' => '<='
                ),
                array(
                   'key' => 'prog_date_start',
                    'value'   => 1,
                    'type'    => 'numeric',
                    'compare' => '>'
                )
            )
        ),
        'orderby' => 'meta_value_num date',
        'order'   => 'ASC',
        'meta_key' => 'prog_date_start'
    );

    $programs = new WP_Query($args);
    ?>
    <?php while($programs->have_posts()): $programs->the_post(); ?>
        <h1><?php the_title(); ?></h1>
    <?php endwhile; ?>
0
passatgt