web-dev-qa-db-fra.com

Utiliser REGEXP dans la clé meta_query de WP_Query

Je sais que je peux utiliser REGEXP dans WP_Query comme ceci:

$query = new WP_Query(array(
  'posts_per_page'    => -1,
  'post_status'       => 'publish',
  'meta_query'        => array(
    array(
      'key'     => 'custom_fields',
      'value'   => 'foo[(][0-9][)]', // with regex stuff
      'compare' => 'REGEXP',
    ),
  ),
));

Mais j'ai aussi besoin d'expressions régulières dans la clé. Comme ça:

$query = new WP_Query(array(
  'posts_per_page'    => -1,
  'post_status'       => 'publish',
  'meta_query'        => array(
    array(
      'key'     => 'custom_fields[(][0-9][)]', // with regex stuff
      'value'   => 'foo',
      'compare' => 'REGEXP',
    ),
  ),
));

Peut-on y arriver avec un filtre peut-être? Ou dois-je tout construire moi-même avec une requête SQL propre?

10
Philipp Kühn

Voici une idée expérimentale:

Supposons que nous ayons:

posteAavec le champ personnalisé location1 sous la forme UK - London

posterBavec le champ personnalisé location2 comme France - Paris

posteCavec le champ personnalisé location3 sous la forme USA - New York

Ensuite, nous pourrions utiliser, par exemple:

$args = [
    'meta_query' => [
        'relation' => 'OR',
        [
            'key'          => "^location[0-9]",
            '_key_compare' => 'REGEXP',
            'value'        => 'London',
            'compare'      => 'LIKE',
        ],
        [
            'key'          => 'location%',
            '_key_compare' => 'LIKE',
            'value'        => 'Paris',
            'compare'      => 'LIKE'
        ],
        [
            'key'          => 'location3',
            'value'        => 'New York',
            'compare'      => 'LIKE'
        ]
    ]
];

où nous supportons l’argument _key_compare personnalisé avec le plugin suivant:

<?php
/**
 *  Plugin Name:   Extended Meta Key Search In WP_Query
 *  Description:   Custom '_key_compare' argument as REGEXP, RLIKE or 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 )
{
    // Check the meta query:
    $mq = $q->get( 'meta_query' );

    if( empty( $mq ) )
        return;

    // Init:
    $marker = '___tmp_marker___'; 
    $rx     = [];

    // Collect all the sub meta queries, that use REGEXP, RLIKE or LIKE:
    foreach( $mq as $k => $m )                                    
    {
        if(    isset( $m['_key_compare'] )
            && in_array( strtoupper( $m['_key_compare'] ), [ 'REGEXP', 'RLIKE', 'LIKE' ] )
            && isset( $m['key'] )
        ) {
            // Mark the key with a unique string to secure the later replacements:
            $m['key'] .= $marker . $k; // Make the appended tmp marker unique

            // Modify the corresponding original query variable:
            $q->query_vars['meta_query'][$k]['key'] = $m['key'];

            // Collect it:
            $rx[$k] = $m;
        }
    }

    // Nothing to do:
    if( empty( $rx ) )
        return;

    // Get access the generated SQL of the meta query:
    add_filter( 'get_meta_sql', function( $sql ) use ( $rx, $marker )
    {
        // Only run once:
        static $nr = 0;         
        if( 0 != $nr++ )
            return $sql;

        // Modify WHERE part where we replace the temporary markers:
        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;
    });

});

où nous ajoutons des marqueurs uniques sur chaque clé méta pour les remplacements de chaînes.

Notez que cela ne prend pas en charge le caractère regex escaping , comme \( et \\.

8
birgire

Votre réponse est parfaite en travaillant dans le premier tableau lvl, par exemple:

$args['meta_query'][] = array(

  'key' => 'tour_itinerario_ciudades_repeater_%_tour_ciudades_nombre',
  '_key_compare' => 'LIKE',
  'value' => 'MEXICO',
  'compare' => 'LIKE',
  );

J'ai besoin de faire quelques modifications pour travailler dans le deuxième niveau du tableau:

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

À présent,

add_action('pre_get_posts', function( $q ) {
// Check the meta query:
$mq = $q->get('meta_query');

if (empty($mq))
    return;

// Init:
$marker = '___tmp_marker___';
$rx = [];

// Collect all the sub meta queries, that use REGEXP, RLIKE or LIKE:
// Only works for 1st level in array
foreach ($mq as $k => $m) {
    if (isset($m['_key_compare']) && in_array(strtoupper($m['_key_compare']), [ 'REGEXP', 'RLIKE', 'LIKE']) && isset($m['key'])
    ) {
        // Mark the key with a unique string to secure the later replacements:
        $m['key'] .= $marker . $k; // Make the appended tmp marker unique
        // Modify the corresponding original query variable:
        $q->query_vars['meta_query'][$k]['key'] = $m['key'];

        // Collect it:
        $rx[$k] = $m;
    }
}

// custom code to make it work with arguments on Multidimensional array 
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'])
            ) {
                // Mark the key with a unique string to secure the later replacements:
                $m_i['key'] .= $marker . $k_i; // Make the appended tmp marker unique
                // Modify the corresponding original query variable:
                $q->query_vars['meta_query'][$k][$k_i]['key'] = $m_i['key'];

                // Collect it:
                $rx[$k][$k_i] = $m_i;
            }
        }
    }
}


// Nothing to do:
if (empty($rx))
    return;

// Get access the generated SQL of the meta query:
add_filter('get_meta_sql', function( $sql ) use ( $rx, $marker ) {
    // Only run once:
    static $nr = 0;
    if (0 != $nr++)
        return $sql;

    // Modify WHERE part where we replace the temporary markers:
    //PRIMER 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']
        );
    }
    //SECOND NIVEL
    foreach ($rx as $k => $r) {
        //TODO: test with several cases since may have bugs
        if (!isset($r['key'])) {//FORZO LA ENTRADA 
            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;
});

}); Juste pour si besoin besoin réponse similaire,

Encore une fois

1
Rogelio Vargas