Wie frage ich nach Beiträgen nach partiellem Metaschlüssel ab?

9

Ich habe eine Funktion, die den "Gefällt mir" -Status für einen Beitrag als Beitragsmeta speichert. Ich möchte dieses "Gefällt mir" dem Benutzer zuordnen, dem es gefallen hat. Daher richte ich ein benutzerdefiniertes Feld mit dem Namen "Gefällt mir_Status_ {Benutzer_ID}" (wobei {Benutzer_ID} die ID des aktuell angemeldeten Benutzers ist) ein, das ich als 0 oder speichere 1. Für einen Beitrag mit mehreren "Likes" gibt es also mehrere Meta-Werte in der Datenbank, die wie folgt eingerichtet sind:

'meta_key' = 'like_status_0'
'meta_value' = 1
'meta_key' = 'like_status_2'
'meta_value' = 1
'meta_key' = 'like_status_34'
'meta_value' = 1

....und so weiter.

Es gibt möglicherweise Tausende von Likes in einem bestimmten Beitrag. Wie würde ich eine Abfrage ausführen, die anzeigt, ob jemand anderes diesen Beitrag auch mag?

Ich dachte so etwas:

$query = new WP_Query(array(
    'meta_key' => 'like_status_{user_id}',
    'meta_value' => 1,
));

Ich versuche, eine Benachrichtigung an alle zu senden, denen ein Beitrag gefallen hat, wenn jemand anderes diesen Beitrag mag ... so etwas wie "Hey, jemand anderem hat dieser Beitrag gefallen, den Sie mögen. Sie sollten ihn sich ansehen!" Aber ich brauche einen Weg, um herauszufinden, ob jemand diesen Beitrag gemocht hat und wenn ja, wer er wäre, damit ich ihn benachrichtigen kann.

Wenn dies nicht möglich ist, können Sie eine bessere Methode zum Speichern dieser Daten als post_meta vorschlagen und gleichzeitig die Effizienz der schnellen Aktualisierung des Status eines einzelnen Benutzers in einem Beitrag beibehalten?

Codescribblr
quelle

Antworten:

6

Leider können Sie bei meta_queryVerwendung keinen LIKEVergleich mit dem meta_keyWert durchführen WP_Query. Ich war auf diesem Weg ...

Stattdessen haben Sie einige andere Optionen, wenn Sie ähnliche Statusbeziehungen als Post-Meta und nicht als Benutzer-Meta und / oder Meta in einer benutzerdefinierten Tabelle beibehalten möchten.

Option 1

  • erfordert keine Änderung Ihres Meta-Schemas
  • verwendet wpdbclass, um eine benutzerdefinierte Abfrage durchzuführen

Beispiel:

//when a user likes a post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "like_status_{$current_user_id}", 1, false);

//later in the request...
global $wpdb;

$results = $wpdb->get_results(
    "
    SELECT meta_key 
    FROM {$wpdb->prefix}postmeta 
    WHERE meta_key 
    LIKE 'like_status_%'
    ",
    ARRAY_N
);

$results = array_map(function($value){

    return (int) str_replace('like_status_', '', $value[0]);

}, $results);

array_walk($results, function($notify_user_id, $key){

    //apply to all users except the user who just liked the post
    if ( $notify_user_id !== $current_user_id ) {
        //notify logic here...           
    }

});

Hinweis: Die Logik kann auf Wunsch weiter vereinfacht werden.

Option 2

  • erfordert, dass Sie Ihr Meta-Schema ändern
  • erfordert, dass Sie die Benutzer-ID als Metawert speichern
  • ermöglicht es Ihnen, WP_Queryzusammen mit zu verwendenmeta_query

Option 2 erfordert, dass Sie Ihren Metaschlüssel von like_status_{user_id}etwas Universellem ändern, z. B. like_statusoder liked_by_user_idwo, anstatt den Wert von 1gegen den Schlüssel zu speichern, stattdessen die Benutzer-ID als Wert speichern.

//when a user likes a post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "liked_by_user_id", $current_user_id, false);

//later in the request
$args = array(
    'post_type'  => 'post', //or a post type of your choosing
    'posts_per_page' => -1,
    'meta_query' => array(
        array(
            'key' => 'liked_by_user_id',
            'value' => 0,
            'type' => 'numeric'
            'compare' => '>'
        )
    )
);

$query = new WP_Query($args);   

array_walk($query->posts, function($post, $key){

    $user_ids = get_post_meta($post->ID, 'liked_by_user_id');

    array_walk($user_ids, function($notify_user_id, $key){

        //notify all users except the user who just like the post
        if ( $notify_user_id !== $current_user_id ) {

            //notify logic here...
            //get user e.g. $user = get_user_by('id', $notify_user_id);

        }

    });

});
Adam
quelle
1
Es ist jetzt seit 5.1, schauen Sie sich meine Antwort unten an
K. Tromp
@ K.Tromp Huzzah!
Adam
10

Es ist ziemlich schwierig, Ihre Frage konkret zu beantworten. Der erste Teil ist jedoch einfach. Ich habe kürzlich etwas Ähnliches beim Stackoverflow gemacht

Metaschlüssel werden verglichen und stimmen genau überein. WP_QueryIch habe keine Möglichkeit, dieses Verhalten mit einem einfachen Parameter anzupassen, aber wir können immer selbst einen einführen und dann die posts_whereKlausel anpassen , um einen LIKEVergleich mit Metaschlüsseln durchzuführen.

DER FILTER

Dies ist nur ein grundlegender Filter. Passen Sie ihn nach Bedarf an.

add_filter( 'posts_where', function ( $where, \WP_Query $q )
{ 
    // Check for our custom query var
    if ( true !== $q->get( 'wildcard_on_key' ) )
        return $where;

    // Lets filter the clause
    $where = str_replace( 'meta_key =', 'meta_key LIKE', $where );

    return $where;
}, 10, 2 );

Wie Sie sehen, wird der Filter nur ausgelöst, wenn wir unseren neuen benutzerdefinierten Parameter wildcard_on_keyauf setzen true. Wenn dies auscheckt, wechseln wir einfach den =Komparator zum LIKEKomparator

Nur eine Anmerkung dazu: LIKEVergleiche sind von Natur aus teurer als andere Vergleiche

DIE ABFRAGE

Sie können Ihre Beiträge einfach wie folgt abfragen, um alle Beiträge mit Metaschlüsseln zu erhalten like_status_{user_id}

$args = [
    'wildcard_on_key' => true,
    'meta_query'      => [
        [
            'key'   => 'like_status_',
            'value' => 1,
        ]
    ]
];
$query = new WP_Query( $args );

ANDERE FRAGE

Benutzerdefinierte Felder haben keinen Einfluss auf die Leistung. Sie können meinen Beitrag zu diesem Thema hier lesen . Ich bin jedoch beunruhigt darüber, dass Sie sagen, dass jeder Beitrag Hunderte oder Tausende von Likes haben kann. Dies kann Sie beim Abrufen und Zwischenspeichern einer so großen Menge benutzerdefinierter Felddaten beeinträchtigen. Es kann auch Ihre Datenbank mit einer großen Menge unnötiger benutzerdefinierter Felddaten verstopfen, was die Wartung ziemlich schwierig macht.

Ich bin kein großer Fan von der Speicherung von serialisierten Daten in benutzerdefinierten Feldern, da man nicht nach serialisierten Daten suchen oder bestellen kann. Ich würde jedoch vorschlagen, alle Benutzer-IDs in einem Array unter einem benutzerdefinierten Feld zu speichern. Sie können das Array einfach mit der Benutzer-ID aktualisieren, wenn ein Benutzer einen Beitrag mag. Es ist einfach, die benutzerdefinierten Felddaten abzurufen, das Array der IDs zu durchlaufen und etwas mit den IDs zu tun. Schau es dir anget_post_meta()

Das Aktualisieren eines benutzerdefinierten Felds ist ebenfalls einfach. Dafür müssen Sie prüfen update_post_meta(), ich weiß nicht, wie Sie Ihre benutzerdefinierten Felder erstellen, aber update_post_meta()ist definitiv etwas, das Sie verwenden möchten.

Wenn Sie beim Aktualisieren eines benutzerdefinierten Felds E-Mails oder Push-Benachrichtigungen senden müssen, stehen Ihnen die folgenden Hooks zur Verfügung. ( Siehe update_metadata()Kontext )

FAZIT

Bevor Sie dies erneut veröffentlichen, stellen Sie sicher, dass Sie nicht nach den sortierten Daten sortieren oder nach bestimmten Daten in den serialisierten Daten suchen müssen, bevor Sie den serialisierten Weg gehen.

Pieter Goosen
quelle
1
Vielen Dank für Ihre Erklärung zur Leistung von post_meta! Super nützlich.
Codescribblr
Dies sollte die akzeptierte Antwort sein. Es ist immer besser, Filter zu verwenden, als benutzerdefinierte Abfragen zu verwenden. Beachten Sie außerdem, dass Sie, wenn Sie get_posts anstelle von WP_Query verwenden, unterdrücken_filters => false durchlaufen müssen, da sonst der Filter nicht ausgelöst wird. Um das LIKE für den Metaschlüssel auszuführen, müssen Sie außerdem% vor und hinter den Schlüssel im Array setzen, je nachdem, welche Art von ähnlicher Suche Sie durchführen möchten.
Earle Davies
Und wie würden Sie es filtern, wenn Sie Beiträge abfragen möchten, aber alle Beiträge mit einem Beitrags-Metaschlüssel nach Präfix ausschließen möchten? (zB alle Beiträge mit einem Beitrags-Meta wie 'my_prefix_' ausschließen?
gordie
5

Seit WordPress 5.1 ist es jetzt möglich, Meta-Abfragen wie folgt zu verwenden: Geben Sie hier die Bildbeschreibung ein

K. Tromp
quelle
Das Entkommen von Unterstrichen scheint ein Problem bei dieser Methode zu sein, aber ansonsten sieht es ziemlich gut aus. Vielen Dank hervorheben.
Jake
2

Wenn Sie dies später mit detaillierteren Statistiken, Funktionen usw. erweitern möchten, könnte eine weitere Alternative sein: benutzerdefinierte Tabelle (n)

  • Profis : Auf Ihre Bedürfnisse zugeschnitten und kann für eine bessere Leistung indiziert werden .

  • Nachteile : Mehr Arbeit

Möglicherweise gibt es auch eine Problemumgehung mit einer benutzerdefinierten Taxonomie, die aufgrund der Indizierung der Kerntabellen eine bessere Abfrageleistung als Post-Meta-Abfragen bietet.

Ich versuche, eine Benachrichtigung an alle zu senden, denen ein Beitrag gefallen hat, wenn jemand anderes diesen Beitrag mag ... so etwas wie "Hey, jemand anderem hat dieser Beitrag gefallen, den Sie mögen. Sie sollten ihn sich ansehen!" Aber ich brauche einen Weg, um herauszufinden, ob jemand diesen Beitrag gemocht hat und wenn ja, wer er wäre, damit ich ihn benachrichtigen kann.

Ich bin mir nicht sicher, welche Art von Benachrichtigungen Sie hier meinen, aber dies kann schnell sperrig werden.

Beispiel : Ein Benutzer, der ~ 1000 Beiträge mag und jeder Beitrag ~ 1000 Likes erhält, dann gibt es 1 Million Benachrichtigungen in den Pipes, nur für diesen Benutzer! Wenn dies E-Mail-Benachrichtigungen sind, ist der Host-Anbieter möglicherweise nicht zufrieden und der Benutzer wird verrückt. Dies kann auch bei einem E-Mail-Dienst eines Drittanbieters teuer sein.

Birgire
quelle
Ich sende die Benachrichtigungen eigentlich nur einmal pro Person und Post. Es ist also weniger als es sich anhört - wenn auch immer noch viel. Der Grund, warum ich versuche, integrierte Tabellen zu verwenden, ist, dass ich die Standard-WP-REST-API später in einer tatsächlichen App mit diesen Daten verwenden möchte.
Codescribblr
-1

Gemäß der WP_Meta_Query- Dokumentation können Sie das compareArgument im meta_queryArgument von WP_Query verwenden. Sie können jedoch nur die valueund nicht die vergleichen, keysodass Sie möglicherweise überlegen möchten, wie Sie dies strukturieren.

Ein likeArgument würde so aussehen:

$arguments = array(
    'meta_query' => array(
        array(
            'key' => 'foo',
            'value' => 'ba',
            'compare' => 'LIKE'
        )
    )
);

$query = new WP_Query($arguments);

Da Sie keine "LIKE" -Suche für das durchführen können, keywürde ich vorschlagen, dass Sie die gewünschten Beiträge in das Benutzer-Meta einfügen und eine WP_User_Query- Suche nach Benutzern durchführen, denen dieser Beitrag gefallen hat:

$arguments = array(
    'meta_query' => array(
        array(
            'key' => 'liked_post',
            'value' => '<post_id>'
        )
    )
);

$users = new WP_User_Query($arguments);
LonnyLot
quelle