3

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; ?>
1
  • 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. Nov 15, 2011 at 15:18

3 Answers 3

8

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 
    //...
}
4
  • 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! Apr 19, 2011 at 17:36
  • Zach, any updates on getting this working? I'm looking for something very similar and I am also using Relevanssi. Apr 25, 2011 at 19:26
  • 1
    I was able to get this working - Thank you Bainternet! Aug 29, 2011 at 16:23
  • 2
    When I use your groupby-code I only get one result of each post type.
    – powerbuoy
    Mar 29, 2015 at 20:35
6

Just 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.

The simple solution is to add this conditional around the code above:

if (!is_admin()) {
  [your code here]
}
2

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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