What happens, when a user comments?
2014
I’ve just replied to the first comment on my blog, when I started to wonder: And does he gets now an email, which informs him about the reply. Well, I didn’t know, and so I started to dig a bit into the core. Sure, I could just test it by writing a comment and comment on this comment. But what fun would that be? And journeys into the core are always more than just to dig one answer. So follow me on my trip and find out what happens, when a user writes a comment.
Well, if you just want to know, how the Comment System works in the view of the user or administrator, here you go. If you want to dig, follow me.

Snæfellsjökull: The journey begins
If you have ever developed your own WordPress Theme, you know, how easy you are able to implement the WordPress Comment System. I started to wonder, what does happen, when a reader actually sends a comment. So I went into the core.
To integrate the Comment Form, you usually just use
So we start to digg for it. I always use Nodepad++ and search all files in wp-includes for a term. Lazy as I am, I just type in ‘comment_form’ and suddenly end up in ‘comments-popup.php’. Its dark and cold in here and a voice in the off is whispering:
This file is here for Backwards compatibility with old themes and will be removed in a future version
So we took a wrong turn, and – almost – get out of water.
Back again and more focussed, we end up in comment-template.php Line 1960. Here, we find the comment_form, which returns the complete form, you need, to enable users to send their comments. As we can see in Line 2046 a comment will be send to wp-comments-post.php
The first lines check, wether there was used the right Request-Method, which is POST. So, if you create your theme and for some reasons, you don’t want to use
make sure, you do send the form via POST, which is the proper way to do anyway.
The first value, that is checked, is the comment_post_ID. This is the ID of the Post, you reply to. Now, the System grabs this Post, and first checks, whether there is a valid comment_status for this Post. If not, the script terminates after firing the Action Hook ‘comment_id_not_found’.
The lines 40 to 84 handle now all the exceptions.
- Comments Closed
- When the comments are closed for this Post, the Action Hook ‘comment_closed’ is fired and the script terminates
- Post is in Trash
- Fires the Action Hook ‘comment_on_trash’ and terminates script
- Post is a Draft
- Fires the Action Hook ‘comment_on_draft’ and terminates
- Post is protected by Password
- Fires ‘comment_on_password_protected’-Hook and terminates.
If everything works fine, it goes on after firing ‘pre_comment_on_post’. Now, WordPress grabs the information send by the Form:
- Author
- URL
- Content
If the reader is logged into the System (for example, the Administrator), these values get overwritten by the values, saved in the System. It additionally checks, whether the loggedin user can use unfiltered HTML. When he is able to, his Comment won’t be filtered for Javascript and HTML markup.
If the user is not loggedin, the System checks now, whether this post is private or you need to be loggedin in order to post a comment. If so, the script terminates.
But, we are back on track. Lets say everything works fine. Now, the information, which has been send by the form needs some validation. Is an Email given and do we need an email? Do we need a name, and no name is given. Does the Comment itself contains text? If not, the script terminates and tells the visitor to provide sufficient information.
But, lets say, everything is correct. Now, its time to check, whether this comment is a reply to another comment. And after this all these information get stored in $commentdata with compact() and send over to the function wp_new_comment()
Onto the coastline: wp_new_comment()
So, we passed all the validated data to wp_new_comment(), which first of all fires the ‘preprocess_comment’-filter, through which all the commentdata will be processed. So, for example, Akismet uses this filter in order to process this data. Akismet sends this data with some other $_SERVER-Information to akismet.com, where it will be checked whether this comment is spam or not.
But, after some Plugin daylight, back into the cave. wp_new_comment() now validates again some data, so for example it ensures that the comment_post_ID is really an Integer.
$commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
Interesting is to see the user_ID-Section in Line 1697 – 1700. Whether the User-Id gets transmitted via $commentdata[‘user_ID’] or $commentdata[‘user_id’], it will be checked and from now on, it will be called ‘user_id’. One might wonder, how come. The history for this piece:
- 4 years ago sirzooro posted a bug “PHP Notice while untrashing comment”
- Ryan provided a first fix, by changing all user_IDs into user_ids.
- But, this lead to another bug, as westi reported:
This broke setup_userdata()
- So, since Changeset 12300 user_id as well as user_ID are accepted
WordPress now checks on the comment_parent. Does this parent exist and is it approved or pending. If so, the parentID remains. If not, the ID is set to 0.
WordPress continues to enrich the data of the comment by the IP and the User-Agent of the User and the Date.
But still, our first question: Does the author of the comment, I’ve replied to got an email? We have to go on. So, what happens now with our data? Three new functions appear at the horizon:
- wp_filter_comment()
- wp_allow_comment()
- wp_insert_comment()
wp_filter_comment()
- pre_user_id (Where we, by the way, find again a user_id-normalisation)
- pre_comment_user_agent
- pre_comment_author_name
- pre_comment_content
- pre_comment_user_ip
- pre_comment_author_url
- pre_comment_author_email
After all these filters are applied, a new value is added:
$commentdata['filtered'] = true;
and the data gets returned.
I am especially happy about ‘pre_comment_user_ip’. When we came to comment.php Line 1706
$commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '',$_SERVER['REMOTE_ADDR'] );
I was a bit concerned for privacy reasons. I already wrote a small comment, that it would be nice, to have a filter, which enables you to get rid of the IP. Well – thats WordPress – this filter exists! Here is, what I wrote, because this issue can even end up in legal matters:
Especially, when it comes to the IP, one might wonder, whether it would be possible to add a filter-hook here. Maybe some bloggers do not want to save the IP of commentators for privacy reasons. As far as I know, there might be even legal problems concerning the saving of IP addresses, for example in Germany. It would be nice to have the possibility to disable this function.
For all those of you, who want to get rid of this IP-saving method, check out Remove IP by guido. It exactly hooks into the ‘pre_comment_user_ip’-Filter and sets the IP to “127.0.0.1” (localhost). (See here)
wp_allow_comment()
‘Duplicate comment detected; it looks as though you’ve already said that!’
We come close now to the point, where the comment indeed will be saved. Close to the Center of the Earth! We bypass the Filter ‘check_comment_flood’, which allows checking for comment flooding. We check, whether the comment was send by the post author. If so, it gets approved immidiatly. If not, some tests are run, whether the comment needs moderation or not. See for more information: check_comment().
wp_allow_comment() returns as far as I can see it three possible values: 0, 1 and “spam”. This information is saved here:
$commentdata['comment_approved'] = wp_allow_comment($commentdata);
And now, we come to wp_insert_comment(), which reminds one the famous wp_insert_post()!
wp_insert_comment()
We are here. Where the heart of the comment system beats! After some checks on the data, the comment will be finally saved in Line 1564! We receive an ID. If the Comment is already approved, the Counter will be set +1 (Line 1569), well okay, after running through two different functions and acutally, in the end its not a $count++ but an SQL Statement, but after all, the counter is set +1.
But still, we don’t know yet: Did he got a mail? So we return into Line 1716, where we now have at least the ID of the new comment. After the ‘comment_post’-Action, two functions are quite interesting:
wp_notify_moderator() and wp_notify_postauthor()
The result of the first function, we know it all quite too well. It will send the Email to the Administrator, that an Comment is waiting for approval.
The second one will send an Email to the postauthor, if the specific option ‘comments_notify’ is set. Actually, the function itself contains a lot of possibilities to add other Email addresses as well. But anyway, by default this Notification is disabled, and my blog runs quite the basic values.
And suddenly, I get it. Of course not! There are some extensions, which say, notify me, when someone replies. But I haven’t such a function. So we return with our new Comment ID, which we received in wp_new_comment() and find ourselfs again in wp-comments-post.php
More or less, after some filters, we get redirected to our Post, where we started our journey. And we know: He doesn’t know at all.