Komplexe custom_field-Suche mit meta_query

Lesezeit: 5 Minuten

Benutzer-Avatar
trex005

Hintergrund

Ich verwende Advanced Custom Fields Pro, um meine benutzerdefinierten Felder zu verwalten, und sie haben ein “Wiederholungsfeld”, das Unterfelder enthält, die als gespeichert werden repeatername_X_fieldname wobei X die Zeilennummer des Repeaters ist.

Ich habe einen benutzerdefinierten Beitragstyp student das hat den Repeater attendance was beinhaltet date und class.

Wenn also ein Schüler an einer Klasse teilnimmt, wird seine Anwesenheit wie folgt gespeichert

  • meta_key:’Anwesenheit_X_Datum’ meta_wert:’20170701′
  • meta_key:’Anwesenheit_X_Klasse’ meta_wert:’Geschichte 101′

Um nach Schülern zu suchen, die an einem bestimmten Kurs teilgenommen oder innerhalb eines bestimmten Datumsbereichs teilgenommen haben, muss ich mich einklinken get_meta_sql und konvertieren Sie meine meta_query benutzen LIKE Anstatt von = wenn der Wert enthält %

function key_rewrite($parts){
    foreach($parts as &$part){
        $part = preg_replace("/(meta_key = )(\'[^']*[%][^']*\')/", "meta_key LIKE $2", $part);
    }
    return $parts;
}
add_action( 'get_meta_sql', 'key_rewrite');

Damit kann ich so etwas machen

$args = array(
    'post_type' => 'student',
    'meta_query' => array(
        array(
            'key'=>'attendance_%_class',
            'compare'=>'=',
            'value'=>'History 101'
        )
    )
);
$my_query = new WP_Query($args);

um nach Personen zu suchen, die an History 101 OR teilgenommen haben

$args = array(
    'post_type' => 'student',
    'meta_query' => array(
        array(
            'key'=>'attendance_%_date',
            'compare'=>'>=',
            'value'=>'20170101'
        )
    )
);

Um nach allen zu suchen, die dieses Jahr teilgenommen haben.

Problemteil 1

Ich muss in der Lage sein, nach jedem zu suchen, der dieses Jahr an „History 101“ teilgenommen hat.

Zunächst scheint es, als würde ein einfaches AND auf der meta_query ausreichen:

$args = array(
    'post_type' => 'student',
    'meta_query' => array(
        'relation' => 'AND',
        array(
            'key'=>'attendance_%_class',
            'compare'=>'=',
            'value'=>'History 101'
        ),
        array(
            'key'=>'attendance_%_date',
            'compare'=>'>=',
            'value'=>'20170101'
        )
    )
);

Da die Wildcards jedoch nicht verknüpft sind, könnte dies tatsächlich jemanden zurückgeben, der letztes Jahr „Geschichte 101“ besucht hat, aber dieses Jahr eine andere Klasse.

Problemteil 2

ich eigentlich müssen in der Lage sein, eine Liste von allen zu bekommen, die dieses Jahr an „Geschichte 101“ teilgenommen haben, aber in der vergangenen Woche überhaupt nicht zum Unterricht erschienen sind. Dies verkompliziert das Problem weiter, da ich meta_query’s kombinieren muss EXISTS und NOT EXISTS mit einer zusätzlichen Bedingung. Oberflächlich betrachtet klingt dies mit verschachtelten meta_queries recht einfach:

$args = array(
    'post_type' => 'student',
    'meta_query' => array(
        'relation' => 'AND',
        array(
            'relation' => 'AND',
            array(
                //Just assume by some magic we resolved Problem part 1
                'key'=>'attendance_%_class',
                'compare'=>'=',
                'value'=>'History 101'
            ),
            array(
                'key'=>'attendance_%_date',
                'compare'=>'>=',
                'value'=>'20170101'
            )
        ),
        array(
            'relation' => 'AND',
            array(
                //again... magic!
                'key'=>'attendance_%_class',
                'compare'=>'=',
                'value'=>'History 101'
            ),
            array(
                'key'=>'attendance_%_date',
                'compare'=>'>',
                'value'=>'20170821'
            ),
            array(
                'key'=>'attendance_%_date',
                'compare'=>'NOT EXISTS'
            )
        )
    )
);

Offensichtlich ist dies mit logischen Problemen verbunden, aber beeindruckenderweise löst WordPress die meisten davon, indem es die Postmeta-Tabelle einmal pro Verwendung in die Metaabfrage einfügt. Leider bedeutet das, dass der > Datumsteil in der nicht verwendet wird NOT EXISTS ON und kann die somit nicht nutzen IS NULL zum Testen nicht vorhanden.

Ich verstehe, dass dies sehr komplex war, und wenn Sie mir gefolgt sind, bin ich sehr beeindruckt. Wenn nicht, stellen Sie bitte Fragen, damit ich bei der Klärung helfen kann.

Ja, mir ist bewusst, dass ich meine eigene Abfrage einfach komplett schreiben könnte, aber ich versuche, mich an die eingebauten WordPress-Tools zu halten.

HILFE!

Benutzer-Avatar
Plamen Nikolow

Ich war dort… beim Versuch, alles in eine komplexe Metaabfrage zu packen. Am Ende müssen Sie das generierte SQL manuell verarbeiten – Klammern verschieben, Operatoren ersetzen, Anführungszeichen usw.

Am Ende ist die Abfrage so komplex und hat mehrere JOINS zum postmeta Tabelle wird es zu teuer und langsam.

Ich habe mich entschieden, dies zu erreichen, indem ich einen etwas anderen Ansatz gewählt habe. Sie können also die Abfrage in mehrere Unterabfragen aufteilen und diese später mit kombinieren post__in und post__not_in,

Zum Beispiel für Problemteil 1:

/* Filter by class */
$history_students_ids = get_posts(array(
    'post_type'      => 'student',
    'fields'         => 'ids',
    'posts_per_page' => -1,
    'meta_query'     => array(
        array(
            'key'=>'attendance_%_class',
            'compare'=>'=',
            'value'=>'History 101'
        ),
    )
));

/* Filter by date */
$students = get_posts(array(
    'post_type' => 'student',
    'post__in' => $history_students_ids,
    'meta_query' => array(
        array(
            'key'=>'attendance_%_date',
            'compare'=>'>=',
            'value'=>'20170101'
        )
    )
));

Das gleiche gilt für Problemteil 2

$not_attended_history_students_ids = get_posts(array(
    'post_type' => 'student',
    'post__in' => $history_students_ids,
    'fields'         => 'ids',
    'posts_per_page' => -1,
    'meta_query' => array(
        array(
            'key'=>'attendance_%_date',
            'compare'=>'NOT EXISTS'
        )
    )
));

$students = get_posts(array(
    'post_type' => 'student',
    'post__in' => $not_attended_history_students_ids,
    'meta_query' => array(
        array(
            'key'=>'attendance_%_date',
            'compare'=>'>=',
            'value'=>'20170101'
        )
    )
)); 

Sie können die Anwesenheitsbedingung auf VORHANDEN umkehren und verwenden post__not_in… Ich hoffe, Sie haben es geschafft, die Idee zu verstehen.

  • Auf den ersten Blick scheint dies eine großartige Lösung zu sein. Bei Gelegenheit werde ich es testen und berichten.

    – trex005

    29. August 2017 um 18:23 Uhr

  • Okay. Dies funktioniert hervorragend für Teil 2. Teil 1 hat jedoch immer noch das gleiche Problem. Wenn zum Beispiel „Schüler 1“ letztes Jahr „Geschichte 101“ besucht hat, wäre er im ersten get_posts Ergebnis. Dann, wenn er dieses Jahr an “History 102” teilnehmen würde, wäre er im zweiten get_posts.

    – trex005

    29. August 2017 um 18:38 Uhr

  • versuche Wp_query post__not_in (codex.wordpress.org/Class_Reference/WP_Query) in der zweiten Schleife

    – Gnanasekaran Loganathan

    1. September 2017 um 10:48 Uhr


1385990cookie-checkKomplexe custom_field-Suche mit meta_query

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy