WP_Query con "post_title LIKE 'something%'"?

30 mag 2011, 15:11:57
Visualizzazioni: 188K
Voti: 56

Ho bisogno di fare una WP_Query con un LIKE sul post_title.

Ho iniziato con questa WP_Query standard:

$wp_query = new WP_Query( 
    array (
        'post_type'        => 'wp_exposants',
        'posts_per_page'   => '1',
        'post_status'      => 'publish',
        'orderby'          => 'title', 
        'order'            => 'ASC',
        'paged'            => $paged
    )
); 

Ma quello che voglio fare in realtà assomiglia a questo in SQL:

$query = "
        SELECT      *
        FROM        $wpdb->posts
        WHERE       $wpdb->posts.post_title LIKE '$param2%'
        AND         $wpdb->posts.post_type = 'wp_exposants'
        ORDER BY    $wpdb->posts.post_title
";
$wpdb->get_results($query);

L'output stampa i risultati che mi aspetto, ma io uso il regolare <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?> per visualizzare i risultati.
E questo non funziona con $wpdb->get_results().

Come posso ottenere ciò che ho descritto qui?

0
Tutte le risposte alla domanda 6
5
54

Risolverei questo problema con un filtro su WP_Query. Un filtro che rileva una variabile di query extra e la utilizza come prefisso del titolo.

add_filter( 'posts_where', 'wpse18703_posts_where', 10, 2 );
function wpse18703_posts_where( $where, &$wp_query )
{
    global $wpdb;
    if ( $wpse18703_title = $wp_query->get( 'wpse18703_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'' . esc_sql( $wpdb->esc_like( $wpse18703_title ) ) . '%\'';
    }
    return $where;
}

In questo modo puoi ancora chiamare WP_Query, devi solo passare il titolo come argomento wpse18703_title (o cambiare il nome in qualcosa di più breve).

30 mag 2011 17:06:03
Commenti

Questa sembra mancare del $wpdb->prepare().

kaiser kaiser
6 nov 2012 17:46:12

@kaiser: È passato molto tempo, ma penso che questo non fosse possibile con prepare(). $wpdb->prepare('LIKE "%s%%"', 'banana') restituirebbe "LIKE ''banana'%'", quindi dobbiamo costruire la query manualmente e fare anche l'escape.

Jan Fabry Jan Fabry
6 nov 2012 21:36:02

@JanFabry Felice di rivedertiiiiii! :) Passa in chat qualche volta, eh? StopPress sarebbe felice di vederti. Riguardo a quel prepare(). Sì, è complicato e ho dovuto provare diverse volte prima di capire come fare. Da qualcosa che ho appena creato: $wpdb->prepare( ' AND {$wpdb->posts}.post_title LIKE %s ', esc_sql( '%'.like_escape( trim( $term ) ).'%' ) ). E sono abbastanza sicuro che esc_sql() sia inutile e solo paranoico.

kaiser kaiser
7 nov 2012 12:35:13

Sembra che non si possa cercare una stringa con un ' (apostrofo) all'interno. Immagino sia a causa dell'escape? Non ho ancora trovato la soluzione

Vincent Decaux Vincent Decaux
30 ago 2018 18:10:29

Ho dovuto rimuovere & da &$wp_query altrimenti ricevevo un errore PHP expected to be a reference, value given

ecairol ecairol
28 mag 2021 23:23:27
8
24

Semplificato:

function title_filter( $where, &$wp_query )
{
    global $wpdb;
    // 2. estrai la query personalizzata qui:
    if ( $search_term = $wp_query->get( 'search_prod_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\'';
    }
    return $where;
}

$args = array(
    'post_type' => 'product',
    'posts_per_page' => $page_size,
    'paged' => $page,
    // 1. definisci una variabile di query personalizzata qui per passare il tuo termine:
    'search_prod_title' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'
);

add_filter( 'posts_where', 'title_filter', 10, 2 );
$wp_query = new WP_Query($args);
remove_filter( 'posts_where', 'title_filter', 10 );
return $wp_query;
19 apr 2013 16:24:00
Commenti

Per favore includi una spiegazione insieme al tuo codice.

s_ha_dum s_ha_dum
19 apr 2013 16:49:54

Ottima semplificazione

Timo Huovinen Timo Huovinen
10 nov 2014 21:52:08

Penso che il codice sia autoesplicativo, almeno per me. Grazie per aver condiviso lo script completo.

Hassan Dad Khan Hassan Dad Khan
8 ago 2017 09:55:26

Usa '$wpdb->esc_like(' invece di 'esc_sql( like_escape('

fdrv fdrv
19 feb 2018 19:16:23

@fdrv Hai ragione ma secondo la documentazione di wp, $wpdb->esc_like ha ancora bisogno di esc_sql(). Quindi penso che il codice corretto sarebbe esc_sql( $wpdb->esc_like( $search_term ) )

Syed Waqas Bukhary Syed Waqas Bukhary
18 ott 2019 21:31:40

like_escape deprecato dalla versione 4.0.0 Usa wpdb::esc_like

Empty Brain Empty Brain
14 mar 2020 08:46:32

remove_filter utilizza solo 3 argomenti, l'ultimo può essere rimosso.

Skatox Skatox
24 giu 2020 18:03:22

sono riuscito a far funzionare il codice sopra ma per qualche motivo quando eseguivo la mia ricerca restituiva dati da altri post_type anche se avevo specificato il tipo di post nell'array $args. Alla fine ho aggiunto la condizione alla query del titolo e ha funzionato $where .= ' OR ' . $wpdb->posts . '.post_title LIKE \'%' . $wpdb->esc_like( $search_term ) . '%\' AND '. $wpdb->posts . '.post_type = \'huguenot-family\'';

philip philip
2 feb 2021 14:10:44
Mostra i restanti 3 commenti
4
21

Volevo aggiornare questo codice su cui avete lavorato per WordPress 4.0 e versioni successive, poiché esc_sql() è deprecato dalla 4.0 in poi.

function title_filter($where, &$wp_query){
    global $wpdb;

    if($search_term = $wp_query->get( 'search_prod_title' )){
        /*utilizzo esc_like() qui invece di esc_sql()*/
        $search_term = $wpdb->esc_like($search_term);
        $search_term = ' \'%' . $search_term . '%\'';
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }

    return $where;
}

Il resto rimane invariato.

Vorrei anche far notare che puoi utilizzare la variabile s all'interno degli argomenti di WP_Query per passare i termini di ricerca, che credo includeranno anche il titolo del post nella ricerca.

In questo modo:

$args = array(
    'post_type' => 'post',
    's' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'        
);
$wp_query = new WP_Query($args);
2 gen 2015 07:36:51
Commenti

Cos'è esattamente search_prod_title? Dovrei cambiarlo con qualcos'altro?

Antonios Tsimourtos Antonios Tsimourtos
24 mar 2017 19:20:18

Da quando esc_sql è deprecato? Non lo è. $wpdb->escape invece sì... https://developer.wordpress.org/reference/functions/esc_sql/

Jeremy Jeremy
2 feb 2018 19:36:34

Nota che il parametro s cerca anche nel contenuto del post, il che potrebbe non essere l'obiettivo desiderato. =)

Christine Cooper Christine Cooper
19 apr 2018 13:43:29

like_escape deprecato dalla versione 4.0.0 Usare wpdb::esc_like

Empty Brain Empty Brain
14 mar 2020 08:40:20
3
18

Con alcune soluzioni vulnerabili pubblicate qui, propongo una versione leggermente semplificata e sanificata.

Per prima cosa, creiamo una funzione per il filtro posts_where che permette di mostrare solo i post che corrispondono a condizioni specifiche:

function cc_post_title_filter($where, &$wp_query) {
    global $wpdb;
    if ( $search_term = $wp_query->get( 'cc_search_post_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . $wpdb->esc_like( $search_term ) . '%\'';
    }
    return $where;
}

Ora aggiungiamo cc_search_post_title ai nostri argomenti della query:

$args = array(
    'cc_search_post_title' => $search_term, // cerca solo nel titolo del post
    'post_status' => 'publish',
);

E infine avvolgiamo il filtro attorno alla query:

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$query = new WP_Query($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

Utilizzo di get_posts()

Alcune funzioni che recuperano i post non eseguono i filtri, quindi le funzioni del filtro posts_where che aggiungi non modificheranno la query. Se intendi usare get_posts() per interrogare i tuoi post, devi impostare suppress_filters su false nell'array degli argomenti:

$args = array(
    'cc_search_post_title' => $search_term,
    'suppress_filters' => FALSE,
    'post_status' => 'publish',
);

Ora puoi usare get_posts():

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$posts = get_posts($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

E il parametro s?

Il parametro s è disponibile:

$args = array(
    's' => $search_term,
);

Sebbene aggiungere il tuo termine di ricerca nel parametro s funzioni e cerchi nel titolo del post, cercherà anche nel contenuto del post.

E il parametro title aggiunto con WP 4.4?

Passare un termine di ricerca nel parametro title:

$args = array(
    'title' => $search_term,
);

È sensibile alle maiuscole/minuscole e utilizza LIKE, non %LIKE%. Questo significa che una ricerca per hello non restituirà post con titolo Hello World o Hello.

19 apr 2018 15:58:35
Commenti

Eccellente. Stavo cercando 'post_title' come parametro e, ovviamente, non ho trovato nulla.

MastaBaba MastaBaba
13 set 2019 18:55:30

Sto riscontrando un errore con wp query o get posts: "E_WARNING Errore nel file »class-wp-hook.php« alla riga 288: il parametro 2 per cc_post_title_filter() dovrebbe essere un riferimento, invece è stato passato un valore

Elkrat Elkrat
3 mar 2020 19:28:10

@Elkrat Rimuovi il & da &$wp_query in cc_post_title_filter.

Mattimator Mattimator
6 mag 2020 00:04:16
2

Basandomi sulle risposte precedenti, per fornire flessibilità nel caso in cui si desideri cercare un post che contenga una parola in un campo meta OPPURE nel titolo del post, offro questa opzione tramite l'argomento "title_filter_relation". In questa implementazione, permetto solo input "OR" o "AND" con un valore predefinito di "AND".

function title_filter($where, &$wp_query){
    global $wpdb;
    if($search_term = $wp_query->get( 'title_filter' )){
        $search_term = $wpdb->esc_like($search_term); //invece di esc_sql()
        $search_term = ' \'%' . $search_term . '%\'';
        $title_filter_relation = (strtoupper($wp_query->get( 'title_filter_relation'))=='OR' ? 'OR' : 'AND');
        $where .= ' '.$title_filter_relation.' ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }
    return $where;
}

Ecco un esempio del codice in azione per un semplice post type "faq" dove la domanda è il titolo stesso del post:

add_filter('posts_where','title_filter',10,2);
$s1 = new WP_Query( array(
    'post_type' => 'faq',
    'posts_per_page' => -1,
    'title_filter' => $q,
    'title_filter_relation' => 'OR',
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key' => 'faq_answer',
            'value' => $q,
            'compare' => 'LIKE'
        )
    )
));
remove_filter('posts_where','title_filter',10,2);
29 apr 2015 01:44:12
Commenti

Ottima intuizione, aggiungere "query vars" personalizzate agli argomenti della query passati a WP_Query per poterli accedere all'interno del filtro posts_where.

Tom Auger Tom Auger
4 feb 2017 23:32:55

Sembra una buona risposta, l'unico problema è che non funziona per me :-(

luke_mclachlan luke_mclachlan
28 mar 2022 14:04:48
0

L'approccio ottimale per eseguire una query WP_Query con una ricerca 'LIKE' su post_title consiste nell'includere l'argomento 'search_columns'. Se stai costruendo manualmente la WP_Query, dovresti specificarlo nel seguente modo:

'search_columns' => ['post_title']

Puoi trovare maggiori dettagli nel codice sorgente di WordPress su Trac: https://core.trac.wordpress.org/browser/tags/6.3/src/wp-includes/class-wp-query.php#L1426

Tuttavia, se l'intenzione è modificare query generate da plugin di terze parti o temi, puoi ottenere questo risultato sfruttando l'hook filter 'post_search_columns'.

La documentazione ufficiale fornisce informazioni dettagliate su come utilizzare questo hook: https://developer.wordpress.org/reference/hooks/post_search_columns/

28 set 2023 13:34:38