WP Query Args - Titolo o Valore Meta

18 feb 2015, 02:59:25
Visualizzazioni: 22.2K
Voti: 12

Come posso eseguire una query per meta_value o titolo?

Se imposto i meta_values,

$args['meta_query'] = array(
   'relation' => 'OR',
    array(
        'key' => 'model_name',
        'value' => $thesearch,
        'compare' => 'like'
    )
);

vengono automaticamente aggiunti come AND.

Questa ricerca sarebbe:

 WHERE title = 'Search' AND (model_name = 'Search' OR ...)

Ho bisogno di

WHERE title = 'Search' OR (model_name = 'Search' OR ...)
1
Commenti

Ho provato ad aggiungere $args['relation'] = 'OR'; ma non viene riconosciuto. Sembra che mi manchi il modo per controllare la logica condizionale tramite args.

Bryan Bryan
18 feb 2015 03:04:49
Tutte le risposte alla domanda 3
16
28

Nota che la parte relation nell'argomento meta_query viene utilizzata solo per definire la relazione tra le query sub meta.

Puoi provare questa configurazione:

$args = [ 
    '_meta_or_title' => $thesearch,   // Il nostro nuovo argomento personalizzato!
    'meta_query'    => [
        [
            'key'     => 'model_name',
            'value'   => $thesearch,
            'compare' => 'like'
        ]
    ],
];

dove abbiamo introdotto un argomento personalizzato _meta_or_title per attivare la query meta OR title.

Questo è supportato dal seguente plugin:

<?php
/**
 *  Plugin Name:   Meta OR Title query in WP_Query
 *  Description:   Attivato tramite l'argomento '_meta_or_title' di WP_Query 
 *  Plugin URI:    http://wordpress.stackexchange.com/a/178492/26350
 *  Plugin Author: Birgir Erlendsson (birgire)
 *  Version:       0.0.1
 */

add_action( 'pre_get_posts', function( $q )
{
    if( $title = $q->get( '_meta_or_title' ) )
    {
        add_filter( 'get_meta_sql', function( $sql ) use ( $title )
        {
            global $wpdb;

            // Esegui solo una volta:
            static $nr = 0; 
            if( 0 != $nr++ ) return $sql;

            // Modifica la parte WHERE:
            $sql['where'] = sprintf(
                " AND ( %s OR %s ) ",
                $wpdb->prepare( "{$wpdb->posts}.post_title = '%s'", $title ),
                mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
            );
            return $sql;
        });
    }
});
18 feb 2015 07:12:24
Commenti

Wow. Risposta fantastica! Dovrebbe essere inclusa nel core.

Bryan Bryan
18 feb 2015 22:06:29

La risposta mi ha portato a metà strada. http://wordpress.stackexchange.com/questions/178574/acf-relationship-field-search-filtering Hai qualche idea per il prossimo passaggio?

Bryan Bryan
18 feb 2015 22:16:36

Ho utilizzato questa risposta per creare una query per un valore meta specifico nella pagina edit.php di un custom post type. Non eseguo alcuna query sul titolo, perché il mio custom post type non ha un titolo. Quindi, ho sostituito " AND ( %s OR %s ) " con " OR ( %s ) " nella query SQL e ho completamente rimosso la riga $wpdb->prepare( "{$wpdb->posts}.post_title = '%s'", $title ),. È un approccio valido?

BdN3504 BdN3504
17 mag 2015 13:30:57

@BdN3504 Sono contento che tu l'abbia trovato un po' utile. Se ho capito bene, le tue modifiche dovrebbero funzionare.

birgire birgire
17 mag 2015 16:20:48

grazie per la risposta. le mie modifiche funzionano, ma non sono sicuro che sia l'approccio giusto. in realtà vorrei eliminare i parametri title e content dalla query e cercare solo i meta. anche se l'approccio attuale funziona, non è il più pratico

BdN3504 BdN3504
17 mag 2015 22:32:03

@BdN3504 ok perfetto, non sono a conoscenza di un modo nativo (senza usare filtri) per cambiare AND -> OR per l'intera meta query, ma puoi ovviamente modificare le relazioni della meta query in molti modi all'interno di meta_query di WP_Query.

birgire birgire
17 mag 2015 22:40:43

Ottimo trucco. Se vuoi una ricerca di sottostringa per il titolo, sostituisci post_title = '%s' con post_title like '%%%s%%'.

jarnoan jarnoan
30 set 2015 13:11:47

Come posso eseguire una query con titolo e valore di tassonomia invece del valore meta?

Jeff Jeff
13 ott 2018 18:11:23

@jeff Una volta ho scritto un plugin per combinare query: https://github.com/birgire/wp-combine-queries. Anche qui ho sperimentato con la ricerca (titolo, excerpt, contenuto) o tax query. Qui ho trovato un'altra risposta simile con cui ho sperimentato. Possiamo anche scrivere due WP_Query separati, poi raccogliere e combinare gli ID dei post risultanti in una terza WP_Query (se necessario e se l'ordinamento PHP non è sufficiente) tramite il parametro di input post__in.

birgire birgire
13 ott 2018 20:39:24

@birgire Ho optato per la strada delle due query separate e ha funzionato, grazie.

Jeff Jeff
13 ott 2018 22:39:17

@Jeff felice di sentire che abbia funzionato per te.

birgire birgire
13 ott 2018 22:42:18

@biergie Grazie per questa fantastica soluzione! Funziona alla grande, ma la mia ricerca non restituisce risultati quando uso _meta_or_title + meta query + tax query. Quando uso il tuo filtro personalizzato e aggiungo una tax_query, l'elemento $sql['where'] risulta vuoto. Hai qualche idea su come risolvere?

chris.ribal chris.ribal
6 giu 2019 15:50:42

@biergie Grazie. Non l'ho testato da un po', ma potresti assicurarti che non ci siano altri plugin/codici che lo influenzano e ad esempio eseguirlo con il debug attivo.

birgire birgire
7 giu 2019 13:05:50

@birgire - mi chiedevo se tu o qualcun altro poteste indicare dove usi gli $args? grazie.

v3nt v3nt
29 giu 2020 19:48:55

Il $q->get( '_meta_or_title' ) è lo stesso di $args['_meta_or_title'].

birgire birgire
30 giu 2020 15:01:01

Soluzione spettacolare! Suggerirei di modificare per includere il commento di jarnoan sull'uso di LIKE invece di = poiché è un consiglio molto utile ma facilmente trascurato

Kai Qing Kai Qing
22 ott 2020 05:53:00
Mostra i restanti 11 commenti
1

Non ho trovato una soluzione per cercare più parole chiave che possono essere mescolate nel titolo del post, nella descrizione E/O in una o più meta, quindi ho creato la mia aggiunta alla funzione di ricerca.

Tutto ciò che devi fare è aggiungere il seguente codice in function.php, e ogni volta che usi l'argomento 's' in WP_Query() e vuoi che cerchi anche in una o più meta, aggiungi semplicemente un argomento 's_meta_keys' che è un array delle chiavi meta in cui vuoi cercare:

/************************************************************************\
|**                                                                    **|
|**  Permette alla funzione di ricerca di WP_Query() di cercare        **|
|**  più parole chiave nelle meta oltre che in post_title e post_content **|
|**                                                                    **|
|**  Di rAthus @ Arkanite                                              **|
|**  Creato: 2020-08-18                                                **|
|**  Aggiornato: 2020-08-19                                            **|
|**                                                                    **|
|**  Usa il solito argomento 's' e aggiungi un argomento 's_meta_keys' **|
|**  contenente un array delle chiavi meta in cui vuoi cercare :)      **|
|**                                                                    **|
|**  Esempio :                                                         **|
|**                                                                    **|
|**  $args = array(                                                    **|
|**      'numberposts'  => -1,                                         **|
|**      'post_type' => 'post',                                        **|
|**      's' => $MY_SEARCH_STRING,                                     **|
|**      's_meta_keys' => array('META_KEY_1','META_KEY_2');            **|
|**      'orderby' => 'date',                                          **|
|**      'order'   => 'DESC',                                          **|
|**  );                                                                **|
|**  $posts = new WP_Query($args);                                     **|
|**                                                                    **|
\************************************************************************/
add_action('pre_get_posts', 'my_search_query'); // aggiunge la funzione di ricerca speciale ad ogni query get_posts (include WP_Query())
function my_search_query($query) {
    if ($query->is_search() and $query->query_vars and $query->query_vars['s'] and $query->query_vars['s_meta_keys']) { // se stiamo cercando usando l'argomento 's' e abbiamo aggiunto un argomento 's_meta_keys'
        global $wpdb;
        $search = $query->query_vars['s']; // ottieni la stringa di ricerca
        $ids = array(); // inizializza l'array degli id dei post corrispondenti per ogni parola chiave cercata
        foreach (explode(' ',$search) as $term) { // dividi le parole chiave e cerca risultati corrispondenti per ciascuna
            $term = trim($term); // rimuovi spazi non necessari
            if (!empty($term)) { // controlla che la parola chiave non sia vuota
                $query_posts = $wpdb->prepare("SELECT * FROM {$wpdb->posts} WHERE post_status='publish' AND ((post_title LIKE '%%%s%%') OR (post_content LIKE '%%%s%%'))", $term, $term); // cerca nel titolo e nel contenuto come fa normalmente la funzione
                $ids_posts = [];
                $results = $wpdb->get_results($query_posts);
                if ($wpdb->last_error)
                    die($wpdb->last_error);
                foreach ($results as $result)
                    $ids_posts[] = $result->ID; // raccogli gli id dei post corrispondenti
                $query_meta = [];
                foreach($query->query_vars['s_meta_keys'] as $meta_key) // ora costruisci una query di ricerca per cercare in ogni chiave meta desiderata
                    $query_meta[] = $wpdb->prepare("meta_key='%s' AND meta_value LIKE '%%%s%%'", $meta_key, $term);
                $query_metas = $wpdb->prepare("SELECT * FROM {$wpdb->postmeta} WHERE ((".implode(') OR (',$query_meta)."))");
                $ids_metas = [];
                $results = $wpdb->get_results($query_metas);
                if ($wpdb->last_error)
                    die($wpdb->last_error);
                foreach ($results as $result)
                    $ids_metas[] = $result->post_id; // raccogli gli id dei post corrispondenti
                $merged = array_merge($ids_posts,$ids_metas); // unisci gli id di titolo, contenuto e meta risultanti da entrambe le query
                $unique = array_unique($merged); // rimuovi i duplicati
                if (!$unique)
                    $unique = array(0); // se nessun risultato, aggiungi un id "0" altrimenti verranno restituiti tutti i post
                $ids[] = $unique; // aggiungi l'array degli id corrispondenti nell'array principale
            }
        }
        if (count($ids)>1)
            $intersected = call_user_func_array('array_intersect',$ids); // se ci sono più parole chiave mantieni solo gli id presenti in tutti gli array corrispondenti
        else
            $intersected = $ids[0]; // altrimenti mantieni il singolo array di id corrispondenti
        $unique = array_unique($intersected); // rimuovi i duplicati
        if (!$unique)
            $unique = array(0); // se nessun risultato, aggiungi un id "0" altrimenti verranno restituiti tutti i post
        unset($query->query_vars['s']); // rimuovi la normale query di ricerca
        $query->set('post__in',$unique); // aggiungi invece un filtro per id del post
    }
}

Esempio di utilizzo:

$search= "parole chiave da cercare";

$args = array(
    'numberposts'   => -1,
    'post_type' => 'post',
    's' => $search,
    's_meta_keys' => array('short_desc','tags');
    'orderby' => 'date',
    'order'   => 'DESC',
);

$posts = new WP_Query($args);

Questo esempio cercherà le parole chiave "parole chiave da cercare" nei titoli dei post, nelle descrizioni e nelle chiavi meta 'short_desc' e 'tags'.

Le parole chiave possono essere trovate in uno o più campi, in qualsiasi ordine, restituirà qualsiasi post che abbia tutte le parole chiave in uno qualsiasi dei campi designati.

Ovviamente puoi forzare la ricerca in una lista di chiavi meta che includi nella funzione ed eliminare gli argomenti extra se vuoi che TUTTE le query di ricerca includano queste chiavi meta :)

Spero che questo aiuti chiunque si trovi ad affrontare lo stesso problema che ho avuto io!

18 ago 2020 21:01:43
Commenti

Sembra piuttosto solido. Puoi aiutarmi a includere campi personalizzati dall'autore [utente] di un post?

Adeerlike Adeerlike
30 mar 2022 15:39:08
1

Sono abbastanza nuovo in WP, non ho testato molto questo approccio che ho ideato. Forse potete aiutarmi a verificare se è corretto. La soluzione che ho trovato finora è implementare la stessa logica di meta_query, facendo solo alcune sostituzioni.

Prima di tutto, l'utilizzo:

$args = array(
    'lang' => 'pt', //questa funzione non entra in conflitto (esempio: polylang)
    'post_type' => 'produtos', 
    'post_status'   => 'publish',
    'posts_per_page' => 10,
    'paged' =>  1,
    'fields' => 'ids',
);
$args['meta_query] = [
    ['relation'] => 'OR'; //qualsiasi relazione desideri
    [
        'key' => 'acf_field', //qualsiasi campo personalizzato (uso normale)
        'value' => $search, //qualsiasi valore (uso normale)
        'compare' => 'LIKE', //qualsiasi comparazione (uso normale)
    ],
    [
        'key' => 'post_title', //imposta il contenuto predefinito di WordPress che desideri ('post_content', 'post_title' e 'post_excerpt')
        'value' => $search, //qualsiasi valore
        'compare' => 'LIKE', //testato con 'LIKE' e '=', funziona bene e non vedo altre necessità.
    ],
    [
        'key' => 'post_exerpt', // puoi aggiungere quante volte vuoi
        'value' => $search_2,
        'compare' => 'LIKE', 
    ],
];
$the_query = new WP_Query( $args ); //solo la query
wp_reset_postdata(); //pulisci la tua query

Per farlo funzionare, aggiungi questa funzione al tuo functions.php del tema

function post_content_to_meta_queries($where, $wp_query){
    global $wpdb;

    //se non c'è metaquery, ciao!
    $meta_queries = $wp_query->get( 'meta_query' );
    if( !$meta_queries || $meta_queries == '' ) return $where;

    //se c'è solo una relazione
    $where = str_replace($wpdb->postmeta . ".meta_key = 'post_title' AND " . $wpdb->postmeta . ".meta_value", $wpdb->posts . ".post_title", $where);
    $where = str_replace($wpdb->postmeta . ".meta_key = 'post_content' AND " . $wpdb->postmeta . ".meta_value", $wpdb->posts . ".post_content", $where);
    $where = str_replace($wpdb->postmeta . ".meta_key = 'post_excerpt' AND " . $wpdb->postmeta . ".meta_value", $wpdb->posts . ".post_excerpt", $where);

    ////per relazioni annidate

    //conta il numero di meta query per possibili sostituzioni
    $number_of_relations = count($meta_queries);

    //sostituisce 'WHERE' usando la logica di denominazione multidimensionale postmeta usata dal core di WordPress
    $i = 1;
    while($i<=$number_of_relations && $number_of_relations > 0){
        $where = str_replace("mt".$i.".meta_key = 'post_title' AND mt".$i.".meta_value", $wpdb->posts . ".post_title", $where);
        $where = str_replace("mt".$i.".meta_key = 'post_content' AND mt".$i.".meta_value", $wpdb->posts . ".post_content", $where);
        $where = str_replace("mt".$i.".meta_key = 'post_excerpt' AND mt".$i.".meta_value", $wpdb->posts . ".post_excerpt", $where);
        $i++;
    }

    return $where;
}

add_filter('posts_where','post_content_to_meta_queries',10,2);

Sono abbastanza sicuro che possa essere migliorato! Spero sia utile!

30 lug 2021 22:43:56
Commenti

Aggiornamento: Ho utilizzato questa soluzione nell'ultimo anno e mezzo. Un salvavita per ricerche complesse insieme ad ACF.

Jeff Oliva Jeff Oliva
19 dic 2022 15:04:36