Cum să utilizezi REGEXP în cheia meta_query din WP_Query
Știu că pot folosi REGEXP în WP_Query astfel:
$query = new WP_Query(array(
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'custom_fields',
'value' => 'foo[(][0-9][)]', // cu elemente regex
'compare' => 'REGEXP',
),
),
));
Dar am nevoie de expresii regulate și în cheie. Ca în acest exemplu:
$query = new WP_Query(array(
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'custom_fields[(][0-9][)]', // cu elemente regex
'value' => 'foo',
'compare' => 'REGEXP',
),
),
));
Există vreo metodă de a realiza acest lucru folosind un filtru? Sau trebuie să construiesc totul manual cu o interogare SQL personalizată?
Iată o idee experimentală:
Să presupunem că avem:
articolul A cu câmpul personalizat
location1ca UK - Londraarticolul B cu câmpul personalizat
location2ca Franța - Parisarticolul C cu câmpul personalizat
location3ca SUA - New York
Apoi am putea folosi, de exemplu:
$args = [
'meta_query' => [
'relation' => 'OR',
[
'key' => "^location[0-9]",
'_key_compare' => 'REGEXP',
'value' => 'Londra',
'compare' => 'LIKE',
],
[
'key' => 'location%',
'_key_compare' => 'LIKE',
'value' => 'Paris',
'compare' => 'LIKE'
],
[
'key' => 'location3',
'value' => 'New York',
'compare' => 'LIKE'
]
]
];
unde suportăm argumentul personalizat _key_compare cu următorul plugin:
<?php
/**
* Plugin Name: Extended Meta Key Search In WP_Query
* Description: Argument personalizat '_key_compare' ca REGEXP, RLIKE sau LIKE
* Plugin URI: http://wordpress.stackexchange.com/a/193841/26350
* Plugin Author: Birgir Erlendsson (birgire)
* Version: 0.0.3
*/
add_action( 'pre_get_posts', function( $q )
{
// Verifică interogarea meta:
$mq = $q->get( 'meta_query' );
if( empty( $mq ) )
return;
// Inițializare:
$marker = '___tmp_marker___';
$rx = [];
// Colectează toate sub-interogările meta care folosesc REGEXP, RLIKE sau LIKE:
foreach( $mq as $k => $m )
{
if( isset( $m['_key_compare'] )
&& in_array( strtoupper( $m['_key_compare'] ), [ 'REGEXP', 'RLIKE', 'LIKE' ] )
&& isset( $m['key'] )
) {
// Marchează cheia cu un șir unic pentru a securiza înlocuirile ulterioare:
$m['key'] .= $marker . $k; // Face marcatorul temporar adăugat unic
// Modifică variabila de interogare originală corespunzătoare:
$q->query_vars['meta_query'][$k]['key'] = $m['key'];
// Colectează:
$rx[$k] = $m;
}
}
// Nimic de făcut:
if( empty( $rx ) )
return;
// Obține acces la SQL generat al interogării meta:
add_filter( 'get_meta_sql', function( $sql ) use ( $rx, $marker )
{
// Rulează o singură dată:
static $nr = 0;
if( 0 != $nr++ )
return $sql;
// Modifică partea WHERE unde înlocuim marcatorii temporari:
foreach( $rx as $k => $r )
{
$sql['where'] = str_replace(
sprintf(
".meta_key = '%s' ",
$r['key']
),
sprintf(
".meta_key %s '%s' ",
$r['_key_compare'],
str_replace(
$marker . $k,
'',
$r['key']
)
),
$sql['where']
);
}
return $sql;
});
});
unde adăugăm marcatori unici pe fiecare cheie meta pentru înlocuirile de șiruri.
Rețineți că acest lucru nu suportă escaparea caracterelor regex, cum ar fi \( și \\.
Îmi plac acești parametri personalizați amuzanți pe care îi adaugi. ;-)
Pieter Goosen
Poate ca niște ajutoarele lui Moș Crăciun - de obicei fac totul să funcționeze magic în final ;-) @PieterGoosen
birgire
wow, omule... asta e uimitor. dar din păcate nu funcționează :( Am nume de chei precum custom_field_language(0)language în baza mea de date și expresia mea regulată custom_field_languages[(][0-9][)]language nu funcționează cu plugin-ul tău. Ai vreo idee?
Philipp Kühn
se pare că funcția de înlocuire de la finalul plugin-ului tău nu funcționează corect.
Philipp Kühn
mersi, am rezolvat asta. Am folosit $count++ în construcția unui șir de caractere când am uitat că trebuia să folosesc $count de două ori ;-) Nu aș recomanda utilizarea de caractere speciale în numele cheilor, în afară de underscore. Tu folosești paranteze în cheia ta. Ele au o semnificație specială în expresiile regulate. Deci ar trebui să le scapi cu \( și \) în REGEXP sau RLIKE, dar escaparea nu este suportată în plugin-ul meu. Ai putea încerca LIKE în schimb cu custom_field_language(%)language. @PhilippKühn
birgire
da. mulțumesc mult. codul tău reparat funcționează!!! dar mai este o problemă. dacă folosesc alt meta_query primesc întotdeauna zero rezultate cu orice relație. ca aici 'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'custom_field_location',
'value' => 'Berlin',
'compare' => '=',
),
array(
'key' => 'custom_field_languages[(][0-9][)]language',
'_key_compare' => 'REGEXP',
'value' => 'ak',
'compare' => 'LIKE',
),
)
Philipp Kühn
dacă afișez $sql['where'] pot vedea că fiecare cheie este înlocuită cu cea REGEXP. @birgire
Philipp Kühn
A fost încă o problemă legată de $count ;-) Te rog să verifici răspunsul actualizat, unde folosesc o cheie de array în schimb. @PhilippKühn
birgire
oh nu... am aflat că acest lucru nu suportă noile interogări meta imbricate introduse în wp 4.1 :( poveste fără sfârșit... @birgire
Philipp Kühn
aha, bun punct, poate voi pune asta pe GitHub în săptămânile următoare și voi încerca să o extind acolo ;-) @PhilippKühn
birgire
Asta ar fi minunat! Până atunci am găsit o soluție improvizată. Dar aș fi fericit să folosesc scriptul tău pentru că este o metodă mult mai elegantă. @birgire
Philipp Kühn
@birgire te-ai gândit vreodată să postezi asta pe GitHub, prietene?
Jacques Koekemoer
Răspunsul tău funcționează perfect la primul nivel al array-ului, de exemplu:
$args['meta_query'][] = array(
'key' => 'tour_itinerario_ciudades_repeater_%_tour_ciudades_nombre',
'_key_compare' => 'LIKE',
'value' => 'MEXICO',
'compare' => 'LIKE',
);
Am nevoie să fac unele modificări pentru a funcționa la al doilea nivel în array:
$args['meta_query'][] = array(
'relation' => 'OR',
array(
'key' => 'tour_itinerario_ciudades_repeater_%_tour_ciudades_nombre',
'_key_compare' => 'LIKE',
'value' => 'CONDESA',
'compare' => 'LIKE',
),
array(
'key' => 'tour_itinerario_ciudades_repeater_%_tour_ciudades_nombre',
'_key_compare' => 'LIKE',
'value' => 'Ciudad 1',
'compare' => 'LIKE',
)
);
Acum,
add_action('pre_get_posts', function( $q ) {
// Verifică interogarea meta:
$mq = $q->get('meta_query');
if (empty($mq))
return;
// Inițializare:
$marker = '___tmp_marker___';
$rx = [];
// Colectează toate sub-interogările meta, care folosesc REGEXP, RLIKE sau LIKE:
// Funcționează doar pentru primul nivel în array
foreach ($mq as $k => $m) {
if (isset($m['_key_compare']) && in_array(strtoupper($m['_key_compare']), [ 'REGEXP', 'RLIKE', 'LIKE']) && isset($m['key'])
) {
// Marchează cheia cu un șir unic pentru a securiza înlocuirile ulterioare:
$m['key'] .= $marker . $k; // Face marcatorul temporar adăugat unic
// Modifică variabila de interogare originală corespunzătoare:
$q->query_vars['meta_query'][$k]['key'] = $m['key'];
// Colectează:
$rx[$k] = $m;
}
}
// cod personalizat pentru a funcționa cu argumente în array multidimensional
foreach ($mq as $k => $m) {
foreach ($m as $k_i => $m_i) {
if (count($m_i) >= 3) {
if (isset($m_i['_key_compare']) && in_array(strtoupper($m_i['_key_compare']), [ 'REGEXP', 'RLIKE', 'LIKE']) && isset($m_i['key'])
) {
// Marchează cheia cu un șir unic pentru a securiza înlocuirile ulterioare:
$m_i['key'] .= $marker . $k_i; // Face marcatorul temporar adăugat unic
// Modifică variabila de interogare originală corespunzătoare:
$q->query_vars['meta_query'][$k][$k_i]['key'] = $m_i['key'];
// Colectează:
$rx[$k][$k_i] = $m_i;
}
}
}
}
// Nimic de făcut:
if (empty($rx))
return;
// Obține acces la SQL generat al interogării meta:
add_filter('get_meta_sql', function( $sql ) use ( $rx, $marker ) {
// Rulează o singură dată:
static $nr = 0;
if (0 != $nr++)
return $sql;
// Modifică partea WHERE unde înlocuim marcatorii temporari:
//PRIMUL NIVEL
foreach ($rx as $k => $r) {
$sql['where'] = str_replace(
sprintf(
".meta_key = '%s' ", $r['key']
), sprintf(
".meta_key %s '%s' ", $r['_key_compare'], str_replace(
$marker . $k, '', $r['key']
)
), $sql['where']
);
}
//AL DOILEA NIVEL
foreach ($rx as $k => $r) {
//TODO: testează cu mai multe cazuri deoarece pot exista bug-uri
if (!isset($r['key'])) {//FORȚEZ INTRAREA
foreach ($r as $k_i => $r_i) {
$sql['where'] = str_replace(
sprintf(
".meta_key = '%s' ", $r_i['key']
), sprintf(
".meta_key %s '%s' ", $r_i['_key_compare'], str_replace(
$marker . $k_i, '', $r_i['key']
)
), $sql['where']
);
}
}
}
var_dump($sql);
return $sql;
});
}); Doar în caz că cineva are nevoie de un răspuns similar,
MULȚUMESC DIN NOU