hi all,

is there a way to exclude nodes of a specific nodetype
from being indexing by the search module?

thanks,
enky

Comments

squaretone’s picture

There may be other ways to do this but I have done it at the theme level before. In the example code below I've re-themed the _search_item() function with phptemplate in order to filter out image node types. Just place the folowing code between the in your template.php file for the theme you're using. If there is not template.php file in that folder; create one.


// re-theme the search results 
function phptemplate_search_item($item, $type) {
 if($item['type'] != 'image'){// FILTER OUT IMAGE NODES-------
 
  if (module_hook($type, 'search_item')) {
    $output = module_invoke($type, 'search_item', $item);
  }
  else {
    $output = ' <dt class="title"><a href="'. check_url($item['link']) .'">'. check_plain($item['title']) .'</a></dt>';
    $info = array();
    if ($item['type']) {
      //$info[] = $item['type'];
    }
    if ($item['user']) {
      //$info[] = $item['user'];
    }
    if ($item['date']) {
      //$info[] = format_date($item['date'], 'small');
      $info[] = date("F j, Y", $item['date']);
    }
    if (is_array($item['extra'])) {
      $info = array_merge($info, $item['extra']);
    }
 
     $output .= ' <dd>'. ($item['snippet'] ? '<p>'. $item['snippet'] . '</p>' : '') . '<p class="search-info">' . implode(' - ', $info) .'</p></dd>';
    
  }
  return $output;
 }
} 

You can see I did more than just filter out the display of image nodes. I also reformatted how the search results were displayed. If you want to get really fancy, you can theme the display of each result differently by node type.

Also, by simply changing that first if statement to read

 if($item['type'] == 'image')

You could tell Drupal to only return results from that 'image' node type.

The one caveat to this method is that if you have node types 'foo' and 'bar' and are filtering out node type 'foo'... if the user's search finds only a result that matches a 'foo' type and none that match 'bar' it will display an empty result as opposed to letting the user know that there were no matches to the search. There is probably a work-around but I've not explored it yet.

Eric Lawrence
Developer/UX Designer
http://squaretone.com

enky’s picture

thanks ericelbow, i will try your solution,

will it be safe hacking the node.module to not to show certian nodetypes
on the search results?

enky
www.electros.in/blog/venkatesh

squaretone’s picture

I would avoid hacking modules whenever possible... especially core modules like node.module. When it comes time for security updates it will be painful to go back in and re-hack the updated module. When possible, use theming overrides instead like the one above.

One of the things that makes Drupal so great is how easily it allows developers to make modules themable. The example above takes advantage of the powerful theming engine - phptemplate in this case. If you use an override in your theme it will most likely still work if you upgrade your drupal site later and if you do something to mess it up you can just change themes until you fix it.

Check out this entry in the handbook on themeable functions in Drupal: http://drupal.org/node/11811

Eric Lawrence
Developer/UX Designer
http://squaretone.com

tille’s picture

I first used squaretone's theme level based suggestion - but I have actually a second function in my phptemplate that is there for styling the results page - so I put the NOT-statement there.. which might also reduce the 'load' a bit cause I'm loading the 'theme('search_item', $entry, $type)' only when I have my 'other' content types....

here it comes:


function phptemplate_search_page($results, $type) {
  $output = '<dl class="search-results">';

  foreach ($results as $entry) {
 
// FILTER OUT IMAGE NODES----(CASE SENSITIVE)
 if($entry['type'] != 'image') { 
    $output .= ("<div class='one-result'>");
    $output .= theme('search_item', $entry, $type);
    $output .= ("</div>");
}
  }
  $output .= '</dl>';
  $output .= theme('pager', NULL, 10, 0);

  return $output;
}



function phptemplate_search_item($item, $type) {

  if (module_hook($type, 'search_item')) {
    $output = module_invoke($type, 'search_item', $item);
  }
  else {
    if (in_array($item['type'], node_get_types())) {
      $node->nid = str_replace("node/","",drupal_get_normal_path(str_replace("/", "", $item['link'])));
      $node = node_load($node->nid);
      $node->teaser = $item['snippet'];
      $output = node_view($node, TRUE, FALSE, FALSE);
    }
    else {
      $output = '<dt class="title">\'<a href="'. check_url($item['link']) .'">'. check_plain($item['title']) .'</a>\'</dt>';
      $info = array();
      if ($item['image']) {
      //  $info[] = $item['type'];
      }
      if ($item['user']) {
      //  $info[] = $item['user'];
      }
      if ($item['date']) {
      //  $info[] = format_date($item['date'], 'small');
      }
      if (is_array($item['extra'])) {
      // $info = array_merge($info, $item['extra']);
      }
      $output .= ''. ($item['snippet'] ? '<p>'. $item['snippet'] . '</p>' : '') . '<p class="search-info">' . implode(' - ', $info) .'</p>';
    }
  }

  return $output;
}

greetings, till..

ps: I just realized that of course the content type IS case sensitive:
--> 'image' vs. 'Image'

___________________________
my pictures: www.bilderbook.org

___________________________

jakeg’s picture

I don't want customers in my basic CRM system to be found by regular users to the site. Hence, in one of my modules I've implemented this code (note, it may be important for my module to come after node.module in the module list):

// hook_update_index implementation. Ensure customers aren't shown in search
function mymodule_update_index() {
  if (function_exists('search_wipe')) {
    $result = db_query("SELECT nid FROM {node} WHERE type = 'customer'");
    while ($data = db_fetch_object($result)) {
      search_wipe($data->nid, 'node');
    }
  }
}

And to remove the customer checkbox from the advanced search options, add this to your module:

function mymodule_form_alter($form_id, &$form) {
  if ($form_id == 'search_form') {
      unset($form['advanced']['type']['#options']['customer']);
  }
}

Following the next cron run, the customers are no longer shown in the search results.

Jake
---
School and university yearbooks and Drupal web services, London

flanderz’s picture

Using hook_update_index works for me! Thanks for the tip. By the way, I don't think it matters what order the modules are called for this. It appears this is just dropping the specified nodes from the index. It also appears to be called *after* the index is rebuilt by cron (most likely for just this reason.)

markhope’s picture

I'm hoping this will work for me too.
Can that function be put in a module on its own, and is this example for 4.7?

Also, how would the query be written to remove multiple content types?
My sql knowledge is a bit basic.

Mark

NaX’s picture

The search_config module is currently testing a patch with this exact feature.

See http://drupal.org/node/170605

You can help test by trying the dev module http://drupal.org/node/175520

halhx’s picture

Thanks for the solution. It simply work

nancydru’s picture

I think this is wrong. It looks like this causes the search status to never reach 100%.

Change the while loop code:

      // Delete anything that is already indexed.
      search_wipe($data->nid, 'node');
      // Now give it nothing to index. This allows the search counts to reach 100%.
      search_index($data->nid, 'node', '');
Bevan’s picture

Here's a good solution to this http://drupal.org/node/111744