Filtering Node Types In Drupal 6 Search

A common practice when creating sites in Drupal is to create different node types for different purposes. Sometimes these node types can be functionality based rather than content based and are used for creating a rotating banner or something similar. A side effect of this is that you will then see these nodes appearing in search results, which can cause some confusing results to be displayed.

So how do you remove these nodes? Well with quite a simple little module you can intercept the search query and stop certain node types being searched for. Adding a couple of extra functions means that we can add form controls to the advanced search form and the search admin area so that nodes can be selected to be excluded from the search results.

First, create a folder in your sites/all/modules directory for the module (I called it searchfilter) along with an info file. We need to add a dependency to the search module so that this module doesn't cause any weird side effects (errors really) when the search module it not present. Here is the searchfilter.info file.

; $Id$

name = Search filter
description = "Filters out selected content types from search results"
dependencies[] = search
core = 6.x

Now create a file that will store the module code called searchfilter.module. This file will contain 4 functions, which I will now go over one by one. The first thing to do it set up a permission so that we can restrict or allow access to the node filter. This is a simple implementation of hook_perm().

function searchfilter_perm() {
    return array('access searchfilter content');
}

The next step is to add a call to HOOK_db_rewrite_sql() so that we can intercept the search query and add the needed where clause to prevent our selected nodes from appearing in the search results. This function makes sure that we are looking at the right query as well as providing a bypass for users who have the 'access searchfilter content' permission. This means that you can turn the module on and still allow some users to find anything they need to.

function searchfilter_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
    // Users with the correct permissions can search for all content on the site.
    if (!user_access('access searchfilter content')) {
        if ($query == '' && $primary_table == 'n' && $primary_field = 'nid' && empty($args)) {
            $excluded_types = variable_get('searchfilter_types', array());
            if (!empty($excluded_types)) {
                $where = " n.type NOT IN ('" . implode("','", $excluded_types) . "') ";
                return array('where' => $where);
            }
        }
    }
}

In order to allow administrators to pre-select the node types to be excluded a hook is added to alter the search admin form. This adds a select box to the bottom of the form in the administration form that will just list out the node types.

function searchfilter_search($op = 'search') {
	if ('admin' == $op) {
        $form = array();
        $form['searchfilter_types'] = array(
            '#type'          => 'select',
            '#multiple'      => TRUE,
            '#title'                => t('Exclude Node Types'),
            '#default_value' => variable_get('searchfilter_types', array()),
            '#options'       => node_get_types('names'),
            '#size'          => 9,
            '#description'   => t('Node types to exclude from search results.'),
        );
        return $form;
    }
}

The final step is to add an option to the main search form (for users who have the permission) that will allow users to select from every node type available and not just those allowed.

function searchfilter_form_alter(&$form, &$form_state, $form_id) {
    if ('search_form' == $form_id) {
        if (!user_access('access searchfilter content')) {
            $excluded_types = variable_get('searchfilter_types', array());
            $types = array_map('check_plain', node_get_types('names'));
            foreach ($excluded_types as $excluded_type) {
                unset($types[$excluded_type]);
            }
            $form['advanced']['type']['#options'] = $types;
        }
    }
}

Once these two files are in place you will be able to activate the module and add a filter to your search results.

For convenience, here is the fully assembled code.

<?php
// $Id$

/**
 * @file
 */

/**
 * Implementation of HOOK_perm().
 *
 * @return array An array of the permissions for this module.
 */
function searchfilter_perm() {
    return array('access searchfilter content');
}

/**
 * Implementation of HOOK_db_rewrite_sql. Rewrite the search database query and 
 * add in the node types that have been selected.
 *
 * @param string $query         Query to be rewritten.
 * @param string $primary_table Name or alias of the table which has the primary key field for this query. 
 * @param string $primary_field Name of the primary field.
 * @param array  $args          Array of additional arguments.
 * 
 * @return array The addition to the where statement to be used by the search
 *               query.
 */
function searchfilter_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
    // Users with the correct permissions can search for all content on the site.
    if (!user_access('access searchfilter content')) {
        if ($query == '' && $primary_table == 'n' && $primary_field = 'nid' && empty($args)) {
            $excluded_types = variable_get('searchfilter_types', array());
            if (!empty($excluded_types)) {
                $where = " n.type NOT IN ('" . implode("','", $excluded_types) . "') ";
                return array('where' => $where);
            }
        }
    }
}

/**
 * Implementation of HOOK_search, allows the addition of a form component to our
 * search admin interface.
 *
 * @return array The additional form component.
 */
function searchfilter_search($op = 'search') {
	if ('admin' == $op) {
        $form = array();
        $form['searchfilter_types'] = array(
            '#type'          => 'select',
            '#multiple'      => TRUE,
            '#title'         => t('Exclude Node Types'),
            '#default_value' => variable_get('searchfilter_types', array()),
            '#options'       => node_get_types('names'),
            '#size'          => 9,
            '#description'   => t('Node types to exclude from search results.'),
        );
        return $form;
    }
}

/**
 * Implementation of HOOK_form_alter. Alter the search form to restrict the 
 * selectable node types to just the list that has been saved.
 * 
 * @param array  $form       Nested array of form elements that comprise the form.
 * @param array  $form_state A keyed array containing the current state of the form.
 * @param string $form_id    String representing the name of the form itself.
 */
function searchfilter_form_alter(&$form, &$form_state, $form_id) {
    if ('search_form' == $form_id) {
        if (!user_access('access searchfilter content')) {
            $excluded_types = variable_get('searchfilter_types', array());
            $types = array_map('check_plain', node_get_types('names'));
            foreach ($excluded_types as $excluded_type) {
                unset($types[$excluded_type]);
            }
            $form['advanced']['type']['#options'] = $types;
        }
    }
}

 

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
1 + 0 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.