Usare REGEXP nella chiave meta_query di WP_Query
So che posso usare REGEXP in WP_Query in questo modo:
$query = new WP_Query(array(
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'custom_fields',
'value' => 'foo[(][0-9][)]', // con roba regex
'compare' => 'REGEXP',
),
),
));
Ma ho bisogno di usare espressioni regolari anche nella chiave. In questo modo:
$query = new WP_Query(array(
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'custom_fields[(][0-9][)]', // con roba regex
'value' => 'foo',
'compare' => 'REGEXP',
),
),
));
C'è un modo per ottenere questo risultato magari con un filtro? O devo costruire tutto da solo con una query SQL personalizzata?
Ecco un'idea sperimentale:
Supponiamo di avere:
articolo A con il campo personalizzato
location1impostato su UK - Londraarticolo B con il campo personalizzato
location2impostato su Francia - Parigiarticolo C con il campo personalizzato
location3impostato su USA - New York
Potremmo quindi utilizzare, ad esempio:
$args = [
'meta_query' => [
'relation' => 'OR',
[
'key' => "^location[0-9]",
'_key_compare' => 'REGEXP',
'value' => 'Londra',
'compare' => 'LIKE',
],
[
'key' => 'location%',
'_key_compare' => 'LIKE',
'value' => 'Parigi',
'compare' => 'LIKE'
],
[
'key' => 'location3',
'value' => 'New York',
'compare' => 'LIKE'
]
]
];
dove supportiamo l'argomento personalizzato _key_compare con il seguente plugin:
<?php
/**
* Plugin Name: Ricerca Estesa delle Meta Key in WP_Query
* Description: Argomento personalizzato '_key_compare' con REGEXP, RLIKE o 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 )
{
// Controlla la meta query:
$mq = $q->get( 'meta_query' );
if( empty( $mq ) )
return;
// Inizializzazione:
$marker = '___tmp_marker___';
$rx = [];
// Raccogli tutte le sotto meta query che utilizzano REGEXP, RLIKE o LIKE:
foreach( $mq as $k => $m )
{
if( isset( $m['_key_compare'] )
&& in_array( strtoupper( $m['_key_compare'] ), [ 'REGEXP', 'RLIKE', 'LIKE' ] )
&& isset( $m['key'] )
) {
// Marca la key con una stringa unica per garantire le sostituzioni successive:
$m['key'] .= $marker . $k; // Rende il marker temporaneo univoco
// Modifica la corrispondente variabile di query originale:
$q->query_vars['meta_query'][$k]['key'] = $m['key'];
// Raccolgila:
$rx[$k] = $m;
}
}
// Nulla da fare:
if( empty( $rx ) )
return;
// Ottieni l'accesso all'SQL generato dalla meta query:
add_filter( 'get_meta_sql', function( $sql ) use ( $rx, $marker )
{
// Esegui solo una volta:
static $nr = 0;
if( 0 != $nr++ )
return $sql;
// Modifica la parte WHERE dove sostituiamo i marker temporanei:
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;
});
});
dove aggiungiamo marker univoci su ogni meta key per le sostituzioni di stringhe.
Nota che questo non supporta l'escaping dei caratteri regex, come \( e \\.
Mi piacciono questi divertenti parametri personalizzati aggiuntivi che stai aggiungendo. ;-)
Pieter Goosen
Forse come i piccoli aiutanti di Babbo Natale - di solito alla fine fanno funzionare tutto magicamente ;-) @PieterGoosen
birgire
wow amico... questo è incredibile. ma sfortunatamente non funziona :( Ho nomi di chiave come custom_field_language(0)language nel mio database e la mia chiave regex custom_field_languages[(][0-9][)]language non funziona con il tuo plugin. qualche idea?
Philipp Kühn
sembra che la funzione replace alla fine del tuo plugin non funzioni correttamente.
Philipp Kühn
grazie, ho risolto. Ho usato $count++ nella costruzione di una stringa quando mi sono dimenticato che dovevo usare $count due volte ;-) Non consiglierei di usare caratteri speciali nei nomi delle chiavi, a parte l'underscore. Stai usando parentesi nella tua chiave. Hanno un significato speciale con le espressioni regolari. Quindi dovresti fare l'escape con \( e \) in REGEXP o RLIKE, ma l'escape non è supportato nel mio plugin. Potresti provare con LIKE invece con custom_field_language(%)language. @PhilippKühn
birgire
si. grazie mille. il tuo codice modificato funziona!!! ma c'è un altro problema. se uso un altro meta_query ottengo sempre zero risultati con qualsiasi relazione. come questo 'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'custom_field_location',
'value' => 'Berlino',
'compare' => '=',
),
array(
'key' => 'custom_field_languages[(][0-9][)]language',
'_key_compare' => 'REGEXP',
'value' => 'ak',
'compare' => 'LIKE',
),
)
Philipp Kühn
se stampo $sql['where'] posso vedere che ogni chiave viene sostituita con quella REGEXP. @birgire
Philipp Kühn
Questo era un altro problema con $count ;-) Per favore controlla la risposta aggiornata, dove uso una chiave di array invece. @PhilippKühn
birgire
oh no... ho scoperto che questo non supporta le nuove query meta annidate introdotte in wp 4.1 :( una storia senza fine... @birgire
Philipp Kühn
aha, buon punto, forse lo metterò su GitHub nelle prossime settimane e cercherò di estenderlo lì ;-) @PhilippKühn
birgire
Sarebbe fantastico! Fino ad allora ho trovato una soluzione alternativa un po' rozza. Ma sarei felice di usare il tuo script perché è un modo molto più pulito. @birgire
Philipp Kühn
La tua risposta funziona perfettamente per il primo livello dell'array, ad esempio:
$args['meta_query'][] = array(
'key' => 'tour_itinerario_ciudades_repeater_%_tour_ciudades_nombre',
'_key_compare' => 'LIKE',
'value' => 'MEXICO',
'compare' => 'LIKE',
);
Ho bisogno di fare alcune modifiche per farlo funzionare al secondo livello dell'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',
)
);
Ora,
add_action('pre_get_posts', function( $q ) {
// Controlla la meta query:
$mq = $q->get('meta_query');
if (empty($mq))
return;
// Inizializza:
$marker = '___tmp_marker___';
$rx = [];
// Raccoglie tutte le sotto meta query che usano REGEXP, RLIKE o LIKE:
// Funziona solo per il primo livello dell'array
foreach ($mq as $k => $m) {
if (isset($m['_key_compare']) && in_array(strtoupper($m['_key_compare']), [ 'REGEXP', 'RLIKE', 'LIKE']) && isset($m['key'])
) {
// Marca la chiave con una stringa unica per garantire le sostituzioni successive:
$m['key'] .= $marker . $k; // Rende il marker temporaneo univoco
// Modifica la corrispondente variabile di query originale:
$q->query_vars['meta_query'][$k]['key'] = $m['key'];
// La raccoglie:
$rx[$k] = $m;
}
}
// Codice personalizzato per farlo funzionare con argomenti su array multidimensionali
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'])
) {
// Marca la chiave con una stringa unica:
$m_i['key'] .= $marker . $k_i; // Rende il marker temporaneo univoco
// Modifica la variabile di query originale:
$q->query_vars['meta_query'][$k][$k_i]['key'] = $m_i['key'];
// La raccoglie:
$rx[$k][$k_i] = $m_i;
}
}
}
}
// Niente da fare:
if (empty($rx))
return;
// Ottieni accesso all'SQL generato della meta query:
add_filter('get_meta_sql', function( $sql ) use ( $rx, $marker ) {
// Esegui solo una volta:
static $nr = 0;
if (0 != $nr++)
return $sql;
// Modifica la parte WHERE dove sostituiamo i marker temporanei:
//PRIMO LIVELLO
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']
);
}
//SECONDO LIVELLO
foreach ($rx as $k => $r) {
//TODO: testare con diversi casi poiché potrebbe avere bug
if (!isset($r['key'])) {//FORZO L'INGRESSO
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;
});
}); Solo nel caso qualcuno abbia bisogno di una risposta simile,
GRAZIE ANCORA