Come posso eseguire una query per i post tramite meta-chiave parziale?


9

Ho una funzione che memorizza lo stato "mi piace" per un post come meta post. Voglio associare quel "mi piace" con l'utente a cui è piaciuto, quindi ho impostato un campo personalizzato chiamato "like_status_ {user_id}" (dove {user_id} è l'id dell'utente attualmente connesso) che memorizzo come 0 o 1. Quindi per un post con diversi "mi piace" ci sarebbero diversi meta valori nel db che sono impostati in questo modo:

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

....e così via.

Esistono potenzialmente migliaia di Mi piace su un post specifico. Come eseguirò una query che mostrava se anche a qualcun altro piaceva quel post?

Stavo pensando a qualcosa del genere:

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

Sto cercando di inviare una notifica a tutti coloro a cui è piaciuto un post quando a qualcun altro piace quel post ... qualcosa del tipo: "Ehi, a qualcun altro è piaciuto quel post che ti è piaciuto. Dovresti andare a dare un'occhiata!" Ma ho bisogno di un modo per scoprire se a qualcun altro è piaciuto quel post e, in caso affermativo, chi sarebbero, in modo da poterlo notificare.

Se non è possibile, potresti suggerire un modo migliore di archiviare questi dati come post_meta mantenendo comunque l'efficienza di aggiornare rapidamente lo stato di un singolo utente su un post?

Risposte:


6

Purtroppo non è possibile eseguire meta_queryun LIKEconfronto con il meta_keyvalore durante l'utilizzo WP_Query. Sono stato su questa strada ...

Invece hai un paio di altre opzioni se vuoi mantenere relazioni di stato simili come post meta e non meta utente e o meta in una tabella personalizzata.

opzione 1

  • non richiede alcuna modifica del tuo meta schema
  • usa la wpdbclasse per eseguire una query personalizzata

Esempio:

//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...           
    }

});

Nota: la logica potrebbe essere ulteriormente semplificata se lo si desidera.

opzione 2

  • richiede di modificare il meta schema
  • richiede di memorizzare l'id utente come meta valore
  • ti permette di usare WP_Queryinsieme ameta_query

L'opzione 2 richiede che tu cambi la tua meta-chiave da like_status_{user_id}qualcosa di universale come like_statuso liked_by_user_iddove a sua volta invece di memorizzare il valore di 1contro la chiave, invece memorizzi l'id dell'utente come valore.

//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);

        }

    });

});

1
Ora è dal 5.1 dare un'occhiata alla mia risposta qui sotto
K. Tromp

@ K.Tromp Huzzah!
Adam,

10

È abbastanza difficile rispondere concretamente alla tua domanda. La prima parte è facile però. Di recente ho fatto qualcosa di simile su StackOverflow

Le chiavi meta vengono confrontate e corrispondono esattamente. WP_Querynon abbiamo alcun mezzo per regolare questo comportamento con un semplice parametro, ma possiamo sempre introdurne uno noi stessi e quindi regolare la posts_whereclausola per fare un LIKEconfronto su meta-chiavi.

IL FILTRO

Questo è solo un filtro di base, regolalo secondo necessità.

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 );

Come puoi vedere, il filtro viene attivato solo quando impostiamo il nostro nuovo parametro personalizzato wildcard_on_keysu true. Quando questo viene verificato, cambiamo semplicemente il =comparatore in LIKEcomparatore

Solo una nota su questo, i LIKEconfronti sono intrinsecamente più costosi per eseguire altri confronti

LA DOMANDA

Puoi semplicemente interrogare i tuoi post come segue per ottenere tutti i post con meta-chiavi like_status_{user_id}

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

ALTRE DOMANDE

I campi personalizzati non influiscono sulle prestazioni, puoi leggere il mio post su questo argomento qui . Sono comunque preoccupato che tu dica che ogni post può avere centinaia o migliaia di Mi piace. Questo può colpirti quando ottieni prestazioni e memorizzi nella cache una così grande quantità di dati sul campo personalizzati. Può anche ostruire il tuo db con un'enorme quantità di dati di campo personalizzati non necessari che lo rendono piuttosto difficile da mantenere.

Non sono un grande fan della memorizzazione di dati serializzati in campi personalizzati in quanto non è possibile cercare o ordinare in base a dati serializzati. Suggerirei comunque di memorizzare tutti gli ID utente in un array in un campo personalizzato. Puoi semplicemente aggiornare l'array con l'ID utente quando a un utente piace un post. Ottenere i dati dei campi personalizzati e passare in rassegna l'array di ID e fare qualcosa con gli ID è facile. Dai un'occhiataget_post_meta()

Anche l'aggiornamento di un campo personalizzato è semplice. Per questo, dovrai esaminare update_post_meta(), non so come creare i tuoi campi personalizzati, ma update_post_meta()è sicuramente qualcosa che vorresti usare.

Se è necessario inviare e-mail o notifiche push quando si aggiorna un campo personalizzato, sono disponibili i seguenti hook con cui lavorare. ( Vedi update_metadata()per il contesto )

CONCLUSIONE

Appena prima di pubblicarlo, di nuovo, prima di seguire il percorso serializzato, assicurati che non sia necessario ordinare in base ai dati ordinati o cercare dati particolari all'interno dei dati serializzati.


1
Grazie per la tua spiegazione sulla performance di post_meta! Super utile.
codescribblr

Questa dovrebbe essere la risposta accettata, è sempre meglio usare i filtri piuttosto che usare query personalizzate. Inoltre, tieni presente che se stai usando get_posts anziché WP_Query devi passare suppress_filters => false o non attiverà il filtro. Per eseguire il LIKE sulla meta-chiave, devi anche mettere% davanti e dietro la chiave nell'array a seconda del tipo di ricerca simile che vuoi fare.
Earle Davies,

E come lo filtreresti se vuoi interrogare i post ma ESCLUDI tutti i post che hanno una meta chiave post per prefisso? (es. escludi tutti i post che hanno un post meta COME 'my_prefix_'?
gordie

5

Da wordpress 5.1 è ora possibile utilizzare meta query come: inserisci qui la descrizione dell'immagine


La fuga di caratteri di sottolineatura sembra essere un problema con questo metodo, ma per il resto sembra piuttosto buona. Grazie evidenziando.
Jake,

2

Se in seguito vuoi estenderlo, con statistiche, funzionalità, ecc. Più dettagliate, allora un'altra alternativa potrebbe essere: tabella / e personalizzata / e

  • pro : su misura per le tue esigenze e può essere indicizzato per prestazioni migliori.

  • contro : più lavoro

Potrebbe esserci anche una soluzione alternativa utilizzando una tassonomia personalizzata, che potrebbe fornire prestazioni di query migliori rispetto alle post meta query, a causa del modo in cui le tabelle principali sono indicizzate.

Sto cercando di inviare una notifica a tutti coloro a cui è piaciuto un post quando a qualcun altro piace quel post ... qualcosa del tipo: "Ehi, a qualcun altro è piaciuto quel post che ti è piaciuto. Dovresti andare a dare un'occhiata!" Ma ho bisogno di un modo per scoprire se a qualcun altro è piaciuto quel post e, in caso affermativo, chi sarebbero, in modo da poterlo notificare.

Non sei sicuro del tipo di notifiche che intendi qui, ma questo può rapidamente diventare ingombrante.

Esempio : un utente a cui piacciono ~ 1000 post e ogni post riceve ~ 1000 like, quindi ci sono 1M di notifiche nelle pipe, solo per quell'utente! Se si tratta di notifiche e-mail, il provider host potrebbe non essere felice e l'utente impazzirebbe. Ciò potrebbe anche essere costoso con un servizio di posta elettronica di terze parti.


In realtà sto inviando le notifiche solo una volta per persona per post. Quindi è meno di quanto sembri - sebbene sia ancora molto. Il motivo per cui sto provando a utilizzare le tabelle integrate è che mi piacerebbe poter utilizzare l'API REST WP standard lungo la strada in un'app reale con questi dati.
codescribblr

-1

Per la documentazione di WP_Meta_Query è possibile utilizzare l' compareargomento meta_querynell'argomento di WP_Query. Tuttavia, puoi solo confrontare il valuee non il, keyquindi potresti voler ripensare come strutturare questo.

Un likeargomento sarebbe simile al seguente:

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

$query = new WP_Query($arguments);

Dato che non è possibile effettuare una ricerca "MI PIACE" sul keysuggerirei di aggiungere i post piaciuti nella meta utente e fare una ricerca WP_User_Query per gli utenti a cui è piaciuto quel post:

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

$users = new WP_User_Query($arguments);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.