Drupal Painkillers: A-Z filter in Drpual 6 and Views

drupal_az_filter.pngToday I came across an interesting issue in Drupal and I wanted to share with you in case you'll ever have to deal with the same problem. I was going to create an index/glossary for some website using Views in Drupal 6. The index itself could be defined as follows:

  • It is a paged list of nodes of a given type (eg. index_item).
  • The list will be sorted alphabetically.
  • There will also be an exposed filter to allow us to filter the nodes by the first letter in their title (ie. a clickable alphabet from A to Z).

Creating a view

The first two features are very easy to implement, so I will describe them only briefly:

  1. Create a new Node view and call it eg. index.
  2. Add a new display (I chose page) and configure it (add a pager, URL path, menu entry and other details), add at least a Node title field.
  3. Set Sort criteria to sort by Node title ASC.
  4. Restrict the display to show Nodes of type index_item only - there is a Node type filter for that.

Your view is almost ready. To be able to filter the nodes by the first letter in their title, you still need to improve it a little by adding an argument:

  1. Add a Node title argument to the view display.
  2. Configure the argument in a following way:
    • Action to take if argument is not present: Display all values
    • Wildcard: all
    • Glossary mode: true
    • Glossary mode character limit: 1

Now if you save the view, you should be able to display the nodes according to the given argument. You can navigate to your view page and add eg. '/a' to the end of the page URL to show only nodes which have titles starting with the letter 'a'.

You can now create a menu for the whole alphabet to finish the job.

So what's the catch?

BUT what if some of your nodes are called like "1. Drupal article" - you would have to add another 10 items to the menu for each number from 0 to 9 - and that's certainly not what you want. It would be much better, if you could add just one 0-9 option (showing all nodes starting with a number).


There is a neat sollution for that - create a Drupal module which would allow you to:

  1. Create a themeable A-Z filter (so you don't have to create a menu for that)
  2. Alter the view query (in order to support 0-9 option)

Creating a module

  1. Create a new module, call it eg. mymodule (I suppose you are familiar with that, see Module developer's guide otherwise).
  2. Add a hook_theme function to your module:
     * Implementation of hook_theme().
    function mymodule_theme() {
        $items = array();
        $items['az_filter'] = array(
            'arguments' => array(),
            'function' => 'mymodule_az_filter',
        return $items;
  3. Create a theme function for the A-Z filter:
    function mymodule_az_filter() {
      $terms = array('0-9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'CH', 'I', 'J', 
                      'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 
                      'W', 'X', 'Y', 'Z', 'All');
      foreach($terms as $term) {
        $class = (arg(1) == strtolower($term) ? 'active' : '');
        $link = l(t($term), arg(0).'/'.strtolower($term));
        $rows[] = array('data' => $link);
      return theme('item_list', $rows, NULL, 'ul', array('class' => 'az-filter'));
  4. Add a hook_views_query_alter function that will to handle 0-9 option:
      * Implementation of hook_views_query_alter().
    function mymodule_views_query_alter(&$view, &$query) {
        // Specific view only (change following 2 lines according to your needs)
        $view_name = 'index';
        $display_name = 'page_1';
        if ($view->name == $view_name && $view->current_display == $display_name) {
            // Obtain array indexes for both the clause and the argument
            $where_key = array_search("SUBSTR(node.title, 1, 1) = '%s'", 
            $arg_key = array_search("0-9", $query->where[0]['args']);
            if ($where_key !== FALSE && $arg_key !== FALSE) {
                // Use REGEXP to is_numeric test
                $query->where[0]['clauses'][$where_key] = 
                    "SUBSTR(node.title, 1, 1) REGEXP ('[0-9]')";
                // unset the argument since we are not using it
                // reindex the arguments array
                $query->where[0]['args'] = 
  5. After you've activated your new module, you must add a following PHP line to the template with the view or put it in a PHP input block:
    print theme('az_filter');

This will render the A-Z filter itself. Now you have a working A-Z filter with 0-9 option support. Note that I also added an 'All' option to the filter, which would make the view display all the nodes regardless of the first letter in their title.


hey, thanks for sharing this. I want to create only alphabetical filter for view of users. will surely try this.