0

I have a custom post type with custom taxonomies, basically a gallery post type. I want to be able to search through the images in the post type. I have created a custom search query for post type and attachments and it doesn't work quite well. I get duplicate search results for some images. Since the image is part of a CPT entry but also exist in the media library. Is there a way to search attachments from a CPT only?

<?php

Class SMGallerySearch {

private $query_instance;

public function __construct(){
    add_filter( 'posts_join', array( &$this, 'terms_join' ) );
    add_filter( 'posts_search', array( &$this, 'search_where' ), 10, 2 );
    add_filter( 'posts_request', array( &$this, 'distinct' ) );
    add_filter( 'pre_get_posts', array( &$this, 'search_query' ) );
    add_filter( 'attachment_link', array( &$this, 'the_search_attachment_link' ), 10, 2 );
    add_filter( 'the_excerpt', array( &$this, 'the_search_excerpt' ) );
}

public function terms_join( $join ) {
    global $wpdb;

    if ( ! empty( $this->query_instance->query_vars['s'] ) ) {

        // searching custom taxonomies
        $taxonomies = get_object_taxonomies( array( 'sm_gallery_item', 'attachment' ) );
        foreach ( $taxonomies as $taxonomy ) {
            $on[] = "ttax.taxonomy = '" . addslashes( $taxonomy )."'";
        }

        // build our final string
        $on = ' ( ' . implode( ' OR ', $on ) . ' ) ';
        $join .= " LEFT JOIN $wpdb->term_relationships AS trel ON ($wpdb->posts.ID = trel.object_id) LEFT JOIN $wpdb->term_taxonomy AS ttax ON ( " . $on . " AND trel.term_taxonomy_id = ttax.term_taxonomy_id) LEFT JOIN $wpdb->terms AS tter ON (ttax.term_id = tter.term_id) ";
    }
    return $join;
}


/**
 * Creates the list of search keywords from the 's' parameters
 *
 * @since 1.8.7
 */
public function get_search_terms() {
    global $wpdb;
    $s = isset( $this->query_instance->query_vars['s'] ) ? $this->query_instance->query_vars['s'] : '';
    $sentence = isset( $this->query_instance->query_vars['sentence'] ) ? $this->query_instance->query_vars['sentence'] : false;
    $search_terms = array();

    if ( !empty( $s ) ) {
        // added slashes screw with quote grouping when done early, so done later
        $s = stripslashes( $s );
        if ( $sentence ) {
            $search_terms = array( $s );
        } else {
            preg_match_all( '/".*?("|$)|((?<=[\\s",+])|^)[^\\s",+]+/', $s, $matches );
            $search_terms = array_map( create_function( '$a', 'return trim($a, "\\"\'\\n\\r ");' ), $matches[0] );
        }
    }
    return $search_terms;
}


/**
 * Add where clause to the search query
 *
 * @since 1.8.7
 */
public function search_where( $where, $wp_query ) {

    $this->query_instance = &$wp_query;
    global $wpdb;

    $searchQuery = $this->search_default();

    $searchQuery .= $this->build_search_categories();

    if ( $searchQuery != '' ) {
        $where = preg_replace( '#\(\(\(.*?\)\)\)#', '(('.$searchQuery.'))', $where );

    }
    return $where;
}


/**
 * Search for terms in default locations like title and content
 * replacing the old search terms seems to be the best way to
 * avoid issue with multiple terms
 *
 * @since 1.8.7
 */
public function search_default(){
    global $wpdb;

    $not_exact = empty( $this->query_instance->query_vars['exact'] );
    $search_sql_query = '';
    $seperator = '';
    $terms = $this->get_search_terms();

    // if it's not a sentance add other terms
    $search_sql_query .= '(';
    foreach ( $terms as $term ) {
        $search_sql_query .= $seperator;

        $esc_term = esc_sql( $term );
        if ($not_exact) {
            $esc_term = "%$esc_term%";
        }

        $like_title = "($wpdb->posts.post_title LIKE '$esc_term')";
        $like_post = "($wpdb->posts.post_content LIKE '$esc_term')";

        $search_sql_query .= "($like_title OR $like_post)";

        $seperator = ' AND ';
    }

    $search_sql_query .= ')';
    return $search_sql_query;
}


/**
 * Create the search categories query
 *
 * @since 1.8.7
 */
public function build_search_categories() {
    global $wpdb;
    $vars = $this->query_instance->query_vars;

    $s = $vars['s'];
    $search_terms = $this->get_search_terms();
    $exact = isset( $vars['exact'] ) ? $vars['exact'] : '';
    $search = '';

    if ( ! empty( $search_terms ) ) {
        // Building search query for categories slug.
        $n = ( $exact ) ? '' : '%';
        $searchand = '';
        $searchSlug = '';
        foreach ( $search_terms as $term ) {
            $term = addslashes_gpc( $term );
            $searchSlug .= "{$searchand}(tter.slug LIKE '{$n}".sanitize_title_with_dashes( $term )."{$n}')";
            $searchand = ' AND ';
        }
        if ( count( $search_terms ) > 1 && $search_terms[0] != $s ) {
            $searchSlug = "($searchSlug) OR (tter.slug LIKE '{$n}".sanitize_title_with_dashes( $s )."{$n}')";
        }
        if ( ! empty( $searchSlug ) )
            $search = " OR ({$searchSlug}) ";

        // Building search query for categories description.
        $searchand = '';
        $searchDesc = '';
        foreach ( $search_terms as $term ) {
            $term = addslashes_gpc( $term );
            $searchDesc .= "{$searchand}(ttax.description LIKE '{$n}{$term}{$n}')";
            $searchand = ' AND ';
        }
        $sentence_term = esc_sql( $s );
        if ( count( $search_terms ) > 1 && $search_terms[0] != $sentence_term ) {
            $searchDesc = "($searchDesc) OR (ttax.description LIKE '{$n}{$sentence_term}{$n}')";
        }
        if ( ! empty( $searchDesc ) )
            $search = $search." OR ({$searchDesc}) ";
    }
    return $search;
}

public function distinct( $query ) {
    global $wpdb;
    if ( ! empty( $this->query_instance->query_vars['s'] ) ) {
        if ( strstr( $query, 'DISTINCT' ) ) {}
        else {
            $query = str_replace( 'SELECT', 'SELECT DISTINCT', $query );
        }
    }
    return $query;
}

public function search_query( $query ) {

    if ( ! $query->is_search )
        return $query;

    if ( $query->get( 'post_type' ) && 'sm_gallery_item' == $query->get( 'post_type' ) ) {

        $post_types = $query->get( 'post_type' );
        if ( $post_types && 'sm_gallery_item' == $post_types )
            $post_types = array( 'sm_gallery_item', 'attachment' );

        $query->set( 'post_type', $post_types );

        /**
         * Add post status "inherit" (for attachments) since WP only searches "publish"
         */
        $post_status = $query->get( 'post_status' );
        if ( ! $post_status || 'publish' == $post_status )
            $post_status = array( 'publish', 'inherit' );

        if ( is_array( $post_status ) )
            $post_status[] = 'inherit';

        $query->set( 'post_status', $post_status );

        return $query;

    }

 }


}
  • I do not think this will be possible because WordPress Media has one to many relation. One media can belong to many page/post (types). – Prasad Nevase Oct 13 '15 at 18:01
  • Can you update your question with the search query you are using to filter the attachments belonging to a post type? May be if someone else has an idea he may help you. – Prasad Nevase Oct 14 '15 at 5:41
  • I updated the question to include the search class I currently have. – Rick Alday Oct 21 '15 at 15:45
0

I think I've cracked it. Replace the top 14 lines of code with

Class SellMediaSearch {

private $query_instance;

/**
 * Init
 */
public function __construct(){
    add_filter( 'posts_join', array( &$this, 'terms_join' ) );
    add_filter( 'posts_search', array( &$this, 'search_where' ), 10, 2 );
    add_filter( 'posts_request', array( &$this, 'distinct' ) );
    add_filter( 'pre_get_posts', array( &$this, 'search_query' ) );
    add_filter( 'attachment_link', array( &$this, 'the_search_attachment_link' ), 10, 2 );
    add_filter( 'the_excerpt', array( &$this, 'the_search_excerpt' ) );
    add_filter( 'posts_where' , array( &$this, 'posts_where' ));
}


public function posts_where( $where ) {

    global $wpdb;
    if( is_search() ) {
                    $where .= ' AND ( post_type = \'sell_media_item\' OR ( post_type = \'attachment\' AND post_parent !=  0 ) ) ';
    }
    return $where;
}

Needs testing, but initially works for me. See github for more comments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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