Tell me more ×
WordPress Answers is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I've been playing around with code snippets which add meta data to admin searches.

The best snippet I've found was written by Stefano on this question.

However, it appears to have 1, annoying bug when searching non-meta terms.

Here are some grabs from my local dev install. I've printed the 2 MySQL queries onto the screen.

View of the single CPT post I'm using to test

View of the single CPT post I'm using to test

This is the code working as expected and allowing me to search meta data from admin

This is the code working as expected and allowing me to search meta data from admin

Unfortunately the code creates duplicates on non-meta matches, in this case on post title

Unfortunately the code creates duplicates on non-meta matches, in this case on post title

A grab showing the post status, post type and post ancestors of dupes

A grab showing the post status, post type and post ancestors of dupes

Here is the code I'm running, it's basically the same as Stefano's, but with my crude attempts to make the query work.

/*
 * Search custom fields from admin keyword searches
 */

function rel_search_join( $join ) {
    global $pagenow, $wpdb;
    if ( is_admin() && $pagenow == 'edit.php' && $_GET['post_type'] == 'listings' && $_GET['s'] != '') {    
        $join .= 'LEFT JOIN ' . $wpdb->postmeta . ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }
    echo '<br><strong>JOIN</strong>: ';
    print_r ( $join );
    echo '<br>';
    return $join;
}
add_filter('posts_join', 'rel_search_join' );

function rel_search_where( $where ) {
    global $pagenow, $wpdb;
    if ( is_admin() && $pagenow == 'edit.php' && $_GET['post_type']=='listings' && $_GET['s'] != '' ) {
        $where = preg_replace( "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/", "(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
        $where = str_replace( "OR wp_posts.post_status = 'pending'", "", $where );
        $where = str_replace( "OR wp_posts.post_status = 'private'", "", $where );
        $where = str_replace( "OR wp_posts.post_status = 'draft'", "", $where );
        $where = str_replace( "OR wp_posts.post_status = 'future'", "", $where );
    }
    echo '<br><strong>WHERE</strong>: ';
    print_r ( $where );
    echo '<br>';
    return $where;
}
add_filter( 'posts_where', 'rel_search_where' );  
share|improve this question
Maybe it lists the revisions too? – passatgt Aug 24 at 11:49
I thought I was only looking at published, because I removed pending, private, draft & future. Didn't notice a revision type. – jnthnclrk Aug 24 at 11:51
Hmmm, doesn't appear to be a "revisions" status: codex.wordpress.org/Post_Status – jnthnclrk Aug 24 at 11:55
try to print_r the post type or the post id in one of the columns, i think revisions are post types, so if you can see revisions, you have that also in the results. But i can also see that you only display results from the listings post type, so i think i'm wrong. But its worth a try:) – passatgt Aug 24 at 11:57
Added a new grab with post statuses, post types and post ancestors. – jnthnclrk Aug 25 at 12:30

1 Answer

up vote 3 down vote accepted

A GROUP BY statement can group your posts after the JOIN. For Wordpress you can use the posts_groupby filter.

add_filter( 'posts_groupby', 'my_post_limits' );
function my_post_limits($groupby) {
    global $pagenow, $wpdb;
    if ( is_admin() && $pagenow == 'edit.php' && $_GET['post_type']=='listings' && $_GET['s'] != '' ) {
        $groupby = "$wpdb->posts.ID";
    }
    return $groupby;
}
share|improve this answer
Works great! Thanks! – jnthnclrk Aug 25 at 12:32

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.