I need to do a WP_Query with a LIKE on the post_title.
I started with this regular WP_Query:
$wp_query = new WP_Query(
array (
'post_type' => 'wp_exposants',
'posts_per_page' => '1',
'post_status' => 'publish',
'orderby' => 'title',
'order' => 'ASC',
'paged' => $paged
)
);
But what I actually want to do looks like this 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);
The output prints the results i’m excpecting, but I use the regular <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?> to display the results.
And that is not working with $wpdb->get_results().
How can I achieve what I described here?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
I would solve this with a filter on WP_Query. One that detects an extra query variable and uses that as the prefix of the title.
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;
}
This way you can still call WP_Query, you just pass the title as the wpse18703_title argument (or change the name to something shorter).
Method 2
Simplified:
function title_filter( $where, &$wp_query )
{
global $wpdb;
// 2. pull the custom query in here:
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. define a custom query var here to pass your term through:
'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;
Method 3
Wanted to update this code you guys worked on for the wordpress 4.0 and above as esc_sql() is deprecated in 4.0 higher.
function title_filter($where, &$wp_query){
global $wpdb;
if($search_term = $wp_query->get( 'search_prod_title' )){
/*using the esc_like() in here instead of other esc_sql()*/
$search_term = $wpdb->esc_like($search_term);
$search_term = ' '%' . $search_term . '%'';
$where .= ' AND ' . $wpdb->posts . '.post_title LIKE '.$search_term;
}
return $where;
}
Rest of the stuff is same.
Also I want to point out you can use s variable within WP_Query arguments to pass search terms, which will also search for post title i believe.
Like this:
$args = array(
'post_type' => 'post',
's' => $search_term,
'post_status' => 'publish',
'orderby' => 'title',
'order' => 'ASC'
);
$wp_query = new WP_Query($args);
Method 4
With some vulnerable solution posted here, I come with a bit simplified and sanitized version.
First, we create a function for the posts_where filter which allows you to only show posts matching specific conditions:
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;
}
Now we add cc_search_post_title into our query arguments:
$args = array(
'cc_search_post_title' => $search_term, // search post title only
'post_status' => 'publish',
);
And finally wrap the filter around the 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 );
Using get_posts()
Certain functions which retrieve posts do not run filters, so the posts_where filter functions you attach will not modify the query. If you plan to use get_posts() to query your posts, you need to set suppress_filters to false in your argument array:
$args = array(
'cc_search_post_title' => $search_term,
'suppress_filters' => FALSE,
'post_status' => 'publish',
);
Now you can use 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 );
What about the s parameter?
The s parameter is available:
$args = array(
's' => $search_term,
);
While adding your search term into the s parameter work and it will search the post title, it will also search the post content.
What about the title parameter which was added with WP 4.4?
Passing a search term into the title parameter:
$args = array(
'title' => $search_term,
);
Is case sensitive and LIKE, not %LIKE%. This mean search for hello will not return post with title Hello World or Hello.
Method 5
Building on other answers before me, to provide flexibility in the situation where you want to search a post that contains a word in a meta field OR in the title of the post, I give that option via the argument “title_filter_relation.” In this implementation, I only allow for “OR” or “AND” inputs with a default of “AND.”
function title_filter($where, &$wp_query){
global $wpdb;
if($search_term = $wp_query->get( 'title_filter' )){
$search_term = $wpdb->esc_like($search_term); //instead of 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;
}
Here’s an example of the code in action for a very simple post type “faq” where the question is the post title itself:
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);
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0