When you first enable the Upload module and start attaching files like PDFs to your nodes, you'll notice that those attachments are displayed in a table at the bottom of the node showing the file name and size of each file attached to the node. This works for most situations, but sometimes you want to make things look just a little bit different.
In today's example we'll re-theme the attachments display to remove this table. In our use case the user will only be attaching one file, a PDF, to each node. Rather than have the PDF's name display in table - they want a simple link with the text "Download the PDF". So how do we make this change?
The answer is a theme override. The default attachments display is provided by theme_upload_attachments(). By overriding this theme function in our site's theme, we can change the behavior however we want. In this tip we'll be learning how to override a theme function using some basic PHP knowledge and a bit of help from the Drupal API site.
Overriding a theme function
The first thing we need to do is get the code for the default theme function. We can do this by going to http://api.drupal.org and punching "attachment" into the search field. We'll see that it lists theme_upload_attachments as an option. Here's the code we'll be starting with:
function theme_upload_attachments($files) { $header = array(t('Attachment'), t('Size')); $rows = array(); foreach ($files as $file) { $file = (object)$file; if ($file->list && empty($file->remove)) { $href = file_create_url($file->filepath); $text = $file->description ? $file->description : $file->filename; $rows[] = array(l($text, $href), format_size($file->filesize)); } } if (count($rows)) { return theme('table', $header, $rows, array('id' => 'attachments')); } }
To get started, we'll copy and paste that code into our template.php file in our theme directory. Now that we have the code there, we'll need to rename the function call. To override a theme function, replace the word theme with either phptemplate or the "machine name" of your theme, eg: framework, zen, etc. The end result will look like this:
function phptemplate_upload_attachments($files) {
Understanding what we're starting with
Now that we've renamed our theme function, we can start changing the rest of the code to get the output we're looking for. To do that, we'll first need to understand what we're looking at. We know the end result of this function is an HTML table that has the header text "Attachment" and "Size". We also know that it outputs a new table row for each attachment, and that contains the attachment's file name or description and the size of the file. From the function itself we see that we're passing the argument "$files", this is an array of the uploaded file data as it relates to each node. This $files array has information like the name of the file, where to find the file in the site's directory structure, and the size of the file. Keeping those things in mind, let's read through the rest of the code and see if we can figure out what's going on.
Looking at the rest of the function we can see that we start off by building a variable that contains the header text for the table, "Attachment" and "Size". Next we create a new array for $rows. The third line in the function starts a foreach() loop, which iterates over each file attached to the node. The rest of the work is done within this loop, as in cases where there's more than one file attached to a node we'd need to make sure we were getting the proper link information for each.
Within the foreach loop, we see that we're setting a few variables. The $href variable is taking information from the file object and passing it through another function, file_create_url(), this is building the path which will be used to link to the file. Next we're putting together the $text portion of the link. The code you see here is first checking to see if the user has typed in a description for the file after uploading it. If they have typed a description, then that's the text we'll use; If not, we'll use the file's name as the text.
Now that we have our $href link and our $text, we can build the table's row for a particular file. This line looks like this:
$rows[] = array(l($text, $href), format_size($file->filesize));
What this means is that we're adding a value to the $rows array we created earlier. This lets us pick up each file attached to the node and add a row that will be output as a table row later on. We see that the contents of each $rows[] is also an array. This array contains the HTML link for the file, and the size of the file. The HTML link is being built by Drupal's l() function which takes our link $text and our $href as arguments - this is the piece we'll need. The final thing the function does is return our work using the theme() function, and specifying the "table" theme.
There are a few conditional (if()) statements in the code as well, those are simply checking to make sure our $file is valid and that we actually created some $rows before we print stuff to the screen - these checks help ensure we aren't dumping out code if the node we're looking at doesn't actually have a file attachment.
Making our changes
Now that we know a little more how the existing function is working, we need to modify it for our use case. We'll leave much of the code alone, but we do want to change the link text and we want to output as a list, not as a table. To do this, we'll need to change how our $text variable is being created, get rid of the $headers variable, get rid of the format_size($file->$filesize) array parameter, and change the theme function we're returning to use "item_list" rather than "table". Those changes make our code look like this:
function phptemplate_upload_attachments($files) { $rows = array(); foreach ($files as $file) { $file = (object)$file; if ($file->list && empty($file->remove)) { $href = file_create_url($file->filepath); $text = "Download the PDF"; $rows[] = array(l($text, $href)); } } if (count($rows)) { return theme('item_list', $rows, NULL, 'ul', array('id' => 'attachments')); } }
So what's the end result of these changes? Our attachment list now looks like this:
Overriding theme functions in Drupal doesn't take much programing knowledge and offers themers a great deal of power over the final rendered page. Using api.drupal.org as a reference can make this process relatively painless.


Comments
Default Theme Implementation documentation (override reference)
If the whole world of the Drupal API seems intimidating as a starting point, I highly recommend reading the Default Theme Implemenation page. http://api.drupal.org/api/group/themeable/6 (this link is to the Drupal 6 tab of this topic).
This topic explains the theme system and how theme overrides work. AND, most helpfully, it provides a list of the themable functions with links to the full entry on each. Both the function Jer explains in this tip and the one (theme_form_element) Maryann asks about on the Labtime list today are listed here for reference.
If you will be adding any theme overrides to your theme or if the idea interests you, this topic page is essential reading and the Drupal API site is an essential reference tool.
Happy theming.
attachments
my God !! I thought my computer and the internet was created to make life easier..
Post new comment