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
location1
ca UK - Londraarticolul B cu câmpul personalizat
location2
ca Franța - Parisarticolul C cu câmpul personalizat
location3
ca 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. ;-)

Poate ca niște ajutoarele lui Moș Crăciun - de obicei fac totul să funcționeze magic în final ;-) @PieterGoosen

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?

se pare că funcția de înlocuire de la finalul plugin-ului tău nu funcționează corect.

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

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',
),
)

dacă afișez $sql['where']
pot vedea că fiecare cheie este înlocuită cu cea REGEXP. @birgire

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

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

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

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

@birgire te-ai gândit vreodată să postezi asta pe GitHub, prietene?

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
