function theme_item_list

You are here

7 theme.inc theme_item_list($variables)
4.6 theme.inc theme_item_list($items = array(), $title = NULL)
4.7 theme.inc theme_item_list($items = array(), $title = NULL, $type = 'ul')
5 theme.inc theme_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = NULL)
6 theme.inc theme_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = NULL)

Returns HTML for a list or nested list of items.

Parameters

$variables: An associative array containing:

  • items: An array of items to be displayed in the list. If an item is a string, then it is used as is. If an item is an array, then the "data" element of the array is used as the contents of the list item. If an item is an array with a "children" element, those children are displayed in a nested list. All other elements are treated as attributes of the list item element.
  • title: The title of the list.
  • type: The type of list to return (e.g. "ul", "ol").
  • attributes: The attributes applied to the list element.

Related topics

28 theme calls to theme_item_list()
aggregator_block_view in modules/aggregator/aggregator.module
Implements hook_block_view().
authorize.php in ./authorize.php
Administrative script for running authorized file operations.
book_render in modules/book/book.pages.inc
Menu callback: Prints a listing of all books.
callback_batch_finished in modules/system/form.api.php
Complete a batch process.
entity_query_access_test_sample_query in modules/simpletest/tests/entity_query_access_test.module
Returns the results from an example EntityFieldQuery.

... See full list

File

includes/theme.inc, line 2082
The theme system, which controls the output of Drupal.

Code

function theme_item_list($variables) {
  $items = $variables['items'];
  $title = $variables['title'];
  $type = $variables['type'];
  $attributes = $variables['attributes'];

  // Only output the list container and title, if there are any list items.
  // Check to see whether the block title exists before adding a header.
  // Empty headers are not semantic and present accessibility challenges.
  $output = '<div class="item-list">';
  if (isset($title) && $title !== '') {
    $output .= '<h3>' . $title . '</h3>';
  }

  if (!empty($items)) {
    $output .= "<$type" . drupal_attributes($attributes) . '>';
    $num_items = count($items);
    $i = 0;
    foreach ($items as $item) {
      $attributes = array();
      $children = array();
      $data = '';
      $i++;
      if (is_array($item)) {
        foreach ($item as $key => $value) {
          if ($key == 'data') {
            $data = $value;
          }
          elseif ($key == 'children') {
            $children = $value;
          }
          else {
            $attributes[$key] = $value;
          }
        }
      }
      else {
        $data = $item;
      }
      if (count($children) > 0) {
        // Render nested list.
        $data .= theme_item_list(array('items' => $children, 'title' => NULL, 'type' => $type, 'attributes' => $attributes));
      }
      if ($i == 1) {
        $attributes['class'][] = 'first';
      }
      if ($i == $num_items) {
        $attributes['class'][] = 'last';
      }
      $output .= '<li' . drupal_attributes($attributes) . '>' . $data . "</li>\n";
    }
    $output .= "</$type>";
  }
  $output .= '</div>';
  return $output;
}

Comments

Why are child lists rendered through the hard-coded theme_item_list() instead of theme('item_list', ...)? Same is true of D6.

thanks.

Cause it is derived to this particular default item_list implementation. So all is OK.

From this, i found how to add attributes to the UL tag, but it's not clear to me how i can add attributes to the LI tags?

Can someone helps?

Hi WilliamB,

In order to add attributes to the li tags, each element in the items array ($variables['items']) must be another (associative) array. For the later, the value of the data key will be treated as the content of the li tag, while any other key (expect for children) will be treated as an attribute to be added (using the key's value as the value for the attribute). Since this might sound confusing, I wrote a simple example...

Let's say you want to print a list of authenticated users. For each of them, you want to print his or her username and add an id attribute with the user's id (uid) to the list item, as well as a class attribute with the roles the user has. Then you would have to do following:

<?php
$title
= t('My custom listing');
$type = 'ul';
// The following attributes apply to the list tag (e.g., <ol> or <ul>)
$attributes = array(
 
'id' => 'my-custom-listing',
 
'class' => 'custom-class another-custom-class', // a string or indexed (string) array with the classes for the list tag
);

$uids = retrieve_uids(); // Replace with your own function

$accounts = array();
foreach (
$uids as $uid) {
 
$accounts[] = user_load($uid);
}

$items = array();
foreach (
$accounts as $account) {
 
$items[] = array(
   
'data' => $account->name,
   
'id' => $account->uid, // be careful not to add another id attribute on the page that might be the same as one of the uids or your page will not validate
   
'class' => array_keys($account->roles), // value for 'class' key MUST be an (indexed) array. Using a string value like '2 3 4' produces an error
 
);
}

theme_item_list(array('items' => $items, 'title' => $title, 'type' => $type, 'attributes' => $attributes));
?>

The preceding code should produce an output similar to:

<div class="item-list">
  <h3>My custom listing</h3>
  <ul id="my-custom-listing" class="custom-class another-custom-class">
    <li id="1" class="2 3 4 first">admin</li>
    <li id="2" class="2 4">john</li>
    <li id="3" class="2 last">doe</li>
  </ul>
</div>

Note that if the function that retrieves the uids returns an empty array, the the resulting html will not have any li element. An if (!empty($uids)) could be used, but that was skipped to keep the example simple. Also, using the array key from $account->roles as classes might not be intuitive (or useful!). The array value might be more useful, but because role names might contain whitespaces, it would require additional processing if you wanted to use them as classes. At least you should replace the whitespaces with dashes.

Hopefully the example clears your doubt. Of course, you can also read the function's implementation to see how it works.

Try this if you don't want to implement retrieve_uids();

<?php
  $items
[] = array(
   
'data' => '1',
   
'class' => array('dummy'=>'category'),
   
'children' => array('1.1','1.2',array('data'=>'1.3','class' => array('dummy'=>'category'),'children'=>array('1.3.1','1.3.2')))
  );
?>

Hello,

I am wondering how to properly generate nested arrays with theme_list_item. Right now I have a nested array where every item has class attributes:

[0] -> [data] = item 1
     -> [class] = level-0
     -> [children] -> [0] -> [data] = item 2
                          -> [class] = level-1
                   -> [1] -> [data] = item 3
                          -> [class] = level-1
[1] -> [data] = item 4
    -> [class] = level-0

The problem here is that the nested ul takes on the classes of the li's that are on the same level. In this case this would give

<ul>
  <li class=level-0>item 1
    <ul class=level-0>
      <li class=level-1>item 2</li>
      <li class=level-1>item 3</li>
    </ul>
  <li class=level-0>item4</li>
</ul>

I do not want my nested ul to have any classes. Is this default behaviour with the theme_list_item function? How do I prevent this?

This can hang you up at times because you need to realize that you need a key called 'items'.

Succinct example:

<?php
  $items
['items'] = array(
   
l('Configure', 'admin/config'),
   
l('Structure', 'admin/structure'),
  );
  return
theme('item_list', $items);
?>

This is because D7 always uses $variables for second parameter of a theme function, where $variables is an array keyed by the names of the variables. This is so they can be overridden in a preprocess function.

Perhaps this makes more sense in the code if you name like so:

<?php
  $items
= array(
   
l('Batch history', 'admin/reports/salesforce/batch'),
   
l('Currently queued items', 'admin/reports/salesforce/current'),
   
l('Retry queue', 'admin/reports/salesforce/retries'),
   
l('Permanent failures', 'admin/reports/salesforce/permanent-failures'),
  );
 
$output .= theme('item_list', array('items' => $items));
?>

Hi,
Im using drupal 7, I would like to know whether i can use the same function to implement multi-level list items. As below:

If possible can anybody help me with an example?

build your list in reverse--start with the inner most and render it into a parent.

but doesn't this bring in a div wrapper for the sub-UL? I am trying to use the theme function, but it makes html super messy for things like Suckerfish/superfish dropdown menus.

This comment has some code that would work for you
http://api.drupal.org/api/drupal/includes--theme.inc/function/theme_item...

On D7, to use attributes on li elements you have to use attributes array instead "class" or "id" directly. Rather, you will get a fatal error.

I personally do not like the wrapper <div class="item-list"></div> being hard-coded. There are contexts where such a wrapper might be not desired, such as when you want to generate markup appropriate for JavaScript/jQuery plugins. All you can do now is act globally, but this can have undesired effect as well.
Therefore I would either vote for providing an additional argument to the function to control that, or provide an additional info into the $variables array supplied to the THEME_item_list which would tell me more about the context of the display.
If developers agree upon that, please try to apply such a patch to D7.x release.

I think this functionality could be a great improvement. The class item-list seems to be quite generic for a wrapper class. I can see use case where it would be good to have something more specific to target the pager wrapper or something like that.

I wanted to have the option of adding a unique id to the wrapper. Here's how I solved it by overriding theme_item_list() in my theme's template.php.

Look for comments starting with KM: for explanation. I'm not sure this is the best way to do it, but it works nicely.

<?php
function MYTHEME_item_list($variables) {
 
$items = $variables['items'];
 
$title = $variables['title'];
 
$type = $variables['type'];
 
$attributes = $variables['attributes'];
 
// KM: Check for an item in the $variables array called 'container_id'
  // KM: If not found, default to a blank string.
 
$container_id = isset($variables['container_id']) ? ' id="' . $variables['container_id'] . '"' : '';

 

// Only output the list container and title, if there are any list items.
  // Check to see whether the block title exists before adding a header.
  // Empty headers are not semantic and present accessibility challenges.
  // KM: Add the container_id attribute to the list element container
 
$output = '<div class="item-list"' . $container_id . '>';
  if (isset(
$title) && $title !== '') {
   
$output .= '<h3>' . $title . '</h3>';
  }

  if (!empty(

$items)) {
   
$output .= "<$type" . drupal_attributes($attributes) . '>';
   
$num_items = count($items);
    foreach (
$items as $i => $item) {
     
$attributes = array();
     
$children = array();
     
$data = '';
      if (
is_array($item)) {
        foreach (
$item as $key => $value) {
          if (
$key == 'data') {
           
$data = $value;
          }
          elseif (
$key == 'children') {
           
$children = $value;
          }
          else {
           
$attributes[$key] = $value;
          }
        }
      }
      else {
       
$data = $item;
      }
      if (
count($children) > 0) {
       
// Render nested list.
       
$data .= theme_item_list(array('items' => $children, 'title' => NULL, 'type' => $type, 'attributes' => $attributes));
      }
      if (
$i == 0) {
       
$attributes['class'][] = 'first';
      }
      if (
$i == $num_items - 1) {
       
$attributes['class'][] = 'last';
      }
     
$output .= '<li' . drupal_attributes($attributes) . '>' . $data . "</li>\n";
    }
   
$output .= "</$type>";
  }
 
$output .= '</div>';
  return
$output;
}
?>

I use it like this:

<?php
$output
.= theme('item_list', array(
   
'items' => $scopeList,
   
'title' => $scopeName,
   
'type' => 'ul',
   
'attributes' => array('id' => 'scope-list'),
   
'container_id' => 'scope-list-wrapper',
    )
  );
?>

Here's the output:

<div class="item-list" id="type-list-wrapper">
  <h3>Type:</h3>
  <ul id="type-list">
    <li class="first"><a href="/projects">All</a></li>
    <li><a href="/projects/residential/">Residential</a></li>
    <li class="last"><a href="/projects/commercial/" class="active">Commercial</a></li>
  </ul>
</div>

I hope that helps, I'm sure you could use the same technique of passing additional items to the $variables argument of your overridden theme function to determine what type of wrapper to use, whether to use one at all, etc.

I think a much better approach would be to set an attributes array instrad of just an id value, like so:

<?php
function MYTHEME_item_list($variables) {
 
$items = $variables['items'];
 
$title = $variables['title'];
 
$type = $variables['type'];
 
$attributes = $variables['attributes'];

 

$wrapper_attributes = $variables['wrapper_attributes'];

  if ( !isset(

$wrapper_attributes['class']) ) {
   
$wrapper_attributes['class'] = array('item-list');
  }

 

// Use drupal attributes function to convert an array into HTML attributes
 
$output = '<div' . drupal_attributes($wrapper_attributes) . '>';
  if (isset(
$title) && $title !== '') {
   
$output .= '<h3>' . $title . '</h3>';
  }

  if (!empty(

$items)) {
   
$output .= "<$type" . drupal_attributes($attributes) . '>';
   
$num_items = count($items);
   
$i = 0;
    foreach (
$items as $item) {
     
$attributes = array();
     
$children = array();
     
$data = '';
     
$i++;
      if (
is_array($item)) {
        foreach (
$item as $key => $value) {
          if (
$key == 'data') {
           
$data = $value;
          }
          elseif (
$key == 'children') {
           
$children = $value;
          }
          else {
           
$attributes[$key] = $value;
          }
        }
      }
      else {
       
$data = $item;
      }
      if (
count($children) > 0) {
       
// Render nested list.
       
$data .= theme_item_list(array('items' => $children, 'title' => NULL, 'type' => $type, 'attributes' => $attributes));
      }
      if (
$i == 1) {
       
$attributes['class'][] = 'first';
      }
      if (
$i == $num_items) {
       
$attributes['class'][] = 'last';
      }
     
$output .= '<li' . drupal_attributes($attributes) . '>' . $data . "</li>\n";
    }
   
$output .= "</$type>";
  }
 
$output .= '</div>';
  return
$output;
}
?>

Then, when you would like to add attributes like class, id, aria, data or anything else, you just have to do:

<?php
return theme('item_list', array(
 
'items' => $items,
 
'attributes' => array('class' => array('pager', 'pagination')),
 
'wrapper_attributes' => array('id' => 'pagination-wrapper', 'class' => array('class1', 'class2')),
));
?>

Thank you so much. Exactly what I needed to change pagination theming in a bootstrap based theme. (y)

How to pass an array of nodes to the theme_item_list ? I need to display 4 nodes which are being fetched from a while loop. But the $items array displays only the last node id and ignores others. Can anyone help me pls.