Come interrogare i post per chiave meta parziale?
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?
È 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.

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

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.

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

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

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.

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.

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