Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have a site that has a few custom post types. When a customer searches it shows a combination of all the different posts. I'd like to segment the two on the same page resulting in something that looks like the example below. Any help would be appreciated.

Showing results for: really cool search
Video Management
from a central location. Radius offers interactive map capability, and multiple monitor support. Designed for a multiple monitor environmen... http://openeye.net/products/software/video-management


Knowledge Base Entries:
Repairing your device
from a central location. Radius offers interactive map capability, and multiple monitor support. Designed for a multiple monitor environmen... http://openeye.net/?faq=video-management-repair

Example of my loop from loop-search.php

<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<h4 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'twentyten' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h4>
<?php if ( is_archive() || is_search() ) : // Only display excerpts for archives and search. ?>
    <div class="entry-summary">
        <?php the_post_thumbnail; ?>
        <?php if (function_exists('relevanssi_the_excerpt')) { relevanssi_the_excerpt(); }; ?>
        <a href="<?php the_permalink(); ?>"><?php the_permalink(); ?></a>
    </div><!-- .entry-summary -->
<?php else : ?>
    <div class="entry-content">
        <?php the_post_thumbnail; ?>
        <?php the_content( __( 'Continue reading', 'twentyten' ) ); ?>
        <?php wp_link_pages( array( 'before' => '<div class="page-link">' . __( 'Pages:', 'twentyten' ), 'after' => '</div>' ) ); ?>
        <a href="<?php the_permalink(); ?>"><?php the_permalink(); ?></a>
    </div><!-- .entry-content -->
<?php endif; ?>

my changes to search.php

<?php if ( have_posts() ) : $posts_per_page = 20; ?>
    <span style="font-size:18px;" class="page-title"><?php printf( __( 'Showing results for: %s', 'twentyten' ), '<span>' . get_search_query() . '</span>' ); ?></span>
    <?php
    /* Run the loop for the search to output the results.
     * If you want to overload this in a child theme then include a file
     * called loop-search.php and that will be used instead.
     */
     get_template_part( 'loop', 'search' );
    ?>
<?php else : ?>
    <div id="post-0" class="post no-results not-found">
        <h2 class="entry-title"><?php _e( 'Nothing Found', 'twentyten' ); ?></h2>
        <div class="entry-content">
    <?php if (function_exists('relevanssi_didyoumean')) {
        relevanssi_didyoumean(get_search_query(), "<p>Sorry, but nothing matched your search criteria. Please try again with some different keywords. Or you can also try ", "</p>", 5);
    }?>
            <?php related_searches(); ?>
        </div><!-- .entry-content -->
    </div><!-- #post-0 -->
<?php endif; ?>
share|improve this question

4 Answers 4

up vote 6 down vote accepted

You can group posts by type using posts_groupby filter hook:

add_filter('posts_groupby', 'group_by_post_type' );
function group_by_post_type( $groupby )
{
  global $wpdb;
  if( !is_search() ) {
    return $groupby;
  }
  $mygroupby = "{$wpdb->posts}.post_type";
  if( !strlen(trim($groupby))) {
    // groupby was empty, use ours
    return $mygroupby;
  }
  // wasn't empty, append ours
  return $groupby . ", " . $mygroupby;
}

Then in your loop of do something like this:

$last_type="";
$typecount = 0;
while (have_posts()){
    the_post();
    if ($last_type != $post->post_type){
        $typecount = $typecount + 1;
        if ($typecount > 1){
            echo '</div>'; //close type container
        }
        // save the post type.
        $last_type = $post->post_type;
        //open type container
        switch ($post->post_type) {
            case 'post':
                echo "<div class=\"post container\"><h2>posts search result</h2>";
                break;
            case 'page':
                echo "<div class=\"page container\"><h2>pages search result</h2>";
                break;
            case 'custom_type_name':
                echo "<div class=\"custom container\"><h2>custom post type search result</h2>";
                break;
            //add as many as you need.
        }
    }

    //...
    // do your loop 
    //...
}
share|improve this answer
    
I seem to be having a bit of trouble getting this working, it doesn't return any data from the loop. I'm using Relevanssi, but I don't believe it has an effect on my loop. I'll update the post with what I'm doing on my end. Thanks again Bainternet! –  Zach Shallbetter Apr 19 '11 at 17:36
    
Zach, any updates on getting this working? I'm looking for something very similar and I am also using Relevanssi. –  Jonathan Wold Apr 25 '11 at 19:26
1  
I was able to get this working - Thank you Bainternet! –  Jonathan Wold Aug 29 '11 at 16:23

I don't have enough karma on this stackexchange to reply to another solution, but wanted to add that while @bainternet's up-voted solution is great, it can break the Media Library's search function. This problem, and a simple solution, both appear here: http://wordpress.org/support/topic/cant-search-in-media-library . The simple solution is to add this conditional around the code above:

if (!is_admin()) {
  [your code here]
}
share|improve this answer

I was looking for the same thing and I found something interesting on relevanssi site.

You can find it here

Separating posts by post type

Actually I'm not able to make it work but hopefully this is the better solution using Relevanssi.

Bye Carletto

share|improve this answer

I got this working after tweaking the above solution a bit. First the filter need to be changed to retrieve more that 1 result:

add_filter('posts_orderby', 'group_by_post_type', 10, 2);
function group_by_post_type($orderby, $query) {
global $wpdb;
if ($query->is_search) {
    return $wpdb->posts . '.post_type DESC';
}
// provide a default fallback return if the above condition is not true
return $orderby;
}

Then the loop needed to be tweaked a little. I wanted to style my results differently with different information, so I added a further conditional.

<?php if(have_posts()) : ?>

<?php   
$last_type="";
$typecount = 0;
while (have_posts()) :
the_post();
if ($last_type != $post->post_type){
    $typecount = $typecount + 1;
    if ($typecount > 1){
        echo '</div><!-- close container -->'; //close type container
    }
    // save the post type.
    $last_type = $post->post_type;
    //open type container
    switch ($post->post_type) {
        case 'post':
            echo "<div class=\"postsearch container\"><h2>Blog Results</h2>";
            break;
        case 'product':
            echo "<div class=\"productsearch container\"><h2>Product Search   Results</h2>";
            break;

    }
} 
?>

    <?php if('post' == get_post_type()) : ?>
     <li class="post"><?php the_title(); ?></li>
<?php endif; ?>

  <?php if('product' == get_post_type()) : ?>
 <li class="product"><?php the_title(); ?></li>
  <?php endif; ?>


<?php endwhile; ?>

<?php else : ?>
<div class="open-a-div">
<p>No results found.</p>    

<?php endif; ?>       

</div><!-- throw a closing div in --> 

Basically the only changes are the filter and the closing div that was omitted at the end. That and the "No results found." This is working on my site.

share|improve this answer

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.