WP_Query cu "post_title LIKE 'something%'"?
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?
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).
@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
@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
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
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;
Cred că codul se explică de la sine, cel puțin pentru mine. Mulțumesc pentru partajarea scriptului complet.
Hassan Dad Khan
@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
like_escape învechit începând cu versiunea 4.0.0 Folosește wpdb::esc_like
Empty Brain
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
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);
Ce este exact search_prod_title? Ar trebui să-l schimb cu altceva?
Antonios Tsimourtos
De când este esc_sql învechit? Nu este. $wpdb->escape este însă... https://developer.wordpress.org/reference/functions/esc_sql/
Jeremy
Rețineți că parametrul s caută și în conținutul articolului, ceea ce poate să nu fie scopul dorit. =)
Christine Cooper
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.
Excelent. Căutam parametrul 'post_title' și, evident, nu am găsit nimic.
MastaBaba
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
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);
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
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/