Cum să interoghez articolele după cheia meta parțială?
Am o funcție care stochează statusul de "like" pentru un articol ca meta post. Vreau să asociez acel "like" cu utilizatorul care l-a dat, așa că am configurat un câmp personalizat numit "like_status_{user_id}" (unde {user_id} este ID-ul utilizatorului conectat) pe care îl stochez ca 0 sau 1. Astfel, pentru un articol cu mai multe "like-uri" vor exista mai multe valori meta în baza de date configurate astfel:
'meta_key' = 'like_status_0'
'meta_value' = 1
'meta_key' = 'like_status_2'
'meta_value' = 1
'meta_key' = 'like_status_34'
'meta_value' = 1
...și așa mai departe.
Există potențial mii de like-uri pe un articol specific. Cum aș putea rula o interogare care să arate dacă altcineva a dat like acelui articol?
Mă gândeam la ceva de genul:
$query = new WP_Query(array(
'meta_key' => 'like_status_{user_id}',
'meta_value' => 1,
));
Încerc să trimit o notificare tuturor celor care au dat like unui articol atunci când altcineva dă like aceluiași articol... ceva de genul "Hei, altcineva a dat like articolului pe care l-ai apreciat. Ar trebui să verifici!" Dar am nevoie de o modalitate de a afla dacă altcineva a dat like acelui articol și, dacă da, cine sunt acești utilizatori pentru a-i putea notifica.
Dacă nu este posibil, puteți sugera o modalitate mai bună de a stoca aceste date ca post_meta păstrând în același timp eficiența actualizării rapide a statusului de like al unui singur utilizator pentru un articol?
Este destul de dificil să răspund concret la întrebarea ta. Prima parte este însă ușoară. Recent am făcut ceva similar pe stackoverflow
Cheile meta sunt comparate și trebuie să se potrivească exact. WP_Query
nu oferă nicio modalitate simplă de a ajusta acest comportament printr-un parametru, dar putem introduce noi înșine unul și apoi ajusta clauza posts_where
pentru a face o comparație de tip LIKE
pe cheile meta.
FILTRUL
Acesta este doar un filtru de bază, ajustează-l după nevoie.
add_filter( 'posts_where', function ( $where, \WP_Query $q )
{
// Verificăm variabila noastră personalizată de interogare
if ( true !== $q->get( 'wildcard_on_key' ) )
return $where;
// Filtrăm clauza
$where = str_replace( 'meta_key =', 'meta_key LIKE', $where );
return $where;
}, 10, 2 );
După cum poți vedea, filtrul este declanșat doar când setăm noul nostru parametru personalizat, wildcard_on_key
la true
. Când această verificare este adevărată, pur și simplu înlocuim operatorul =
cu operatorul LIKE
.
Doar o observație, comparațiile LIKE
sunt în mod inerent mai costisitoare decât alte comparații.
INTEROGAREA
Poți interoga postările în felul următor pentru a obține toate postările cu chei meta like_status_{user_id}
:
$args = [
'wildcard_on_key' => true,
'meta_query' => [
[
'key' => 'like_status_',
'value' => 1,
]
]
];
$query = new WP_Query( $args );
ALTA ÎNTREBARE
Câmpurile personalizate nu au un impact asupra performanței, poți citi postarea mea pe acest subiect aici. Totuși, sunt îngrijorat de faptul că spui că fiecare postare poate avea sute sau mii de aprecieri. Acest lucru poate afecta performanța la obținerea și stocarea în cache a unei cantități atât de mari de date din câmpuri personalizate. De asemenea, poate înfunda baza de date cu o cantitate enormă de date inutile din câmpuri personalizate, ceea ce o face greu de întreținut.
Nu sunt un mare fan al stocării datelor serializate în câmpuri personalizate, deoarece nu poți căuta sau ordona după date serializate. Aș sugera totuși stocarea tuturor ID-urilor de utilizator într-un singur câmp personalizat sub formă de array. Poți actualiza pur și simplu array-ul cu ID-ul utilizatorului atunci când un utilizator apreciază o postare. Obținerea datelor din câmpul personalizat și parcurgerea array-ului de ID-uri pentru a face ceva cu ele este simplă. Aruncă o privire la get_post_meta()
.
Actualizarea unui câmp personalizat este de asemenea ușoară. Pentru asta, va trebui să te uiți la update_post_meta()
, nu știu cum creezi câmpurile tale personalizate, dar update_post_meta()
este cu siguranță ceva ce ai vrea să folosești.
Dacă trebuie să trimiți emailuri sau notificări push atunci când un câmp personalizat este actualizat, ai la dispoziție următoarele hook-uri cu care poți lucra. (Vezi update_metadata()
pentru context)
CONCLUZIE
Înainte de a posta acest răspuns, din nou, înainte de a alege calea datelor serializate, asigură-te că nu vei avea nevoie să sortezi după aceste date sau să cauți anumite informații în interiorul lor.

Mulțumesc pentru explicația legată de performanța post_meta! Foarte utilă.

Acesta ar trebui să fie răspunsul acceptat, este întotdeauna mai bine să folosești filtre decât interogări personalizate. De asemenea, reține că dacă folosești get_posts în loc de WP_Query, trebuie să treci suppress_filters => false, altfel filtrul nu va fi declanșat. Pentru a efectua căutarea LIKE pe cheia meta, trebuie să adaugi % în față și în spatele cheii în array, în funcție de tipul de căutare LIKE pe care dorești să-l faci.

Din păcate, nu poți efectua o interogare meta_query
folosind o comparație LIKE
pe valoarea meta_key
atunci când utilizezi WP_Query
. Am trecut și eu prin asta...
În schimb, ai câteva alte opțiuni dacă dorești să menții relațiile de "like" ca metadate ale postărilor și nu ca metadate ale utilizatorilor sau metadate într-un tabel personalizat.
Opțiunea 1
- nu necesită modificarea schemei de metadate
- folosește clasa
wpdb
pentru a executa o interogare personalizată
Exemplu:
//când un utilizator apreciază o postare...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "like_status_{$current_user_id}", 1, false);
//mai târziu în cerere...
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){
//aplică tuturor utilizatorilor, exceptând utilizatorul care tocmai a dat like
if ( $notify_user_id !== $current_user_id ) {
//logică de notificare aici...
}
});
Notă: logica poate fi simplificată în continuare dacă dorești.
Opțiunea 2
- necesită modificarea schemei de metadate
- necesită stocarea ID-ului utilizatorului ca valoare meta
- îți permite să folosești
WP_Query
împreună cumeta_query
Opțiunea 2 necesită să schimbi cheia meta de la like_status_{user_id}
la ceva universal precum like_status
sau liked_by_user_id
, unde în loc să stochezi valoarea 1
împotriva cheii, stochezi ID-ul utilizatorului ca valoare.
//când un utilizator apreciază o postare...
$current_user_id = get_current_user_id();
add_post_meta($current_user_id, "liked_by_user_id", $current_user_id, false);
//mai târziu în cerere
$args = array(
'post_type' => 'post', //sau un tip de postare la alegere
'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){
//notifică toți utilizatorii, exceptând utilizatorul care tocmai a dat like
if ( $notify_user_id !== $current_user_id ) {
//logică de notificare aici...
//obține utilizatorul de ex. $user = get_user_by('id', $notify_user_id);
}
});
});

Actualizați răspunsul acceptat pentru a reflecta cele mai recente capabilități ale WP sau marcați răspunsul lui @K.Tromp ca fiind cel mai actualizat

Dacă ulterior doriți să extindeți acest lucru, cu statistici mai detaliate, funcționalități suplimentare etc., atunci încă o alternativă ar putea fi: tabele personalizate
avantaje: Personalizate în funcție de nevoile dumneavoastră și pot fi indexate pentru o performanță mai bună.
dezavantaje: Mai mult de lucru
Ar putea exista și o soluție alternativă folosind o taxonomie personalizată, care ar putea oferi o performanță mai bună la interogări decât interogările de post meta, datorită modului în care tabelele de bază sunt indexate.
Încerc să trimit o notificare tuturor celor care au apreciat un post când altcineva apreciază acel post... ceva de genul: „Hei, altcineva a apreciat postul pe care l-ai apreciat. Ar trebui să arunci o privire!” Dar am nevoie de o modalitate de a afla dacă mai cineva a apreciat acel post și, dacă da, cine sunt aceia pentru a le putea notifica.
Nu sunt sigur ce fel de notificări vă referiți aici, dar acest lucru poate deveni rapid greoi.
Exemplu: Un utilizator care apreciază ~ 1000 de postări și fiecare postare primește ~ 1000 de aprecieri, atunci există 1M de notificări în așteptare, doar pentru acel utilizator! Dacă acestea sunt notificări prin e-mail, atunci furnizorul de hosting s-ar putea să nu fie încântat, iar utilizatorul ar înnebuni. Acest lucru ar putea fi și costisitor cu un serviciu de e-mail terț.

De fapt, trimit notificările o singură dată per persoană pe postare. Deci este mai puțin decât sună — deși tot destul de mult. Motivul pentru care încerc să folosesc tabelele încorporate este că aș dori să pot folosi API-ul standard WP REST în viitor într-o aplicație reală cu aceste date.

Conform documentației WP_Meta_Query, puteți folosi argumentul compare
în argumentul meta_query
al WP_Query. Totuși, puteți compara doar pe value
și nu pe key
, așa că ar trebui să reconsiderați structura acestei abordări.
Un argument like
ar arăta astfel:
$arguments = array(
'meta_query' => array(
array(
'key' => 'foo',
'value' => 'ba',
'compare' => 'LIKE'
)
)
);
$query = new WP_Query($arguments);
Având în vedere că nu puteți face o căutare de tip 'LIKE' pe key
, vă sugerez să adăugați postările apreciate în metadatele utilizatorului și să faceți o căutare WP_User_Query pentru utilizatorii care au apreciat acea postare:
$arguments = array(
'meta_query' => array(
array(
'key' => 'liked_post',
'value' => '<post_id>'
)
)
);
$users = new WP_User_Query($arguments);
