Come interrogare i post per chiave meta parziale?

26 mar 2016, 05:00:10
Visualizzazioni: 23.1K
Voti: 11

Ho una funzione che memorizza lo stato "mi piace" per un post come meta post. Voglio associare quel "mi piace" con l'utente che ha messo il like, 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 valori meta nel database 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.

Ci sono potenzialmente migliaia di mi piace su un post specifico. Come posso eseguire una query che mostri se qualcun altro ha messo mi piace a 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 che hanno messo mi piace a un post quando qualcun altro mette mi piace a quel post... qualcosa tipo "Ehi, qualcun altro ha messo mi piace al post che ti è piaciuto. Dovresti dare un'occhiata!" Ma ho bisogno di un modo per scoprire se qualcun altro ha messo mi piace a quel post e, in tal caso, chi sarebbero queste persone per poterle notificare.

Se non è possibile, potreste suggerire un modo migliore per memorizzare questi dati come post_meta mantenendo comunque l'efficienza dell'aggiornamento rapido dello stato dei mi piace di un singolo utente su un post?

0
Tutte le risposte alla domanda 5
3
12

È abbastanza difficile rispondere concretamente alla tua domanda. La prima parte è semplice però. Recentemente ho fatto qualcosa di simile su stackoverflow

Le meta key vengono confrontate e devono corrispondere esattamente. WP_Query non ha mezzi per modificare questo comportamento con un semplice parametro, ma possiamo sempre introdurne uno noi stessi e poi modificare la clausola posts_where per fare un confronto LIKE sulle meta key.

IL FILTRO

Questo è solo un filtro base, modificatelo come necessario.

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

    // Filtriamo la clausola
    $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_key a true. Quando questo controllo è positivo, semplicemente cambiamo l'operatore = con l'operatore LIKE

Solo una nota su questo, i confronti con LIKE sono intrinsecamente più costosi da eseguire rispetto ad altri confronti

LA QUERY

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

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

ALTRA DOMANDA

I custom field non hanno impatto sulle prestazioni, puoi leggere il mio post su questo argomento qui. Tuttavia sono preoccupato dal fatto che dici che ogni post può avere centinaia o migliaia di like. Questo può colpirti sulle prestazioni ottenendo e memorizzando nella cache una quantità così grande di dati dei custom field. Può anche intasare il tuo db con una grande quantità di dati non necessari nei custom field che rendono difficile la manutenzione.

Non sono un grande fan di memorizzare dati serializzati nei custom field poiché non è possibile cercare o ordinare per dati serializzati. Suggerirei invece di memorizzare tutti gli ID utente in un array sotto un unico custom field. Puoi semplicemente aggiornare l'array con l'ID utente quando un utente mette like a un post. Ottenere i dati del custom field e scorrere l'array di ID e fare qualcosa con gli ID è facile. Basta dare un'occhiata a get_post_meta()

Aggiornare un custom field è anche semplice. Per quello, dovrai guardare update_post_meta(), non so come crei i tuoi custom field, ma update_post_meta() è sicuramente qualcosa che vorrai usare.

Se hai bisogno di inviare email o notifiche push quando un custom field viene aggiornato, hai i seguenti hook disponibili con cui lavorare. (Vedi update_metadata() per contesto)

CONCLUSIONE

Prima di postare questo, ancora una volta, prima di prendere la strada della serializzazione, assicurati che non avrai bisogno di ordinare per i dati serializzati o cercare dati particolari all'interno dei dati serializzati.

26 mar 2016 09:09:10
Commenti

Grazie per la spiegazione sulle prestazioni di post_meta! Molto utile.

codescribblr codescribblr
26 mar 2016 20:25:14

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

Earle Davies Earle Davies
31 lug 2016 20:10:30

E come lo filtreresti se vuoi interrogare i post ma ESCLUDERE tutti i post che hanno una meta key con un prefisso? (es. escludere tutti i post che hanno una meta key LIKE 'my_prefix_' ?

gordie gordie
1 apr 2017 18:47:42
1

Da WordPress 5.1 è ora possibile utilizzare query meta come: descrizione dell'immagine

27 feb 2019 09:59:05
Commenti

La gestione degli underscore sembra essere un problema con questo metodo, ma per il resto sembra piuttosto buono. Grazie per averlo evidenziato.

Jake Jake
24 apr 2019 00:20:40
4

Sfortunatamente non è possibile eseguire una meta_query utilizzando un confronto LIKE sul valore meta_key quando si utilizza WP_Query. Ci sono passato anche io...

Invece hai un paio di altre opzioni se vuoi mantenere le relazioni di "mi piace" come meta dei post e non come meta degli utenti o meta in una tabella personalizzata.

Opzione 1

  • non richiede modifiche allo schema dei meta
  • utilizza la classe wpdb per eseguire una query personalizzata

Esempio:

//quando un utente mette "mi piace" a un post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "like_status_{$current_user_id}", 1, false);

//più tardi nella richiesta...
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){

    //applica a tutti gli utenti tranne quello che ha appena messo "mi piace"
    if ( $notify_user_id !== $current_user_id ) {
        //logica di notifica qui...           
    }

});

Nota: la logica potrebbe essere ulteriormente semplificata se lo desideri.

Opzione 2

  • richiede di modificare lo schema dei meta
  • richiede di memorizzare l'ID utente come valore del meta
  • consente di utilizzare WP_Query insieme a meta_query

L'opzione 2 richiede di cambiare la chiave meta da like_status_{user_id} a qualcosa di universale come like_status o liked_by_user_id dove invece di memorizzare il valore 1 nella chiave, memorizzi l'ID dell'utente come valore.

//quando un utente mette "mi piace" a un post...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "liked_by_user_id", $current_user_id, false);

//più tardi nella richiesta
$args = array(
    'post_type'  => 'post', //o un post type a tua scelta
    '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){
        
        //notifica tutti gli utenti tranne quello che ha appena messo "mi piace"
        if ( $notify_user_id !== $current_user_id ) {
                
            //logica di notifica qui...
            //ottieni l'utente es. $user = get_user_by('id', $notify_user_id);
            
        }

    });

});
26 mar 2016 09:11:51
Commenti

È dal 5.1, dai un'occhiata alla mia risposta qui sotto

K. Tromp K. Tromp
5 nov 2019 00:13:14

@K.Tromp Evviva!

Adam Adam
5 nov 2019 12:50:55

Aggiorna la risposta accettata per riflettere le ultime funzionalità di WP o segna la risposta di @K.Tromp come la più aggiornata

zumek zumek
5 mag 2020 05:23:40

Ormai obsoleto.

Michael Rogers Michael Rogers
5 gen 2021 00:20:43
1

Se in seguito vorrai estendere questa funzionalità con statistiche più dettagliate, caratteristiche aggiuntive, ecc., un'altra alternativa potrebbe essere: tabelle personalizzate

  • vantaggi: Personalizzate in base alle tue esigenze e possono essere indicizzate per migliorare le prestazioni.

  • svantaggi: Richiedono più lavoro

Potrebbe esserci anche una soluzione alternativa utilizzando una tassonomia personalizzata, che potrebbe offrire prestazioni di query migliori rispetto alle query sui post meta, grazie a come sono indicizzate le tabelle core.

Sto cercando di inviare una notifica a tutti coloro che hanno messo "mi piace" a un post quando qualcun altro mette "mi piace" a quel post... qualcosa tipo: "Ehi, qualcun altro ha messo 'mi piace' al post che ti è piaciuto. Dovresti andare a vederlo!" Ma ho bisogno di un modo per scoprire se qualcun altro ha messo "mi piace" a quel post e, in caso affermativo, chi sarebbe per poterli notificare.

Non sono sicuro di che tipo di notifiche tu intenda qui, ma questo può diventare rapidamente pesante.

Esempio: Un utente che mette "mi piace" a circa 1000 post e ogni post riceve circa 1000 "mi piace", allora ci sono 1M di notifiche in coda, solo per quell'utente! Se si tratta di notifiche via email, il provider di hosting potrebbe non essere contento e l'utente impazzirebbe. Potrebbe anche essere costoso con un servizio email di terze parti.

26 mar 2016 13:18:18
Commenti

In realtà sto inviando le notifiche solo una volta per persona per articolo. Quindi è meno di quanto sembri, anche se comunque molte. Il motivo per cui sto cercando di usare le tabelle integrate è che vorrei poter utilizzare la standard WP REST API in futuro in un'app reale con questi dati.

codescribblr codescribblr
26 mar 2016 20:23:06
0
-1

Secondo la documentazione di WP_Meta_Query, puoi utilizzare l'argomento compare nell'argomento meta_query di WP_Query. Tuttavia, puoi confrontare solo il value e non la key, quindi potresti voler ripensare a come strutturi questa operazione.

Un argomento like apparirebbe così:

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

$query = new WP_Query($arguments);

Dato che non puoi fare una ricerca 'LIKE' sulla key, suggerirei di aggiungere i post apprezzati nei metadati dell'utente e fare una ricerca con WP_User_Query per gli utenti che hanno apprezzato quel post:

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

$users = new WP_User_Query($arguments);
26 mar 2016 05:39:55