Theming Drupal Comments, Exemplifying with Garland
Part 1 - enhancing the comment layout
When browsing the drupal showcase forum I notice that few people take the effort the theme the comments, which is strange because comments are not only a very popular feature, but also exceedingly easy to theme!. For this comment theming tutorial we're going to spice up the comment template of the default Garland theme with some additional styling and a date widget just like the one in my latest free drupal theme Delicious Fruit.
Before starting with this tutorial, open up the garland theme folder and open the comments.tpl.php file. Our first step, is checking out what variables are natively available in this theme file, we're doing this by using the awesome print_r function. The print_r function prints out all the contents of an array in a nice layout. Past the following code in your comment.tpl.php file, right before the very last </div> tag:
<pre style=”margin:1em;background:#lightgreen;border:1px solid #666;”> <?php print_r($comment) ?> </pre>
Now upload your modified comment.tpl.php file to the themes/garland directory on your webserver, and observe a content item with a comment on your site (if necessary, post a new comment first, lol). In this block with available variables, these are the ones that interest us most in the context of this tutorial:
- Timestamp (creation date)
- Name (author name)
- Uid (user id)
- Picture
ps, if you want to use user pictures, don't forget to enable userpics in admin->user->setting, and enable userpics for comments in admin->themes->build->themes->[tab]Configure. You can upload your userpic at yourdrupalsite.com/user/1/edit, if you are logged in as admin (user 1).
Now we will rearrange some tags, so that the browsers will render their positions the way we want. We're moving the user picture, the submitted information and the links into the div.content element. We're creating a new container called meta, to house our date, comment title and the ‘new' thingy that marks new comments.
In order to create our nifty date widget, we need to use the php date function to print human-readable information from the linux-timestamp that drupal provides us with. Check out the php manual page about date to learn how to modify the date formatting to your liking.
Put the following code into your comment.tpl.php file, replacing all content that was previously there.
<div class="comment<?php print ($comment->new) ? ' comment-new' : ''; print ($comment->status == COMMENT_NOT_PUBLISHED) ? ' comment-unpublished' : ''; print ' '. $zebra; ?>"> <div class="clear-block"> <div class="meta"> <?php if ($submitted): ?> <span class="submitted"> <span class="month"><?php echo date("M",$comment->timestamp); ?></span> <span class="day"><?php echo date("d",$comment->timestamp); ?></span> <?php if ($comment->new) : ?> <a id="new"></a> <span class="new"><?php print drupal_ucfirst($new) ?></span> <?php endif; ?> </span> <?php endif; ?> <h3><?php print $title ?></h3> </div> <div class="content"> <?php print $picture ?> <?php print $content ?> <?php if ($links): ?> <div class="links"><?php print $links ?></div> <?php endif; ?> <?php if ($submitted): ?> <span class="author"><?php print $submitted ?></span> <?php endif; ?> </div> </div> <pre style="display:none;margin:1em;background:lightgreen;border:1px solid #666;font:12px/1.2em arial,verdana;"> <?php print_r($comment) ?> </pre> </div>
Now we need to add some style to this new layout, this is not a CSS tutorial so I will only give a brief explanation (see code annotation for more info):
- All content here is floated, except for the ‘new' marker because it was giving layout problems in ie7. I therefore took it out of the layout flow by positioning it absolutely.
- The comment box is completely scalable, it won't break with different fontsize settings
- Place this code at the bottom of the Garland style.css, or even better, below the native garland comment styling, search for this line to find it .node .content, .comment .content {
/*** Custom Comment Styling ***/ #comments div.comment { border:none; } #comments div.comment .content { border-bottom:1px solid #999; float:left; } #comments div.comment { position:relative; } #comments div.comment h3 { float:left; clear:none; } #comments div.comment span.new { float:right; clear:none; } #comments div.meta { float:left; width:100%; position:relative; /*we're using this to absolutely position the 'new' flag for new comments because it was causing layout problems in ie7 as a floated or static element*/ /* To spare load time (and our time!) we use existing background images from garland theme for styling. This will also make sure that styling will adapt to color settings from color.module */ background:url(http://www.clearwind.nl/cwlabs/drupal-five/themes/garland/images/bg-content.png) 0 -43px repeat-x; border-top:1px solid #999; } #comments .comment span.submitted { float:left; clear:none; background:url(http://www.clearwind.nl/cwlabs/drupal-five/themes/garland/images/body.png) 0 -115px repeat-x; padding:8px 0 3px 0; /* below style makes all browsers center text vertically */ line-height:1.1em; width:3.5em; text-align:center; border-right:2px solid #fff; } #comments .comment .meta span.submitted { font-weight:bold; } #comments .comment span.submitted .month { color:#222; } #comments .comment span.submitted .day { color:#444; clear:both; } #comments .comment span.submitted .new { position:absolute; top:3px; right:3px; } #comments .comment span.submitted #new { display:none; } #comments .comment .meta h3 { line-height:1.7em; text-indent:0.2em; font-weight:normal; font-style:italic; font-size:1.6em; } #comments .comment .picture { margin-top:5px; } #comments .comment div.links { float:left; clear:left; } #comments .comment div.links a { font-weight:bold; font-size:90%; } #comments .comment span.author { float:right; color:#777; font-size:80%; }
Part 2 - Single out comments based on their author
In this part of the tutorial we will use data about our users, to add things to our comments. As a starter, we're going to add a feature to our comments that will allow our comment posters to quickly spot their own comments on a page with many comments. This is very helpful when you are checking a blog page to see if someone has replied to your comment. For this feature we want the user to be logged in, so that the information of his identity resides in the Globals object. Our first step is to construct a way to see if there is a user logged in, and subsequently we will check if the comment that is currently being processed through comment.tpl.php belongs to our user;
if (($GLOBALS['user']->uid != 0) AND ($GLOBALS['user']->uid == $comment->uid)) {print ' mycomment';}
We can add this code to the class of our comment, thereby adding a mycomment class to the comment that is to be styled. Before we go into that part, we're going to add a second feature. This time we're going to make the styling of comments by our administrator stand out. For this feature we're going to carry out another if test:
if ($comment->uid == 1) {print ' admin';}
Wasn't that easy? This piece of code adds a class called admin to our comment, thereby allowing us to add CSS styles that target only comments by our administrator. In drupal, the administrator is always user 1, hence the uid==1 part.
Our 2 php snippets will be inserted into our standard garland div.comment class attribute, as such:
<div class="comment<?php if (($GLOBALS['user']->uid == $comment->uid) AND ($GLOBALS['user']->uid != 0)) {print ' mycomment';} if ($comment->uid == 1) {print ' admin';} print ($comment->new) ? ' comment-new' : ''; print ($comment->status == COMMENT_NOT_PUBLISHED) ? ' comment-unpublished' : ''; print ' '. $zebra; ?>">
Now they are ready to be styled, to wrap it up we will add some more style rules below our initial comment CSS code:
/* Recognised-user comments */ #comments div.comment.mycomment .meta { border-top:3px solid #00AA00; } #comments div.comment.admin .meta { border-top:3px solid #000; }
If you have applied this code to your site, and you see admin comments with thick borders on top, gud job! If you're logged in as admin you will not see comments highlighted by the mycomment styling because that style rule is overridden by the admin styling. In order to test out the mycomment styling you must log in with another username and view a comment posted by that user.
Now, with this newly gained knowledge, you could call it a day and be happy with yourself. However, if you're not exhausted yet, keep reading. For our next (and final) feature, we're going to turn on expert mode for just a bit. If you are terrified of doing some php with a SQL query, then I advise you to avert your gaze! May you choose to face this code like a man (or a webchick!), you will learn a drupal trick that may help you solve complex problems in the future.
Our next trick is to test if a comment is posted by a user who belongs to a specific role. Unfortunately, our $comment object does not tell us about user roles, which is why we are going to do a check inside our database to see if we can find our $comment-uid user in our users_roles table. This feature can be exceptionally useful in our drupal forums. Typically, when your forums grow larger, you will find that you need help to moderate your forums with users who our upgraded to a special moderator role. With styling you can make moderator forum posts look different, which will make your moderators post more visible and credible.
The following code will have to go at the very top of our comment.tpl.php file:
<?php $sql = "SELECT users_roles.rid FROM {users_roles} WHERE users_roles.uid = $comment->uid"; $result = db_query($sql); while ($data = db_fetch_object($result)) { $role = $data->rid; } ?>
If you find it hard to read, copy this code into an editor that colorizes programming code, such as HTML-Kit. The first line of our code constructs the SQL query that we will use, it selects only the rid (role id) value from the users_roles table, from the table row that matches our user (users_roles.uid = $comment->uid). You may see some code snippets where the sql query goes directly into the $result = db_query() part but that method would not allow us to add variables to the query. The code that follows loads the query result into our new variable called $role.
The role variable contains the role id of our user. Role 0 is anonymous, role 1 is any authenticated user, so if you have created one additional role this will be rid 3. As you might have guessed, our next step is to construct a test that checks if the current user in comment.tpl.php belongs to role #3:
if ($role == 3) {print ' moderator';}
We are also going to add a text string to our metadata header, add the following code right before the <h3><?php print $title ?></h3> part:
<?php if ($comment->uid == 1) {print '<span class="user">admin</span>';} ?> <?php if ($role == 3) {print '<span class="user">moderator</span>';} ?>
And add the following css styles after our other comment styling:
#comments div.comment.moderator .meta { border-top:3px solid silver; } #comments .comment .meta span.user { position:absolute; bottom:3px; right:3px; font-size:80%; font-weight:bold; }
And that's a wrap! Now we have garland comments that do not only look much cooler, but are also much more informational. You can find the style.css and comment.tpl.php file with all the code in it below.