How to Theme the Comment Form in Drupal 7

Posted by Art Williams on May 26, 2011

Theming the comment form is something that most Drupal themers want to do at some point. Based on the popularity of our previous post, How to Theme the Comment Form in Drupal 6, I have decided to revisit this subject for Drupal 7.

Form Theming Basics

The default comment form in D7 is just like D6, contains fields for name, email, homepage, subject, and comment. The email and homepage fields can be turned off in the content type settings. Plus you can add new fields to the comment form and change some of their display options in the content type settings.  But for more advanced theming we have to override the form.

theme-comment-form-drupal7-original.png

In D6 and D7 you can use the hook_form_alter function to make changes to a form before it is rendered, but the issue with this function is that it is called for every form rendered by Drupal. I’m going to suggest that you use hook_form_FORM_ID_alter instead, since it is only called for the specific form with the id of FORM_ID. Plus this function is called last of all the form override functions, so you will know that your changes won’t be undone anywhere else. All you have to do is locate the FORM_ID for the comment form and begin building your function.

Locating the FORM_ID

To find the FORM_ID try firebugging the form and look for the hidden input field with the name=form_id. It looks like this:

<input type="hidden" value="comment_node_article_form" name="form_id">

The part after value= is the FORM_ID.

Many forms have multiple IDs that will work for theming. The comment form is a good example. Each node type has a specific comment FORM_ID that only applies to comment forms on that node type.

For example, the node type ‘article’ would have the FORM_ID of comment_node_article_form, as in the code example above. However the more generic FORM_ID comment_form applies to all comment forms for all content types. (Sorry there isn’t an easy way to find the more generic FORM_ID other than poking around in the Drupal API or making an educated guess.)

I want to override all of the comment forms on my site so I’m going to use the generic FORM_ID comment_form for the rest of this post.

Overriding the Form in template.php

Now combine the parts we’ve gathered into a function in the template.php file in your theme. The resulting function to override the comment form will be: (replace THEMENAME with the name of your theme)

function THEMENAME_form_comment_form_alter(&$form, &$form_state) {
}

All of the modifications to the comment form will go in this function between the brackets { }.

Finding the $form elements

Now that the function is ready to use, it would be helpful to know what the $form looks like with all of its various elements. The easiest way to do this is to Install and activate the devel module. One of the best little functions in this module is the dpm() function which will output the structure of an array or object in an easy to navigate manner.

In your hook_form_comment_form_alter function (above) add the line:

dpm($form);

This code will only work if the devel module is installed.

Now when you load a page on your site containing a comment form you will see this at the top of the page:

theme-comment-form-drupal7-dpm.png

Click on the gray bar that says “Array, x elements” to expand the $form array. These are all of the elements of the comment form.

Now the fun begins. You can move these elements around, assign values, create new one, etc. Some are nested and open up into more levels of elements. Click around and explore.

Aside: For the rest of this post I will reference elements that I want to manipulate, all of which can be found in this array It might help to follow along with the array open.

Form Manipulation

First I want to group some of the fieldsin my comment form into a fieldset. I see that in D7 there is already a grouping called “author” in the array. And it already contains the elements I want to group (name, email, domain), but it isn’t a fieldset. To make it a fieldset you can just give it a #type of fieldset.

$form['author']['#type'] = 'fieldset';

But now there is no label for the fieldset. We can fix that by adding the line:

$form['author']['#title'] = 'Your Information';

And to set the fieldset to not collapsible, add the line:

$form['author']['#collapsible'] = FALSE;

On the other hand, the subject and comment fields are not grouped in the comment form array, so to add a fieldset to them I’m going to need to create a new fieldset, then assign the existing fields to the new fieldset, and finally unset the existing fields. Here is how:

$form['your_comment'] = array(
  '#type' => 'fieldset',
  '#title' => t('Your Comment'),
  '#collapsible' => FALSE,
  '#weight' => 2,
  );

  //Subject
  $form['your_comment']['subject'] = $form['subject'];
  unset($form['subject']);
  $form['your_comment']['subject']['#weight'] = -10;

  //Comment
  $form['your_comment']['comment_body'] = $form['comment_body'];
  unset($form['comment_body']);

Another manipulation is removing a field all together. To accomplish that you set the field equal to NULL. For example to remove the homepage field add the following line to your function:

$form['author']['homepage'] = NULL;

Updated (6/7/2011): As Dan pointed out in the comments, the above line does NOT work in the case of homepage, due to the validation code in the comments module.  Instead of using the above line to remove the homepage field, use the following line to set access to the field as FALSE. This hides the field and prevents user input.

$form['author']['homepage']['#access'] = FALSE;

The final form manipulation that I’m covering in this article is making a field required. In the drupal content type settings you can make all of the contact information required or all of it optional, but there are no options for some of each. We can solve that by making them all optional in the content type settings and adding a line to our override function to make the email address required, like this:

$form['author']['mail'][‘#required’] = TRUE;

The Summary and the Code

There are many more manipulations that can be done to the fields on a form, but that should get you started. The main difference between Drupal 6 and Drupal 7 is that the default $form array is rearranged a bit, so the devel module becomes very important to investigate those changes.

Important Note: Be sure to comment out or delete the "dpm($form);" line once you are finished makeing changes to the comment form.  You should also deactivate the devel module once you are finished development to reduce the overhead.

Here is the entire override function containing all of our changes (replace THEMENAME with your own theme’s name) and a screenshot of the resulting comment form.  Copy and paste this into your template.php file and start theming away on that comment form.

function THEMENAME_form_comment_form_alter(&$form, &$form_state) {
  //dpm($form);  //shows original $form array
  $form['author']['#type'] = 'fieldset';
  $form['author']['#title'] = 'Your Information';
  $form['author']['#collapsible'] = FALSE;

  $form['your_comment'] = array(
    '#type' => 'fieldset',
    '#title' => t('Your Comment'),
    '#collapsible' => FALSE,
    '#weight' => 2,
  );

  //Subject
  $form['your_comment']['subject'] = $form['subject'];
  unset($form['subject']);
  $form['your_comment']['subject']['#weight'] = -10;

  //Comment
  $form['your_comment']['comment_body'] = $form['comment_body'];
  unset($form['comment_body']);

  $form['author']['homepage']['#access'] = FALSE;

  $form['author']['mail']['#required'] = TRUE;

  //dpm($form);  //shows $form array after our changes

}

theme-comment-form-drupal7-result.png

MONTHLY MARKETING INSIGHTS.

Get thought-provoking and actionable insights to improve how your firm makes a connection with your customers.

LEAVE A COMMENT

The content of this field is kept private and will not be shown publicly.

Plain text

  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
Submitted by Benjamin Melançon on Thu, 05/26/2011 - 10:46am

Don't forget that you can add additional fields to comments in D7!

Submitted by Art Williams on Thu, 05/26/2011 - 11:19am

Nice catch, Benjamin! I made the changes to the post to reference those options in D7.

Submitted by David Corbacho on Thu, 05/26/2011 - 12:31pm

I just discovered this blog from Drupal Planet. Nice design, love it.

Submitted by Amy Peveto on Fri, 05/27/2011 - 9:12am

We're glad you like. Take a look around and feel free to subscribe to our RSS feed!

Submitted by Vince on Wed, 06/01/2011 - 10:03am

This is really helpful... thanks. I am just getting into Drupal. A couple of questions...

+ Is there a way to do it wordpress style with a "website" field, and if you enter an address, your name becomes a link to your website in the comment?

+ And I've noticed here in this comment template you've totally removed the subject field, which I like. How did you do that?

+ Does Drupal have a way to subscribe to comments?

Any help is appreciated!

Submitted by Vince on Wed, 06/01/2011 - 10:05am

Also can I ask one more question... did you write a custom module to do the social sharing buttons? I am having a real hard time finding a D7 plugin that does the social buttons with a count.

Submitted by Art Williams on Wed, 06/01/2011 - 10:29am

Vince,

Welcome to Drupal! I'll try to answer each of questions as best I can in the limit space of a comment.

1. If you leave in the website field that is exactly how it works by default. The username links to that value.

2. The same way I removed the homepage value in the example.
$form['subject'] = NULL;

3. I beleive you are looking for the comment notify module. Be careful though since it is currently an alpha version for D7.

4. We are not using a module for the social sharing buttons. We just took the code from each service (i.e. Facebook Like Button) and pasted it into the proper template file (example: node--blog.tpl.php). I will say that it's hard to get all those buggers to line up right since some of them are iframes and they aren't uniform sizes. I'd love to see some standardization of these buttons across services, but that's unlikely.

Submitted by Vince on Wed, 06/01/2011 - 10:41am

Art, thanks. That is helpful. I have a standard install of Drupal and don't have the website field though. Not sure why.

I've been wavering back and forth between Drupal and Wordpress. It seems more difficult to do some basic things in Drupal that Wordpress would easily do, but it seems that in the long run, Drupal is more flexible.

Submitted by Art Williams on Wed, 06/01/2011 - 11:34am

Vince,

Make sure you've allowed Anonymous posters to leave contact info. Also make sure you are viewing the comment form while logged out. It looks difference when a user is logged in.

Find the setting here:
Administration » Structure » Content types » (Your content type) » Comment Settings » Anonymous commenting » Anonymous posters (may not/may/must) leave their contact info.

Submitted by Vince on Wed, 06/01/2011 - 12:15pm

Ah, wow. That is what I was looking for! There are a lot of menus and settings in Drupal.... still getting used to it! I've developed on Joomla for a very long time.

Thanks again, and this is a great article.

Submitted by Art Williams on Wed, 06/01/2011 - 12:17pm

Glad to help!

Submitted by Dan on Mon, 06/06/2011 - 9:32pm

Hello again,

Just a quick note, when using

$form['author']['homepage'] = NULL;

it caused the form validation to throw up some php errors, so instead I used

$form['author']['homepage']['#type'] = 'hidden';

which seemed to work (one php notice appeared, but was never seen again!)

thanks again for the tutorial!

Submitted by Art Williams on Tue, 06/07/2011 - 10:08am

Dan,

Nice Catch. The validation code in the comment.module cannot handle homepage as NULL or unset. I just tried both. This is a unique situation because of the validation code in the module.

But, I don't really like using #type = 'hidden' because a savy user could still insert a value in that field if they wanted. And you can run into problems if the field is both 'hidden' and 'required'. That isn't the case here, but it would be a good practice to set #required = FALSE whenever you set type to hidden.

My preferred solution:

$form['author']['homepage']['#access'] = FALSE;

This both hides the field and prevents any user input.

I will update the post to reflect this change. Thanks again for catching this issue.

Submitted by Dan on Tue, 06/07/2011 - 1:04pm

ah great stuff, will use that instead. Also I was wondering, the comment form you use on this site, when you click submit does it skip validation of the author name and email address due to the use of #value to display 'Your name...' or whatever it was? Ie it validates the text 'Your name' as correct? been trying to do something similar, have resorted to using the 'hint' module which replaces the #title attribute of a field with a 'hint' which then hides when the field gains focus... however I am experience the issue i just mentioned still :S bit of a random comment, sorry

Submitted by Art Williams on Tue, 06/07/2011 - 2:29pm

Dan,

This site is D6, so things work differently than is described in this post. D6 has some strange behaviors that allows us to change the #value in the theme layer and still let the user change those fields. In D7 you would want to use #default_value.

Example:

$form['your_comment']['subject']['#default_value'] = "Enter a subject";

You may want to also check out this resource for other form api references:

https://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html

Submitted by corrie on Sat, 06/18/2011 - 8:45pm

How to remove guidelines and resizable comment textarea

Submitted by Art Williams on Mon, 06/20/2011 - 12:03pm

I'm not sure exactly what you are asking, but I would suggest poking around in the dpm output and finding the form element that you are looking for. Then try changing some values. Once you find the right one, you can report back here and let everyone know.

Submitted by Corrie on Tue, 06/21/2011 - 10:56am

Thanks for the response. Basically I want to remove the guidelines we see right below the comment body. I am unable to figure it out from the array. Drupal is too big, I dont know where to look. I also tried to see everywhere inside the template.php and .tpl.php but unsuccessful. Looks like this is coming from somewhere else and not comment form.

Submitted by Corrie on Tue, 06/21/2011 - 4:50pm

Thank you very much. This solved part of my problem. I could have never figured this out myself

Submitted by jorge mejia on Sat, 07/30/2011 - 11:42am

i have comments open for anonymus users, so i have added an email field. how can i hide this field for registered users? and how about a nice text like the one you have on this form underneath the email field?
Thanks

Submitted by paul on Fri, 08/26/2011 - 11:20am

I'm trying to hide a field in the comments form depending on a value in the node but can't get it to work.

This is what I have:

if ($node['field_yesno'][0]['value'] = 'no') {
$form['field_partner']['#access'] = FALSE;

But it doesn't work,

Any help appreciated!

Thanks.

Submitted by Art Williams on Fri, 08/26/2011 - 11:34am

Paul,

Without seeing all of your code and the comments configuration, I'm just guessing, but I would try to print $node['field_yesno'][0]['value'] just before your if statement to make sure the value is really 'no' as you expect.

-Art

Submitted by makeapage on Sat, 08/27/2011 - 9:43am

Hi there. I'm have some troubles adapting a comment form for my site. In my case i'm forced to use comment forms in panels as my real nodes are pop-up windows.

the comment form gets displayed properly. But here's the catch:
After submitting/editing the user gets redirected to the real node and i'd like them to stay on the panel page!

Is this possible? And in what direction should i look, i'm truely clueless.

Submitted by Art Williams on Mon, 08/29/2011 - 9:05am

makeapage,

If what you are trying to do is possible throught simple comment theming then you'll just need to look through the $form array and see if there are any elements with a path in them.

If not, then you will likely need a custom module built to intercept the form submission and redirect to the panel.

Art

Submitted by Philadelphia W… on Wed, 08/31/2011 - 7:13pm

[...] How to Theme a Comment Form in Drupal 7 | Digett – [...]

Submitted by Testo on Tue, 05/22/2012 - 8:43am

How can i rename the "comment*" field?

$form['your_comment']['comment_body']['#title'] = t('TEST');

i dont find the right way...

Submitted by Frank on Fri, 07/20/2012 - 3:00pm

Hello,

thanks for your work. I have on question. How can I hide the "Your name" field?

Best regards

Submitted by Frank on Thu, 07/26/2012 - 4:24pm

Thanks a lot!..That helps

Best regards
Frank

Submitted by Amy Peveto on Mon, 07/30/2012 - 8:46am

You're welcome, Frank! Glad it helped.

Submitted by nicodv on Sat, 09/01/2012 - 3:44am

Thanks so much, great help.
nico

Submitted by Amy Peveto on Tue, 09/04/2012 - 9:50am

Glad you found it helpful, Nico!

Submitted by Tiago Santos on Sun, 09/09/2012 - 7:29am

Hi there! Does anyone knows how to attach the user picture to comment form like in facebook p.e.?

regards

Submitted by Tiago Santos on Mon, 09/10/2012 - 9:47am

Thanks for the answer JD, but I want the user picture to be loaded in the form comment, beside the comment field. The link you pointed shows the solution to display the picure in the comment itself.

regards

Submitted by Jeff on Mon, 09/10/2012 - 9:08pm

How do you remove a class from the comment form.

This added a class to the preview button:

$form['actions']['submit']['#attributes']['class'][] = 'primary button';

But there was a class on the submit button that is canceling out this 'primary button' class

Submitted by creaux on Sat, 10/06/2012 - 9:54am

I don't much understand how you get this:

function THEMENAME_form_comment_form_alter(&$form, &$form_state) {
}

I'm talking about part of name form_ and _alter.

Can anyone explain me this. Thanks

Submitted by Mikael on Fri, 10/19/2012 - 4:18pm

This is a great start for me... but I'm stuck on how to add a new field.

In particular, where can I find a list of ALL available fields that I can use in comments?

I'd really like to add "user picture" to the left of the subject text (facebook-style)... but I don't know the fieldname of "user picture".

Any help much appreciated!

Kindly,
Mikael

Submitted by Veronica on Tue, 12/18/2012 - 1:04am

Hi

I am at the last stages of cleaning up my first Drupal site and getting to know my way around Drupal. Of all the "help" I've read up on over the last month, this was probably the best I have come across. Also your follow up needs to be complemented on. Well Done!

Submitted by Amy Peveto on Tue, 12/18/2012 - 10:05am

Thank you, Veronica! The Drupal community in general is great at follow-up/responsiveness -- we're just trying to keep up! :)

Glad you found the info helpful. We do our best.

Submitted by Oneng on Sun, 06/02/2013 - 6:29pm

Thanks you)) very useful
But i have question. how to add placeholder to any field in comment-form
I tried this:

function ahb_form_alter(&$form, &$form_state, $form_id){
if($form_id == "comment-form"){
if (isset($form['name'])) {
$form['name']['#attributes']['placeholder'] = t('enter your name');
}
}
}

Submitted by Jonathan Dale on Mon, 06/03/2013 - 9:03am

@Oneng: You will likely want to use hook_form_comment_form_alter instead.

Something like the following should work:

function ahb_form_comment_form_alter(&$form, &$form_state) {
if (isset($form['name'])) {
$form['name']['#attributes']['placeholder'] = t('enter your name');
}
}

Submitted by Oneng on Mon, 06/03/2013 - 9:31am

thanks for reply)
work if:
$form['author']['name']['#attributes']['placeholder'] = t('YOUR NAME');
for mail, name... works fine, but for comment body no:
this for cooment body:
$form['comment_body']['#attributes']['placeholder'] = t('YOUR TEXT');

Submitted by Jonathan Dale on Mon, 06/03/2013 - 11:07am

@Oneng: It looks like comment body is wrapped with other elements and needs some special handling. To determine this, you will need to use dsm or some other method of debugging to view the form array for that field.

In my testing, I found that the proper syntax for comment body is this:

$form['comment_body'][$form['comment_body']['#language']][0]['#attributes']['placeholder'] = t('YOUR TEXT');

Submitted by Oneng on Mon, 06/03/2013 - 11:44am

Thanks you very much! useful site)
PS but need button "to top"

Submitted by Morten Andersen on Wed, 06/05/2013 - 6:59am

Where do you put this placeholder code:

$form['comment_body'][$form['comment_body']['#language']][0]['#attributes']['placeholder'] = t('YOUR TEXT');

in the template.php ?

Submitted by Jonathan Dale on Wed, 06/05/2013 - 9:16am

@Morten:

This would go within your theme template.php or module file and would need to be wrapped in a hook_form_comment_form_alter() function.

For example:

function THEMENAME_form_comment_form_alter(&$form, &$form_state) {
$form['comment_body'][$form['comment_body']['#language']][0]['#attributes']['placeholder'] = t('YOUR TEXT');
}

Submitted by Morten Andersen on Wed, 06/05/2013 - 10:25am

cool :-)

Submitted by Sonya on Sun, 06/16/2013 - 11:50pm

I added in the additional comments box field type field_collection.
But in the form of adding comments no name sub-fields that constitute a field_collection.
You can tell how to add the names of the sub-fields in the form adding comments?

Thank you in advance.