I was responding to a post on Drupal4Lib about modifying Drupal search results to show facets for content types and was writing just how easy I thought it would be, when I decided that if it was really easy I could have some fun trying to make it work.
Instead of using the Search module, I used the Views module with the addition of Views FastSearch. I'm on Drupal 5, so this might not work with the new version of Views, but you'll get the idea.
I created a view named 'faceted_search' that:
- uses the view type 'search results' - this might be
- uses the field 'Search: score'
- uses a filter for 'Node: published' = true
- uses an exposed filter for 'Search: Fast Index'
- uses an exposed filter for 'Node: Type'
- uses 'Lock Operator' on both exposed filters.
- sorts by 'Search: score'
I put this view at http://www.oregonlibaries.net/faceted_search.
Two code snippets make this work.
The first is in my theme's template.php file. I added a function that modifies the exposed filters for this view.
function phptemplate_views_filters($form) {
if ($form['#view_name'] == 'faceted_search') {
// Make the search box (filter1) as big as we want.
$form['filter1']['#size']=60;
// Hide the content type filter (filter0).
unset($form['filter0']);
}
return theme_views_filters ($form);
}The second snippet is copied largely from how-to on drupal.org for Theming your Views. I copied the part about 'Display a view'.
// lnet_views_view_faceted_search displays themes this view to show facets by content type.
//
// In this case, the module is called 'lnet' and the view is called 'faceted_search'.
//
// Call yours MODULE_views_view_VIEWNAME
//
// Based on the code snippet at http://drupal.org/node/42597 for 'Display a view'.
function lnet_views_view_faceted_search ($view,$type,$nodes,$level,$args) {
// The beginning of the function sets up the facets by modifying the Views query.
$my_view = views_build_view('queries',$view,$args);
$my_query = $my_view['query'];
// Instead of asking for nodes, we're asking for a count of each node type.
$my_query = str_replace('DISTINCT(node.nid)','node.type, COUNT(node.nid) as co',$my_query);
// Remove the ORDER BY stuff and replace it with GROUP BY stuff.
$my_query = preg_replace('/ORDER BY .*$/','GROUP BY (node.type)',$my_query);
// Last, remove the content type filter if one exists.
$my_query = preg_replace('/AND \(node\.type.*$/','GROUP BY (node.type)',$my_query);
$facet_query = db_query($my_query);
$facets = array();
while ($ref = db_fetch_object($facet_query)) {
$facets[$ref->type] = $ref->co;
}
$facet_output .="<div class='facet_tabs'>\n";
foreach ($facets as $ntype => $count) {
// Get the URL - there's got to be a more Drupal-ly way to do this.
$link = $_SERVER['REQUEST_URI'];
// Remove the content type filter (in this case, filter0) from the end of the URL, if it exists
$link = preg_replace('/\&filter0=.*/','',$link);
// Add a new content type filter at the end of the URL
$link .= '&filter0=' . $ntype;
$facet_output .= "<a href='http://www.oregonlibraries.net" . $link . "'>$ntype</a>" . ' (' . $count . ') ';
}
$facet_output .= "</div>\n";
$num_nodes = count($nodes);
if ($type == 'page') {
drupal_set_title(filter_xss_admin(views_get_title($view, 'page')));
views_set_breadcrumb($view);
}
if ($num_nodes) {
$output .= views_get_textarea($view, $type, 'header');
}
if ($type != 'block' && $view->exposed_filter) {
$output .= views_theme('views_display_filters', $view);
}
// Here is where we display the facets!
$output .= $facet_output;
$plugins = _views_get_style_plugins();
$view_type = ($type == 'block') ? $view->block_type : $view->page_type;
if ($num_nodes || $plugins[$view_type]['even_empty']) {
if ($level !== NULL) {
$output .= "<div class='view-summary ". views_css_safe('view-summary-'. $view->name) ."'>".
views_theme($plugins[$view_type]['summary_theme'], $view, $type, $level, $nodes, $args) . '</div>';
}
else {
$output .= "<div class='view-content ". views_css_safe('view-content-'. $view->name) ."'>".
views_theme($plugins[$view_type]['theme'], $view, $nodes, $type) . '</div>';
}
$output .= views_get_textarea($view, $type, 'footer');
if ($type == 'block' && $view->block_more && $num_nodes >= $view->nodes_per_block) {
$output .= theme('views_more', $view->real_url);
}
}
else {
$output .= views_get_textarea($view, $type, 'empty');
}
if ($view->use_pager) {
$output .= theme('pager', '', $view->pager_limit, $view->use_pager - 1);
}
if ($output) {
$output = "<div class='view ". views_css_safe('view-'. $view->name) ."'>$output</div>\n";
}
return $output;
}The results aren't perfect - I lost my pager, and I hacked some things I don't know how to do in "The Drupal Way", but I think this is a good whack at faceted search in Drupal.
Update: I just noticed all of the faceted search modules at http://drupal.org/project/faceted_search, including under 'See Also'. Wee!
Comments
Hi Caleb, still digesting the
Hi Caleb, still digesting the actual content of the post, but you've got a typo in your example URL (mispeeled libary) :-)