0
votes

I have a custom post type (songs) and several custom fields associated with it. One of the custom fields is a checkbox (sample_playlist), the rest are text strings.

I have added a select element and I am using the checkbox value to filter the results when on edit.php?post_type=songs

add_filter( 'parse_query', array( &$this, 'wpse45436_posts_filter' ) );

function wpse45436_posts_filter( $query ){
// current page and post type checks omitted
    $query->query_vars['meta_key'] = 'sample_playlist';
    $query->query_vars['meta_value'] = 'on'; //these are the queries that get executed when filtering the posts that have the custom field checkbox checked
  }

This works fine when I only attempt to filter the results based on the checkbox value.

Searching by other custom field values is also possible on that same page via

 add_filter( 'posts_join', array( &$this, 'songs_search_join' ) );
 add_filter( 'posts_where', array( &$this, 'songs_search_where' ) );
function songs_search_join ($join){
    // current page, post type and $_GLOBAL['s'] checks omitted    
    $join .='LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    return $join;
}
function songs_search_where( $where ){
    // current page, post type and $_GLOBAL['s'] checks omitted
    $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 
    );
    return $where;
}

The search works fine when I only try to search terms by custom field values.

HOWEVER, when I try to use both of these sequentially (ie search then filter, or vice versa), I run into a problem with the search join using wp_postmeta as well as the filter by "custom field checkbox value" using it as well. Is there a way around this, that would allow me to utilize both of these sequentially?

the error I recieve: WordPress database error Not unique table/alias: 'wp_postmeta'

the resulting sql query output:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id WHERE 1=1 AND (((wp_posts.post_title LIKE '%searchterm%') OR (wp_postmeta.meta_value LIKE '%searchterm%') OR (wp_posts.post_content LIKE '%searchterm%'))) AND wp_posts.post_type = 'songs' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'future' OR wp_posts.post_status = 'draft' OR wp_posts.post_status = 'pending' OR wp_posts.post_status = 'private') AND ( (wp_postmeta.meta_key = 'sample_playlist' AND CAST(wp_postmeta.meta_value AS CHAR) = 'on') ) ORDER BY wp_posts.post_date DESC LIMIT 0, 20
1

1 Answers

2
votes

I needed to use an alias for $wpdb->postmeta in my search:

add_filter( 'posts_join', array( &$this, 'songs_search_join' ) );
 add_filter( 'posts_where', array( &$this, 'songs_search_where' ) );
function songs_search_join ($join){
    // current page, post type and $_GLOBAL['s'] checks omitted    
    $join .='LEFT JOIN '.$wpdb->postmeta. ' p ON '. $wpdb->posts . '.ID = p.post_id ';
    return $join;
}
function songs_search_where( $where ){
    // current page, post type and $_GLOBAL['s'] checks omitted
    $where = preg_replace(
      "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
      "(".$wpdb->posts.".post_title LIKE $1) OR (p.meta_value LIKE $1)", $where 
    );
    return $where;
}