In past versions of WordPress, theme developers had to create all the HTML for handling comment forms. While this wasn’t a tough task, it was a stiff and inflexible system that didn’t offer a lot in the way of innovation. Plus, plugin authors only had a single hook to work with, so potentially awesome comment plugins were not something easily built without having users manually input code.
With the addition of the comment meta table in WordPress 2.9, the problem became even more apparent. What good was comment meta if plugin authors had no way to take advantage of it?
WordPress 3.0 introduced a new function for handling comment forms: comment_form(). Theme developers, listen up. If your theme isn’t using this function, you’re probably going to have some angry plugin developers bugging you at some point.
In this tutorial, I’m going to walk you through the steps of using the comment form and theme/plugin developers can manipulate its output.
The basic function
Standard comment forms in the past would look something like the below code.
<div id="respond">
Lots of HTML code to output form elements.
</div>
If you’re updating a theme, you’ll need to delete all of that comment form code and replace it with a single line.
<?php comment_form(); ?>
It does not get any simpler than that. If all you’re wanting to do is update your comment form to the new standard, you can stop reading now. That’s all the required code you need. You may have to tinker with your stylesheet to make sure the classes/IDs match with any changes, but you don’t have to do anything else.
Comment form arguments
The comment_form function takes in two parameters by default.
comment_form( $args, $post_id );
$args: An array of arguments for controlling the output of the comment form.$post_id: The ID of the post for which to show a comment form. This defaults to the current post, so you don’t need it in most scenarios.
The $args variable is what we want to focus on. There are two ways to change this. The first is to manually input the arguments into the comment_form() function. The second is to filter the output (see “Filtering the comment form defaults” below).
Input of these arguments would look something like this:
<?php comment_form(
array(
'cancel_reply_link' => __( 'Cancel reply' ),
'label_submit' => __( 'Post Comment' ),
)
); ?>
Next, I’ll list all the arguments and explain what they’re used for.
fields
The fields argument is an array of multiple fields that come standard in the comment form: author, email, and url. You can also add custom input fields here if you like, but we’re going to focus on the defaults for now.
These fields are only shown for users that are not logged in. It is assumed that these fields represent information that logged-in users have already provided through their profile page in the admin.
If you’re going to customize these fields, you need to add a small bit of code before the comment form for getting a few variables.
<?php
$commenter = wp_get_current_commenter();
$req = get_option( 'require_name_email' );
?>
When creating custom fields, the most important thing is to stay consistent with the HTML for easier styling.
'fields' => array(
'author' => '<p class="comment-form-author">' . '<label for="author">' . __( 'Name' ) . '</label> ' . ( $req ? '<span class="required">*</span>' : '' ) . '<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30" /></p>',
'email' => '<p class="comment-form-email"><label for="email">' . __( 'Email' ) . '</label> ' . ( $req ? '<span class="required">*</span>' : '' ) . '<input id="email" name="email" type="text" value="' . esc_attr( $commenter['comment_author_email'] ) . '" size="30" /></p>',
'url' => '<p class="comment-form-url"><label for="url">' . __( 'Website' ) . '</label>' . '<input id="url" name="url" type="text" value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" /></p>',
),
comment_field
The comment_field argument allows you to customize the HTML of the comment textarea (where the actual comment text is input).
'comment_field' => '<p class="comment-form-comment"><label for="comment">' . _x( 'Comment', 'noun' ) . '</label><textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea></p>',
must_log_in
To change the text shown when a user must log in to comment, you use the must_log_in argument. Note that you definitely need to use the standard wp_login_url() function to show a link for logging in. Otherwise, plugins won’t be able to hook into it properly.
'must_log_in' => '<p class="must-log-in">' . sprintf( __( 'You must be <a href="%s">logged in</a> to post a comment.' ), wp_login_url( get_permalink() ) ) . '</p>',
logged_in_as
You can easily change the text shown when a user is logged in using the logged_in_as argument. Note that you should also link to the user account with the admin_url() function and use the standard wp_logout_url() function for providing a link to log out of the site.
'logged_in_as' => '<p class="logged-in-as">' . sprintf( __( 'Logged in as <a href="%1$s">%2$s</a>. <a href="%3$s" title="Log out of this account">Log out?</a>' ), admin_url( 'profile.php' ), $user_identity, wp_logout_url( get_permalink() ) ) . '</p>',
comment_notes_before
The comment_notes_before argument allows you to add custom HTML before the comment form fields. This is only shown to users that are not logged in.
'comment_notes_before' => '<p class="comment-notes">' . __( 'Your email adress will not be published.' ) . '</p>',
comment_notes_after
The comment_notes_after argument is shown to all users (logged in or not) after the comment form fields and textarea.
'comment_notes_after' => '<p class="form-allowed-tags">' . sprintf( __( 'You may use these HTML tags and attributes: %s' ), ' <code>' . allowed_tags() . '</code>' ) . '</p>',
id_form
The id_form argument allows the input of a custom HTML ID for the <form> element.
'id_form' => 'commentform',
id_submit
The id_submit argument allows the input of a custom HTML ID for the submit button.
'id_submit' => 'submit',
label_submit
You can change the text for the submit button with the label_submit argument.
'label_submit' => __( 'Post Comment' ),
title_reply
Before the comment form a reply title is shown letting readers know they can reply. You can change its text with the title_reply argument.
'title_reply' => __( 'Leave a Reply' ),
title_reply_to
When users are using nested comments and a reader clicks the “reply” link on a comment, the reply title changes slightly. You can use the title_reply_to argument to customize this text.
'title_reply_to' => __( 'Leave a Reply to %s' ),
cancel_reply_link
When nested comments are turned on and a reader is replying to a comment, a cancel link is shown next to the reply title. The cancel_reply_link argument allows you to change the text shown for this.
'cancel_reply_link' => __( 'Cancel reply' ),
Filtering the comment form defaults
If you’re adding a lot of customizations to the comment_form as a theme developer, you probably noticed how quickly your code started looking messy. Generally, I don’t like for users to see all of that and potentially mess it up and take down their entire site. I highly recommend using comment_form_defaults or one of the other more-specific hooks for heavy customizations.
These filter hooks ares also what plugin authors will use to manipulate the comment form.
comment_form_default_fields
If you just need to change the output of the fields argument from above or add extra inputs, you would use this hook. The example below will add an input field for a Twitter username.
add_filter( 'comment_form_default_fields', 'my_comment_form_default_fields' );
function my_comment_form_default_fields( $fields ) {
$fields['twitter'] = '<p class="comment-form-twitter"><label for="twitter">' . __( 'Twitter (@username)' ) . '</label><input type="text" id="twitter" name="twitter" value="" size="30" /></p>';
return $fields;
}
comment_form_field_{$name}
You can also filter a specific default field by its name. The $name variable represents the array key used for the specific field. For example, you may want to change the <p> class for the author field.
add_filter( 'comment_form_field_author', 'my_comment_form_field_author' );
function my_comment_form_field_author( $field ) {
$field = str_replace( 'class="comment-form-author"', 'class="form-author"', $field );
return $field;
}
comment_form_field_comment
The comment_field argument from above also has a specific filter for overwriting it just before display. Let’s suppose we wanted to add a wrapper <div> around it because we have to do some funky CSS design.
add_filter( 'comment_form_field_comment', 'my_comment_form_field_comment' );
function my_comment_form_field_comment( $comment_field ) {
$comment_field = '<div class="comment-field-wrapper">' . $comment_field . '</div>';
return $comment_field;
}
comment_form_logged_in
This hook allows you to filter what’s displayed for the logged_in_as argument from above. It passes three parameters:
$logged_in_as: The HTML used for displaying logged-in information.$commenter: Information about the current comment provided by the wp_get_current_commenter() function.$user_identity: The global variable used in WordPress that represents the current user.
There’s a lot of things you can do with this, such as creating custom messages for the logged-in user. But, let’s keep this example simple and append a small message to the end of the normal output.
add_filter( 'comment_form_logged_in', 'my_comment_form_logged_in', 10, 3 );
function my_comment_form_logged_in( $logged_in_as, $commenter, $user_identity ) {
$logged_in_as .= '<p>' . __( 'We appreciated comments from registered users and are happy to read your feedback.' ) . '</p>';
return $logged_in_as;
}
comment_form_defaults
If you need to overwrite arguments other than the default fields, you’d use the comment_form_defaults filter hook. You can use this hook to overwrite any of the arguments we went over above. In the example below, we’re going to change the submit button text to read “Submit.”
add_filter( 'comment_form_defaults', 'my_comment_form_defaults' );
function my_comment_form_defaults( $defaults ) {
$defaults['label_submit'] = __( 'Submit' );
return $defaults;
}
Comment form action hooks
If you didn’t think there were enough filter hooks available for customization, take a look at these extra action hooks. There’s plenty of them to accommodate anyone’s needs.
I’m only going to give you one code example of using the hooks because the concept and method of using them is the same for each hook.
comment_form_comments_closed
This hook is fired only when comments are closed. It is also the only action hook available to developers when they’re closed. The other hooks will only be available when comments are open.
In this example, we’ll show a message to let readers know that commenting is now closed.
add_action( 'comment_form_comments_closed', 'my_comments_closed' );
function my_comments_closed() {
echo '<p class="comments-closed">' . __( 'Apologies, commenting is now disabled for this post.' ) . '</p>';
}
comment_form_before
The comment_form_before hook is fired just before the <div id="respond"> is displayed.
comment_form_after
The comment_form_after hook is fired immediately after the closing </div> of <div id="resond">.
comment_form_must_log_in_after
This action hook is fired just after the HTML for the must_log_in argument from the arguments listed above. It is only fired if the user is not logged in and comment registration is required for commenting.
comment_form_logged_in_after
This hook is an alternate hook to the previous one. It fires for logged-in users only. It is fired just after the logged_in_as argument from above is displayed.
comment_form_top
This hook is fired just after the opening of the <form> element and before any of the form fields are displayed.
comment_form
This hook is fired just before the closing </form>. It also passes the $post_id variable for use in your function.
You may wonder why it’s not called comment_form_bottom. This is because comment_form is a legacy hook that has been around for ages. It didn’t make much sense to have two hooks that done the same thing, so the developers just stuck with what we already had.
CSS rules
Now that you’ve figured out how to change the markup and know how all the hooks work, you might want to just get back to actually styling your comment form. I won’t go over any specific style stuff here, but I will give you a list of the basic things you can style.
These represent the default HTML output by the comment_form() function. Remember, you have nearly full control over the markup, so any changes you make need to be reflected in your theme’s style.css file.
/* Wrapper div for the entire comment form. */
div#respond { }
/* Reply title. */
h3#reply-title { }
/* Cancel comment link. */
h3#reply-title small { }
/* The comment form. */
form#commentform { }
/* Comment author field. */
p.comment-form-author { }
p.coment-form-author label { }
p.comment-form-author input#author { }
/* Comment email field. */
p.comment-form-email { }
p.comment-form-email label { }
p.comment-form-email input#email { }
/* Comment URL field. */
p.comment-form-url { }
p.comment-form-url label { }
p.comment-form-url input#url { }
/* Required (*) text. */
span.required { }
/* Comment form text. */
p.comment-form-comment { }
p.comment-form-comment label { }
p.comment-form-comment textarea#comment { }
/* Must log in paragraph. */
p.must-log-in { }
/* Logged in paragraph. */
p.logged-in-as { }
/* Comment notes paragraph. */
p.comment-notes { }
/* Allowed tags paragraph. */
p.form-allowed-tags { }
p.form-allowed-tags code { }
/* Paragraph that wraps the submit button and hidden comment ID fields. */
p.form-submit { }
/* Submit button. */
input#submit { }
Give the new comment form a try
I hope you found this tutorial useful and can use the information presented within your own projects. There’s definitely a lot of different ways you can customize the comment form now and plenty of hooks for plugin developers to use for cool plugins.
Please share any awesome customizations you’ve made in the comments. We’d love to hear about them.
thanks guys, these first 3 posts are looking the right way. I’m looking forward to what will come from this nice collaboration!
Excellent tutorial Justin! It’s on my backburner to do list for way too long now, so I should really do this ASAP! The tutorial will come in very handy. Thank you for an outstanding explanation.
I caught the title of this post on my iphone earlier and thought “could it be?” yea, it is and then some. holy crap, this post is sick. thank you so much.
vinh
Will threaded comments work with this implementation?
Yes. Nested comments don’t really have anything to do with the comment form itself.
Except for the couple arguments you stated above. The “cancel_reply_link” and “title_reply_to” come into effect for nested comments, and it’s good to have them. Looks like DevPress isn’t customizing the title_reply_to, but does have the cancel_reply_link.
Will threaded comments work with this implementation?
OK, Justin, now why don’t you explain how to rearrange elements of the comment form?
For instance, how did you move the labels and the “cancel reply” links from their default positions?
Thanks.
Very nice post that will definitely be bookmarked for future use. Just what I needed as I wanted to add html5 form fields to a base template but was unable to figure out how.
Justin: no more comments.php? I’m guessing the architecture is still there to support it but I guess we’re all supposed to be moving to comment_form because of plugin interoperability?
You still use
comments.php, but it should be a much smaller file now when using bothwp_list_comments()andcomment_form().The change makes it extremely easy for plugin authors to step in and do some creative stuff like comment ratings, Twitter contact fields, Gravatar previews, and so on. Before, much of this stuff was either too difficult or required the user to edit the comments template. Now, plugin authors can simply plug into the available hooks.
By far best explanation I’ve seen on this. Nice!
Great stuff!
Plan on trying the News theme.
Any chance of renaming it? I already have ‘News’ themes from Studio Press and WooThemes, which makes it hard to just dowload and install (I have to rename it 1st).
Thanks!
~Jeff
MileHighTechGuy
No chance of renaming it. It’s already on the WordPress themes repository with that name. Plus, renaming it would break your child theme.
Thanks for this tutorial. I’ve just recently wrote a callback for wp_list_comments() and was looking for a good way to work on the comments form! Good to see comments getting some love recently from WordPress updates.
I’m definitely liking DevPress so far! Keep up the great work guys!
Thanks for the tutorial. I just updated the theme which I use for all of my WordPress build and it only took me a few minutes to sort everything out.
Yeah, it’s extremely simple to make the change and the code is much cleaner.
Any idea why the $commenter and $req stuff would make the fields disappear whether logged in or not?
So instead of a bunch of basic html to create the basic comment forms, we now have a bunch of crazy php with a bunch of html hidden and mixed up inside it, so it is confusing and impossible for anybody but programmers to make any basic adjustments to the comments area? Sweet. Awesome idea. That’s not complete backwards at all.
Oh, goodie! An anonymous comment from someone too afraid to stand behind his own opinions by leaving a real email or Web site. Is “Ryan” even your real name?
The purpose of the function is to standardize the comment form so that theme developers don’t have to code all sorts of different comment forms with even crazier HTML. This allows plugin developers to create plugins that hook into it, which was impossible before.
If you want to create your own markup without using the
comment_form()function, you can do that. No one is stopping you.Just view your source code with the comment_form() function in, then find the div ‘respond’ and copy and paste it into your comments.php where the comment_form() function used to be.
That’s how I did it to customise my form. This way you keep all the functionality but can easily take parts out and read the id’s and classes that need styling.
It is stopping people because not every web developer is a programmer also. Writing everything inside out like that prevents front end development, or at least turns it into a giant head ache just trying to do basic things.
But, you don’t have to use the
comment_form()function. No one is forcing you to use it. If it bothers you so much, simply don’t use the function.Hi Justin, thanks for the tutorial. This is prob the most informative tut Ive come across on explaining how to use the filters and arguments available to the comment_form. Just a small question/request though – Im still very green to php and I can see what the arguments are doing to the outputed html, however each snippet you use for an example of what you can do to filter the output still leaves me a bit clueless since I kinda need to see one entire code block to get the bigger picture of how to apply each filter, hook, etc.
Im basically not very clear on how to start and end the code. I understand now what filters to use, and thats awesome cuz thats exactly what Im looking to do, however now I dont really know where to put them?….Any help to really green developer would be super appreciated…and thank you for the great info once again.
Best,
SB
Indeed, this is probably the best tutorial on the comment_form() function there is so far. Thanks for taking the time to write such an elaborate and helpful article, Justin. Keep up the good work!
Hi,
After adding some more fields to the comment form, how do I output this data to the comment itself?
Thanks,
Dan
Hi Justin!
Thanks for this explaination about comment_form(). There“s one thing i still do not understand: Can i split the output of comment_form() into two parts so that authorname, email and url surrounded by div 1 and commenttext and submit is surrounded by div 2? I need this to style these elements. Is there a way to do it with comment_form()?
PS: Sorry about my english…
Thanks so much for putting this up! This documentation is not anywhere else!
testing 123
this extensive post was incredibly useful and saved me a ton of work since i didn’t know comment_form() existed yet. thanks!
I too agree with Dan Stramer, how do you output this data onto the contact form?
Agh! not contact form, comment list…
You had mentioned this fields array..
Where does this code actually go?
Thanks for this! I’m trying to figure out how to customize my comments.php file without messing things up, and this is the first page I’ve found where it’s actually starting to make more sense.
Great! A wonderful tutorial on the comment_form() function.
When I add a new to the form, what is the best way to capture the new data for insertion into the database?
Sorry, the last comment should have read “When I add a new input field to the form, what is the best way to capture the new data for insertion into the database?
Your post was very helpful and concise!
Wish you all the best.
good post thanks
Thanks. This is the only documentation for I’ve found for comment_form() that actually helped me understand and navigate altering my theme. Big help.
Thanks for this. If I add twitter for the comment form how would I go about retrieving the twitter username the commenter submits?
Nevermind… I found this: http://www.binarymoon.co.uk/2010/05/integrate-twitters-wordpress-comments/ And it answered my question. Thanks!
Thanks very much, this post was really helpful; parts of that api can be quite confusing.
Thanks for this tutorial, very useful and well made.
I’d like to understand if the value of
$required_textvariable that the default comment_form uses can be retained as you did with$commenter = wp_get_current_commenter();$req = get_option( 'require_name_email' );
or if we just have to set it.
Thanks.
Thanks so much for this awesome detailed post. Helped a lot.
Hi,
Thanks so much for the great tutorial. Everything is very clear, but there’s something about WP forms that I still cannot figure out and wonder if you know how:
When a user misses a mandatory form field, or enters the wrong type of info, is there a way to create custom error messages displaying in the form page itself? Currently WP sends me to a default error page. I want to avoid this.
Thanks in advance!
There are so many blogs about wordpress. That is how popular it has become since its inception. This blog post is a great addition to its portfolio. It is important for wordpress users to know how to use the comment form. With this blog post, hopefully, more wordpress users are enlightened.
Hello,
I have been trying to customize my comment_form and the one thing I can’t figure out is how to change the order of fields.
For instance, I’d like the Comment area first, followed by the author name and url. The default has the name, url and then comment area.
Your helps is greatly appreciated!!
Reshma
This is just what i have been looking for, great article!
I am just starting in WP, but have done web dev in the other technologies for a while. I’ve been piecing together a CMS type theme from different tidbits that I’ve found from all over. I’m now to the point that I need to add some of the “blog” stuff to a couple of pages and was looking for a way to add comments to a page.
This will be a great starting place.
Just wanted to say that it seems that when I am searching the web for ideas that your name is always at the top of the list! You do awesome work!!
Thanks, Roger K
Your tutorial was great. However, I am a photographer that is using wordpress theme Twenty Ten and I’m sorry to disappoint all you bloggers, but I simply want to display my photography and not blog. Therefore, I’d like to remove the Leave a Reply & Comment form on the bottom of my pages. The comments have been a ROYAL nuissance as I get tons of spam. I have searched word press forums for hours trying to find a solution. My theory is after I finish my web site, I can opt to put the comments, reply fields back in, but for now I would like them out. Can you help me. I have printed out 4 pages of how to remove these items, one of which did work, but then I have this very nice error message on the bottom of my pages. Thanks for any help or input you can give me.
Hi,
How can I edit HTML in regardings to the tag positions. I understand all functions ect but don’t know what is the best way to implement some structure. I’d like to replace fields and main comments textarea (fields below). I’d also like to move cancel next to submit. I’ve done it using CSS (positions) but I suppose this is not the best way. I suppose should be some way to add filters _before, _after but doesn’t look clear from documentation to me.
How can I fire onclick event when a user clicks on Submit Comment?
How can I add that functionality?
Thanks.
Hi Justin,
I know it’s an old article, but I hope you’re still around and leave me a useful answer.
I have tried since last Friday (7 days) to figure out this problem, and though ( I thought) I understand your above article, no matter how hard I try, it will not compute for me
What I try to accomplish for so easy before the no-longer-that-new comment form. I simply want the input field to be at the left, followed by the asterix and then the label.
Do you have an solution?
Any help will be greatly appreciated, thank you.
Regards,
Michael
Hi, how can I show the comments if I use comment_form()? If I use comments_template() it shows the form and the comments of the post, but if I use comment_form only and then comment a post, the comments aren’t showing up! Only the form…. ;((( thanks a lot