Tables in Drupal Part 2: Theme your Table

Last time we covered how to create a nice paged, sortable Drupal table with a selection of simple code snippets.

I don't know about you, but I hate repeating myself in my code. Tables are the kind of thing you need in nearly every module to keep track of the data you have added, so rewriting the same code can get very tedious very quickly.

Well, now you don't have to do that again! Enter the Tables module, which allows you create a table very few lines of code!

How does it work?

It works by implementing a hook called hook_theme, Drupal's built in theme function. You simply call the theme function, tell it you want to create a pager table, and away you go!

Is That it?

Essentially, Yes! But what fun is a module without some customization? The basic implementation does not do a great job of formatting your data. This is why I have provided you with two callbacks; one gets called during the data retrieval loop (when your data gets pulled out of the database, and one to generate the options for each table row. With these two functions, you can create an infinitely customizable table, with very few lines of code, and without having to set up all the code for the table itself!

How does it work?

Here's an example of the what you need to put in your code to make this work:

  1. print theme('pager_table','SELECT nid FROM {node_revisions}', 5, $headers );

This line will provide you with a paged, sortable table containing all the nodes in your site.

Here, we pass in the type of element we want themed, (in this case, it's the 'pager_table'), the SQL to execute, (could by anything, but allows you to customize what you get), the number of rows you see per page, the headers to sort by. There are no callbacks here, use this implementation if you simply want to display data.

How do I add callbacks?

The callbacks are passed as the fifth and sixth parameters, for the retrieval loop and the options builder respectively.

Examples

1: A basic retrieval loop callback

Here's a pointless example to demonstrate how to use a callback function.

This example simply unsets the row you retrieved from the database.

  1. //set up your headers
  2. $headers = array(
  3.         array(
  4.                 'data' => t('Node ID'),
  5.                 'field' => 'nid',
  6.                 'sort'=> 'desc'
  7.         ),
  8.         array(
  9.                 'data' => t('Title'),
  10.                 'field' => 'title',
  11.                 'sort'=> 'asc'
  12.         ),
  13. );
  14.  
  15. //define your callback function
  16. /*
  17.  * Paramaeters are:
  18.  * $data_array - the array to add the processed data to.
  19.  * $counter - the number of the current row
  20.  * $row_data - the current row (returned from db_fetch_array)
  21.  * $options_callback - the Callback to generate the options for this row
  22.  */
  23.  
  24.  function remove_id(&$data_array, $counter, $row_data, $options_callback = NULL){
  25.         $data_array[$counter]['id'] = $row_data['nid'];
  26.         $data_array[$counter]['title'] = $row_data['title'];
  27. }
  28.  
  29. //call the function, but this time with the name of your retrieval loop callback function              
  30. print theme(
  31.         'pager_table',
  32.         'SELECT nid, title FROM {node_revisions}',
  33.         5,
  34.         $headers,
  35.         'remove_id'
  36. );

In this example, first we set up the headers, then we define the callback function to be used in the data retrieval loop. Next we call the theme function, passing the name of the callback as a string. Simple!

2: Using both callbacks

In this example, we will create a link to edit each node.

  1. //set up your headers
  2. $headers = array(
  3.         array(
  4.                 'data' => t('Node ID'),
  5.                 'field' => 'nid',
  6.                 'sort'=> 'desc'
  7.         ),
  8.         array(
  9.                 'data' => t('Title'),
  10.                 'field' => 'title',
  11.                 'sort'=> 'asc'
  12.         ),
  13.         'options' // notice we only pass options as a string because we don't need to do any kind of sorting on this column.
  14. );
  15.  
  16. //define your callback function
  17. /*
  18.  * This time we pass in the options callback function name as a string.
  19.  */
  20.  
  21.  function remove_id(&$data_array, $counter, $row_data, $options_callback){
  22.         $data_array[$counter]['id'] = $row_data['nid'];
  23.         $data_array[$counter]['title'] = $row_data['title'];
  24.         $data_array[$counter]['options'] = $options_callback($row_data, $counter);
  25. }
  26.  
  27. /*
  28.  * Define your options callback
  29.  * This gets called form within the data retrieval loop callback, so you can pass any
  30.  * parameters available in that function into this callback.
  31.  * A good choice is the current row data, so you can construct
  32.  * a selection of links based on the data in the current row.
  33.  * In this example we add a link to edit each node.
  34.  */
  35.  function opts($row, $c){
  36.         return l(t('Edit'),'node/'.$row['nid'].'/edit' );
  37.  }
  38.  
  39.  
  40. //call the function, but this time with the name of your options callback function             
  41. print theme(
  42.         'pager_table',
  43.         'SELECT nid, title FROM {node_revisions}',
  44.         5,
  45.         $headers,
  46.         'remove_id',
  47.         'opts'
  48. );

All we have changed is the use of the final parameter, the options callback function.

This ic called within the data retrieval loop, if you decide to use one. You have complete control here; you can add any parameters you want or need.

I add the row varaible, because I want to build a link based in the node id of each element.

All I do in the callback is use the l() function to create a link based on the current node id, and return it. Simple.

What else do I need to know?

You need to know how to structure the array of headers to pass in. Without the correct structure, the table sorting will not apply.

In the above example, the headers look like this:

  1. $headers = array(
  2.         array(
  3.                 'data' => t('Node ID'),
  4.                 'field' => 'nid',
  5.                 'sort'=> 'desc'
  6.         )
  7. );

You need an array like normal, but for each header, you need another array containing the parameters for the tablesort.

  • Data - The actual text to display
  • Field - The name of the database field to sort the table by
  • Sort - The default order to sort by

With this structure, you can make your table sortable by multiple columns. Simply duplicate this structure for each header.

Remember - you need only add the data parameter as a string if you don't want to sort by this column.

Where can I get this code?

You can download the code here. It comes bundled with a selection of example callback functions to get you started.

Any suggestions?

If you have any suggestions for features, get in touch! Drop me an email or leave a comment.

Support?

If I can help with support I will. Drop me an email and we'll talk.

Enjoy! Hope you find it useful!

Anonymous
Mr.Dijj here, nice looking site. The tables code looks rather familiar to oneself rather like looking at something I myself may have possibly tomed in recent weeks for OUR current employer or have I got it wrong. ;)
Submitted by Anonymous on Wed, 07/08/2009 - 12:12.
lev
I had the idea of writing this around the time you wrote your code, but this is an expanded version of what you came up with, allowing for extra callbacks. It looks similar becasue this is a good way of writing the code! Now get back to work! lol
Submitted by lev on Wed, 07/08/2009 - 14:41.
Anonymous
Is it time for lunch yet ? LOL
Submitted by Anonymous on Fri, 07/10/2009 - 12:55.

Post new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
Are you human? Prove it by typing in the two words below.
Top