Meta dáta vo WordPresse slúžia na ukladanie dát, ktoré súvisia práve s konkrétnym článkom, napr. k článkom typu “hráč” priradíme meta dáta “pozicia”. Aj keď meta dáta sa do databázy ukladajú vždy ako string, existujú situácie, kedy tento string môže predstavovať serializované pole, dátum, číslo a pod. Pomerne jednoducho možno pridať vlastné meta dáta pomocou tzv. “custom fields” alebo s využitím pluginov ako napr ACF alebo CMB2.
WordPress ponúka celý rad funkcií, ktoré môžete volať odkiaľkoľvek a ktoré vám umožnia získať potrebné dáta. Medzi takéto funkcie patria aj funkcie pre získanie článkov či používateľov, konkrétne funkcia get_posts a funkcia get_users. Obe tieto funkcie maju jediný parameter, ktorý predstavuje pole s argumentami. Jedným z týchto argumentov je meta_query. Ten slúži na filtrovanie výsledkov na základe meta dát.
- ziskat data bez meta query a nasledne vo foreach getnut meta a porovnat – neefektivne, zataz na DB,
- vygenerovat samostatne meta queries pre každu položku pola a použiť operator LIKE – nebzepecne
- pouzit regex
Pred tým, než si ukážeme riešenia na praktíckom príklade, uvedieme alternatívne spôsoby ukladania meta udajov predstavujúce pole.
- Uloženie každej hodnoty z pola hodnôt do samostatného meta pola s hodnotami true/false, napríklad: position_obranca = 1, position_utocnik = 1, position_obranca = 1 a pod.
- Pouzitie vlastnej taxonomi a argumentu tax_query s operátorom IN vo funkcii get_posts()
Príklad z praxe
Predstavme si situáciu, že máme vo WordPresse vytvorený vlastný typ príspevku “player” a k nemu priradené meta pole “positions”. Toto pole môže nadobúdať hodnoty “brankar”, “utocnik” a “obranca”, pričom hráč musí mať priradenú aspoň jednu z týchto hodnôt.
Môžeme si to predstaviť ako multiple checkbox:
Teraz si predstavme, že potrebujeme vybrať vštkých útočníkov a obrancov, teda tých, ktorí majú meta pole “positions” s hodnotou “utocnik”, “obranca” alebo kombináciu týchto dvoch hodnôt. Budeme teda porovnávať pole hodnôt (utocnik, obranca) s polom hodnôt v meta poli “positions”. Keďže ide o hodnotu pola, takato hodnota sa ulozi do databázy ako serializovaný string. Napríklad hráč so všetkými pozíciami (brankar, utocnik, obranca) bude mať uloženú túto hodnotu takto:
a:3:{i:0;s:7:"brankar";i:1;s:7:"utocnik";i:2;s:7:"obranca";}
Ukážeme si spôsoby, ako dokážeme filtrovať príspevky na základe takto uloženej meta hodnoty v databáze.
1. spôsob - filtrovanie pomocou vlastnej PHP funkcie
Prvým riešenim takéhoto problému je, že si získame všetkých hráčov bez filtrovania (meta_query) a nasledne si každého hráča pomocou foreach prejdeme, získame jeho hodnotu meta “positions” a porovname ju pomocou funkcie array_intersect s polom hľadaných hodnôt (utocnik, obranca). Pre univerzálnosť si vytvoríme teda funkciu s troma argumentami:
- meta_key (text) – predstavuje kľúč meta hodnoty, ktorú budeme porovnávať
- posts (pole) – zoznam všetkych hráčov
- values (pole) – zoznam hľadaných hodnôt meta
function filter_posts_by_meta_array($meta_key,$posts, $values) {
$filtered_posts = [];
if (!empty($posts)) {
foreach ($posts as $post) {
$meta_values = get_post_meta($post->id, $meta_key, 1);
$intersect = array_intersect($values, $meta_values);
if (!empty($intersect))
$filtered_posts[] = $post;
}
}
return $filtered_posts;
}
Čiže v našom prípade bude použitie funkcie nasledovné:
$searched_values = [
'obranca',
'utocnik'
];
$posts = get_posts([
'post_type' => 'player',
'posts_per_page' => -1,
]);
$filtered_posts = filter_posts_by_meta_array('positions', $posts, $searched_values);
Nevýhodou tohto riešenia by bola zvýšená záťaž na databázu ako aj na server, kedže by sme museli dopytovat meta hodnotu pre každého hráča samostatne a pri veľkom počte hráčov by tento proces mohol spomalovať webstránku.
2. spôsob - viacnásobné meta_query
Ďalším zo spôsobov ako vyriešiť tento problém je, že použijeme argument meta_query pre každú hodnotu z hľadaných hodnôt s použitím operátora LIKE a s relačným vzťahom OR.
Čiže v našom prípade bude meta_query vyzerať nasledovne
$args = [
'post_type' => 'player',
'posts_per_page' => -1,
'meta_query' => [
'relation' => 'OR',
[
'key' => 'positions',
'value' => 'obranca',
'compare' => 'LIKE',
],
[
'key' => 'positions',
'value' => 'utocnik',
'compare' => 'LIKE',
]
]
];
$posts = get_posts($args);
Ak by sme si chceli toto riešenie ešte uľahčiť, môžeme si vytvoriť jednoduchú PHP funkciu na generovanie takýchto viacnásobných meta_query.
function px_create_meta_query_for_array($meta_key, $values, $relation = "OR"): array
{
$meta_query = [];
if (!empty($values)) {
$meta_query[$meta_key]['relation'] = $relation;
foreach ($values as $value) {
$meta_query[$meta_key][] = array(
'key' => $meta_key,
'value' => $value,
'compare' => 'LIKE'
);
}
}
return $meta_query;
}
Ako môžeme vidieť, funkcia obsahuje tri parametre:
- meta_key (text) – povinný parameter predstavujúci kľúč meta hodnoty, ktorú budeme porovnávať
- values (pole) – povinný parameter predstavujúci zoznam hľadaných hodnôt meta
- relation – nepovinný parameter s možnosťou výberu použitia relačného vzťahu OR (default) alebo AND
Posledný nepovinný parmeter slúži aj pre prípad, ak by sme potrebovali získať tie záznamy, ktorých meta hodnota “positions” je “obranca” a zároveň (AND) aj “utocnik”. Pri použití OR získame záznamy, ktorých meta hodnota “positions” je “utocnik” alebo “obracna”, resp. kombinácia oboch hodnôt.
Použitie tejto funkcie bude v našom prípade nasledovné:
$searched_values = [
'obranca',
'utocnik'
];
$meta_query = px_create_meta_query_for_array('positions', $searched_values);
$args = [
'post_type' => 'player',
'posts_per_page' => -1,
'meta_query' => $meta_query
];
$posts = get_posts($args);
Nevýhodou tohto riešenia je použitie operátora LIKE, ktorý hľadá zhodu aj medzi substringami, to znamená, že ak by sme napriklad hľadali hodnotu “auto” a existovala by aj meta hodnota s hodnotou “autobus”, aj táto hodnota by bola zahrnutá vo výsledku, čo však nie je správne. Avšak pokial máme vopred známe meta hodnoty a vieme túto chybovosť vylúčiť, čo je aj naš prípad, je toto riešenie správne.
3. spôsob - použitie operátora REGEXP
Na záver si popíšeme najlepšie riešenie tohto problému, a to použitie operátora REGEXP v argumente meta_query. Pre použitie tohto operátora v meta_query, potrebujeme prekonvertovať naše pole hľadných hodnôt do stringu, predstavujúci hľadané hodnoty oddelené znakom “|”. To docielíme použitím funkcie implode(). Okrem toho musí byť tento string ešte v obyčajných zátvorkách. Čiže v našom prípade bude string vyzerať takto “(obranca|utocnik)”
$searched_values = [
'obranca',
'utocnik'
];
$args = [
'post_type' => 'player',
'posts_per_page' => -1,
'meta_query' => [
[
'key' => 'positions',
'value' => '"('. implode('|', $searched_values) .')"', //'"(obranca|utocnik)"'
'compare' => 'REGEXP'
],
],
];
$posts = get_posts($args);