How to Theme the Comment Form in Drupal 7

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

Comments

Don't forget that you can add

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

Nice catch, Benjamin! I made

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

I just discovered this blog

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

We're glad you like. Take a

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

This is really helpful...

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!

Also can I ask one more

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.

Vince, Welcome to Drupal!

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.

Art, thanks. That is helpful.

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.

Vince, Make sure you've

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.

Ah, wow. That is what I was

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.

Glad to help!

Glad to help!

Hello again, Just a quick

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!

Dan, Nice Catch. The

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.

ah great stuff, will use that

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

Dan, This site is D6, so

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

How to remove guidelines and

How to remove guidelines and resizable comment textarea

I'm not sure exactly what you

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.

Thanks for the response.

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.

Corrie, Try

Thank you very much. This

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

i have comments open for

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

I'm trying to hide a field in

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.

Paul, Without seeing all of

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

Hi there. I'm have some

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.

makeapage, If what you are

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

Pingback

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

How can i rename the

How can i rename the "comment*" field?

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

i dont find the right way...

Hello, thanks for your work.

Hello,

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

Best regards

@Frank: This may help:

@Frank: This may help: http://drupal.org/node/368776

Thanks a lot!..That

Thanks a lot!..That helps

Best regards
Frank

You're welcome, Frank! Glad

You're welcome, Frank! Glad it helped.

Thanks so much, great

Thanks so much, great help.
nico

Glad you found it helpful,

Glad you found it helpful, Nico!

Hi there! Does anyone knows

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

regards

@Tiago, try this link

@Tiago, try this link http://drupal.org/node/22271

Thanks for the answer JD, but

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

How do you remove a class

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

I don't much understand how

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

This is a great start for

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

Hi I am at the last stages of

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!

Thank you, Veronica! The

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.

Thanks you)) very useful But

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');
}
}
}

@Oneng: You will likely want

@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');
}
}

thanks for reply) work

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');

@Oneng: It looks like comment

@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');

Thanks you very much! useful

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

Where do you put this

Where do you put this placeholder code:

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

in the template.php ?

@Morten: This would go within

@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');
}

cool :-)

cool :-)

I added in the additional

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.