WP_Query cu "post_title LIKE 'something%'"?

30 mai 2011, 15:11:57
Vizualizări: 188K
Voturi: 56

Am nevoie să execut un WP_Query cu LIKE pe post_title.

Am început cu acest WP_Query obișnuit:

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

Dar ceea ce vreau să fac arată așa în 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);

Rezultatul afișează ceea ce mă aștept, dar folosesc obișnuitul <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?> pentru a afișa rezultatele.
Iar asta nu funcționează cu $wpdb->get_results().

Cum pot realiza ceea ce am descris aici?

0
Toate răspunsurile la întrebare 6
5
54

Aș rezolva acest lucru cu un filtru pe WP_Query. Unul care detectează o variabilă suplimentară de interogare și o folosește ca prefix pentru titlu.

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;
}

În acest fel poți continua să apelezi WP_Query, doar treci titlul ca argument wpse18703_title (sau schimbă numele în ceva mai scurt).

30 mai 2011 17:06:03
Comentarii

Aceasta pare să lipsească $wpdb->prepare().

kaiser kaiser
6 nov. 2012 17:46:12

@kaiser: A trecut mult timp, dar cred că acest lucru nu era posibil cu prepare(). $wpdb->prepare('LIKE "%s%%"', 'banana') ar returna "LIKE ''banana'%'", așa că trebuie să construim query-ul manual și să facem escaping-ul și noi.

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

@JanFabry Mă bucur să te văd din nooooooou! :) Treceți pe chat cândva, da? StopPress ar fi fericit să te vadă. Legat de acel prepare(). Da, e complicat și a trebuit să încerc de mai multe ori înainte să reușesc. Din ceva ce am făcut recent: $wpdb->prepare( ' AND {$wpdb->posts}.post_title LIKE %s ', esc_sql( '%'.like_escape( trim( $term ) ).'%' ) ). Și sunt sigur că esc_sql() este inutil și doar paranoic.

kaiser kaiser
7 nov. 2012 12:35:13

Se pare că nu poți căuta un șir care conține ' (apostrof). Presupun că e din cauza escapării? Încă nu am găsit soluția.

Vincent Decaux Vincent Decaux
30 aug. 2018 18:10:29

A trebuit să elimin & din &$wp_query altfel primeam o eroare PHP expected to be a reference, value given

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

Simplificat:

function title_filter( $where, &$wp_query )
{
    global $wpdb;
    // 2. preiați interogarea personalizată aici:
    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. definiți o variabilă de interogare personalizată aici pentru a transmite termenul:
    '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
Comentarii

Te rog să incluzi o explicație împreună cu codul tău.

s_ha_dum s_ha_dum
19 apr. 2013 16:49:54

Excelentă simplificare

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

Cred că codul se explică de la sine, cel puțin pentru mine. Mulțumesc pentru partajarea scriptului complet.

Hassan Dad Khan Hassan Dad Khan
8 aug. 2017 09:55:26

Folosește '$wpdb->esc_like (' în loc de 'esc_sql( like_escape('

fdrv fdrv
19 feb. 2018 19:16:23

@fdrv Ai dreptate, dar conform documentației WordPress, $wpdb->esc_like are în continuare nevoie de esc_sql(). Deci cred că codul corect ar fi esc_sql( $wpdb->esc_like( $search_term ) )

Syed Waqas Bukhary Syed Waqas Bukhary
18 oct. 2019 21:31:40

like_escape învechit începând cu versiunea 4.0.0 Folosește wpdb::esc_like

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

remove_filter folosește doar 3 argumente, ultimul poate fi eliminat.

Skatox Skatox
24 iun. 2020 18:03:22

am reușit să fac funcțional codul de mai sus, dar din nu știu ce motiv, când efectuam căutarea, returna date din alte post_types chiar dacă am specificat tipul de post în array-ul $args. Am rezolvat adăugând condiția direct în interogarea pentru titlu, care a funcționat pentru mine: $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
Arată celelalte 3 comentarii
4
21

Am dorit să actualizez acest cod la care ați lucrat pentru WordPress 4.0 și versiunile superioare, deoarece esc_sql() este învechit începând cu versiunea 4.0.

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

    if($search_term = $wp_query->get( 'search_prod_title' )){
        /*folosim esc_like() aici în loc de esc_sql()*/
        $search_term = $wpdb->esc_like($search_term);
        $search_term = ' \'%' . $search_term . '%\'';
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }

    return $where;
}

Restul rămâne la fel.

De asemenea, vreau să menționez că puteți folosi variabila s în argumentele WP_Query pentru a transmite termenii de căutare, care cred că va căuta și în titlurile postărilor.

Ca în exemplul de mai jos:

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

Ce este exact search_prod_title? Ar trebui să-l schimb cu altceva?

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

De când este esc_sql învechit? Nu este. $wpdb->escape este însă... https://developer.wordpress.org/reference/functions/esc_sql/

Jeremy Jeremy
2 feb. 2018 19:36:34

Rețineți că parametrul s caută și în conținutul articolului, ceea ce poate să nu fie scopul dorit. =)

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

like_escape învechit începând cu versiunea 4.0.0 Utilizați wpdb::esc_like

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

Cu unele soluții vulnerabile postate aici, vin cu o versiune puțin simplificată și mai sigură.

Mai întâi, creăm o funcție pentru filtrul posts_where care vă permite să afișați doar postările care corespund anumitor condiții:

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;
}

Acum adăugăm cc_search_post_title în argumentele noastre de interogare:

$args = array(
    'cc_search_post_title' => $search_term, // caută doar în titlul postării
    'post_status' => 'publish',
);

Și în final aplicăm filtrul în jurul interogării:

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

Folosind get_posts()

Anumite funcții care preiau postări nu rulează filtre, astfel încât funcțiile de filtrare posts_where pe care le atașați nu vor modifica interogarea. Dacă intenționați să folosiți get_posts() pentru a interoga postările, trebuie să setați suppress_filters la false în array-ul de argumente:

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

Acum puteți folosi 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 );

Ce zici de parametrul s?

Parametrul s este disponibil:

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

Deși adăugarea termenului de căutare în parametrul s funcționează și va căuta în titlul postării, va căuta de asemenea în conținutul postării.

Ce zici de parametrul title adăugat în WP 4.4?

Transmiterea unui termen de căutare în parametrul title:

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

Este sensibil la majuscule și folosește LIKE, nu %LIKE%. Aceasta înseamnă că căutarea pentru hello nu va returna postări cu titlul Hello World sau Hello.

19 apr. 2018 15:58:35
Comentarii

Excelent. Căutam parametrul 'post_title' și, evident, nu am găsit nimic.

MastaBaba MastaBaba
13 sept. 2019 18:55:30

Am o eroare cu wp query sau get posts: "E_WARNING Eroare în fișierul »class-wp-hook.php« la linia 288: Parametrul 2 pentru cc_post_title_filter() se aștepta să fie o referință, a fost dată o valoare

Elkrat Elkrat
3 mar. 2020 19:28:10

@Elkrat Elimină & din &$wp_query în funcția cc_post_title_filter.

Mattimator Mattimator
6 mai 2020 00:04:16
2

Bazându-mă pe alte răspunsuri anterioare, pentru a oferi flexibilitate în situația în care doriți să căutați un articol care conține un cuvânt într-un câmp meta SAU în titlul articolului, ofer această opțiune prin argumentul "title_filter_relation." În această implementare, permit doar intrări "OR" sau "AND" cu o valoare implicită "AND."

function title_filter($where, &$wp_query){
    global $wpdb;
    if($search_term = $wp_query->get( 'title_filter' )){
        $search_term = $wpdb->esc_like($search_term); //în loc de 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;
}

Iată un exemplu al codului în acțiune pentru un tip de articol foarte simplu "faq" unde întrebarea este chiar titlul articolului:

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
Comentarii

Perspectivă bună, adăugarea de variabile personalizate "query vars" la argumentele query transmise către WP_Query pentru a putea accesa acestea în cadrul filtrului posts_where.

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

pare un răspuns bun, singura problemă este că nu funcționează pentru mine :-(

luke_mclachlan luke_mclachlan
28 mar. 2022 14:04:48
0

Cea mai optimă abordare pentru efectuarea unei interogări WP_Query cu căutare 'LIKE' pe post_title este să includeți argumentul de interogare 'search_columns'. Dacă construiți manual WP_Query, ar trebui să îl specificați astfel:

'search_columns' => ['post_title']

Puteți găsi mai multe detalii în codul sursă WordPress pe Trac: https://core.trac.wordpress.org/browser/tags/6.3/src/wp-includes/class-wp-query.php#L1426

Cu toate acestea, dacă intenția dumneavoastră este să modificați interogările generate de plugin-uri terțe sau interogări create de teme, puteți realiza acest lucru utilizând cârligul de filtrare 'post_search_columns'.

Documentația oficială oferă informații detaliate despre cum să utilizați acest cârlig: https://developer.wordpress.org/reference/hooks/post_search_columns/

28 sept. 2023 13:34:38