Creating a Canned Search With Views Exposed Filters

A client recently had a requirement for what we call a canned search.  A canned search is simply a saved search with specific criteria that can be accessed directly at a URL.  This allows content editors to easily generate a list of various types of content suited to a specific topic without having to specifically link the items together in another manner.

A client recently had a requirement for what we call a canned search.  A canned search is simply a saved search with specific criteria that can be accessed directly at a URL.  This allows content editors to easily generate a list of various types of content suited to a specific topic without having to specifically link the items together in another manner.

As you might have guessed, Views is the primary engine for this feature.  However, it also uses a couple of other capabilities of Views that demonstrates another side to its already amazing flexibility.   Exposed filters is a well-known feature of Views allows a user to modify search criteria on the fly so that everything does not have to be determined ahead of time when the view is created, but one other less well-known feature is the ability to display those exposed filters separately in a block.  These are the primary builing blocks of our canned search feature.

Create the View

The first step is to create a view with exposed filters.  Select the fields you want to display and then in the Filters section, select the filters you want to expose to your users.  In order for them to be available, you need to expose them.  This is done by clicking on the Expose button at the right when adding the filter.

For added flexibility, you can unlock the operators for a field.  This allows the user to narrow down the results even more.  For instance, with a Node: Type filter and a multi-select field, the user could specify only one type, multiple types, or even every type except a specific one.

If you have done all this in the defaults, you will want to create a display.  For this example, I am using a Page view.  In the Basic Settings for the display, there is a setting entitled Exposed form in block.  The default value is No, so click on the No link and change it to Yes.  It should look like this when you're done:

Also, a Page display requires a path, so be sure to set one.  I set mine to canned_search (i.e. mysite.com/canned_search).

Configuring the Block

Now you need to configure your block containing the exposed filters to display.  Navigate to your Block Admin page (admin/build/blocks).  Your block name will be a combination of the view name and the machine name for the display.  To determine the display name, hover your mouse over the display name tab on the left on the views admin page and note the link.  The display name will be whatever is after the last dash at the end of the URL.  For instance, in my view named canned_search, the link I see is

<span class="sy0">/</span>admin<span class="sy0">/</span>build<span class="sy0">/</span>views<span class="sy0">/</span>edit<span class="sy0">/</span>canned_search<span class="co2">#views-tab-page_2</span>

so the machine name for my view is page_2.  This makes my block name canned_search-page_2.  In the block listing, this name is prefixed with Exposed form:, so the full block name in the block listing is Exposed form: canned_search-page_2.

Once the block has been enabled (I put mine in the right sidebar), you can configure where you want it to appear.  Since I set the path for the display to canned_search, I am going to set this block to appear only on that page.  This is done by clicking on the configure link for the block, and in the Page specific visibility settings, selecting the Show on only the listed pages button, and entering canned_search in the Pages textarea.

Now, when you navigate to /canned_search, you will see your block displayed on the right side.  Select your filter values, click on the Apply button, and you will see your search results displayed in the page.  You can then copy the URL and use it as a menu item or a link in another piece of content as a way to link directly to this listing of content.

Bonus: Limiting The Number of Items

One thing that is not possible with this setup so far is the ability to specify the number of items that are returned in the search.  The Items to Display setting is part of the Basic Settings, so it must be set in the view itself and isn't available as an option when the exposed filters are applied.  However, with a little bit of code fu, this setting can be made available with the other exposed filters.

The thing that makes this all possible is that the exposed filters block is a form.  This means that we can alter it with hook_form_alter() and add our number of items field to it.

function mymodule_form_alter(&amp;$form, $form_state, $form_id) {
  switch ($form_id) {
    case 'views_exposed_form':
      if ($form['#id'] == 'views-exposed-form-canned-search-page-2') {
        $form['num_items']['#type'] = 'select';
        $form['num_items']['#title'] = 'Number of items to return';
        $form['num_items']['#default_value'] = 100;
        $form['num_items']['#options'] = _canned_search_num_items();
        $form['num_items']['#weight'] = -10;
      break;
  }
}

And a helper function to fill the select list:

function _canned_search_num_items() {
  $options = array();
  for ($i = 1; $i &lt;= 250; $i++) {
    $options[$i] = $i;
  }
  return $options;
}

Now that the field has been added to the form, we need to insert that value into the view so it can be made part of the query.  Views makes it easy for us in that it automatically adds the parameter to the URL, so it is available in the $_GET array.  The parameter is inserted into the view in the hook_views_pre-execute() hook:

function mymodule_views_pre_execute(&amp;$view) {
  if ($view-&gt;name == 'canned_search') {
    $view-&gt;set_items_per_page($_GET['num_items']);
  }
}

Voila!  Now you can limit the number of items returned in the canned search, and it can be set at runtime.

Thanks to Robert Douglass and Earl Miles for their help in creating this feature.

sedwards