Utiliser REGEXP dans la clé meta_query WP_Query

10

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

Existe-t-il un moyen d'y parvenir avec un filtre peut-être? Ou dois-je tout construire moi-même avec une propre requête SQL?

Philipp Kühn
la source

Réponses:

9

Voici une idée expérimentale:

Supposons que nous ayons:

poster A avec le champ personnalisé location1comme au Royaume - Uni - Londres

poste B avec le champ personnalisé location2comme France - Paris

poster C avec le champ personnalisé location3comme 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 prenons en charge l' _key_compareargument 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îne.

Notez que cela ne prend pas en charge l' échappement de caractères regex , comme \(et \\.

Birgire
la source
J'apprécie ces paramètres personnalisés supplémentaires amusants que vous ajoutez. ;-)
Pieter Goosen
1
Peut-être comme les petits assistants du Père Noël - ils finissent généralement par fonctionner comme par magie ;-) @PieterGoosen
birgire
1
merci, j'ai corrigé cela. Je viens de l'utiliser $count++dans une construction de chaîne quand j'ai oublié que je devais utiliser $countdeux fois ;-) Je ne recommanderais pas d'utiliser des caractères spéciaux dans les noms de clés, autres que le trait de soulignement . Vous utilisez des parenthèses dans votre clé. Ils ont une signification particulière avec les expressions régulières. Vous devrez donc les échapper avec \(et \)dans REGEXPou RLIKE, mais l'échappement n'est pas pris en charge dans mon plugin. Vous pouvez essayer à la LIKEplace avec custom_field_language(%)language. @ PhilippKühn
birgire
1
génie! fonctionne comme un charme!
Philipp Kühn
1
aha, bon point, peut-être que je vais juste mettre cela sur GitHub dans les semaines à venir et essayer de l'étendre là-bas ;-) @ PhilippKühn
birgire
1

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

Maintenant,

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 si vous avez besoin d'une réponse similaire,

THK AGAIN

Rogelio Vargas
la source
Merci pour le partage, mais ce serait apprécié si les commentaires du code en étaient en anglais, merci.
birgire