Comments in WordPress
Posts (and pages, if you allow it) can receive comments from readers. They are stored in the wp_comments table, linked to the post, and shown by the theme under the content. A fresh site comes with one example comment on "Hello world!":
wp comment list --fields=comment_ID,comment_post_ID,comment_author,comment_approved+------------+-----------------+-----------------------+------------------+
| comment_ID | comment_post_ID | comment_author | comment_approved |
+------------+-----------------+-----------------------+------------------+
| 1 | 1 | A WordPress Commenter | 1 |
+------------+-----------------+-----------------------+------------------+comment_approved is 1 for approved comments. Pending comments have 0, and spam has spam.
Discussion settings
Settings → Discussion sets the rules for the whole site. The most important options, with their names in wp_options:
| Setting | Option | Default |
|---|---|---|
| Allow people to submit comments on new posts | default_comment_status |
open |
| Users must be registered and logged in to comment | comment_registration |
off |
| Automatically close comments on posts older than N days | close_comments_for_old_posts |
off |
| Comment must be manually approved | comment_moderation |
off |
| Comment author must have a previously approved comment | comment_previously_approved |
on |
| Hold a comment if it contains N or more links | comment_max_links |
2 |
wp option get default_comment_status
wp option get comment_previously_approved
wp option get comment_max_linksopen
1
2So by default, a first-time commenter is held for moderation, while someone with an approved comment is published straight away, unless their comment has two or more links.
Moderation in action
Here a new visitor comments, and WordPress decides whether to publish it using those rules:
<?php
$post = get_page_by_path( 'hello-world', OBJECT, 'post' );
$ravi = [
'comment_post_ID' => $post->ID,
'comment_author' => 'Ravi',
'comment_author_email' => 'ravi@example.com',
'comment_author_url' => '',
'comment_author_IP' => '203.0.113.5',
'comment_agent' => 'Example browser',
];
$first = wp_new_comment( $ravi + [ 'comment_content' => 'Thanks, this helped me a lot.' ], true );
echo "1. first comment: ", wp_get_comment_status( $first ), "\n";
wp_set_comment_status( $first, 'approve' ); // an administrator approves it
$again = wp_new_comment( $ravi + [ 'comment_content' => 'One more question: does this work on mobile?' ], true );
echo "2. straight away: ", is_wp_error( $again ) ? $again->get_error_message() : wp_get_comment_status( $again ), "\n";
// A few minutes later (we move the first comment's time back to simulate that)
$five_minutes_ago = gmdate( 'Y-m-d H:i:s', time() - 300 );
wp_update_comment( [ 'comment_ID' => $first, 'comment_date' => get_date_from_gmt( $five_minutes_ago ), 'comment_date_gmt' => $five_minutes_ago ] );
$later = wp_new_comment( $ravi + [ 'comment_content' => 'One more question: does this work on mobile?' ], true );
echo "3. five minutes later: ", is_wp_error( $later ) ? $later->get_error_message() : wp_get_comment_status( $later ), "\n";1. first comment: unapproved
2. straight away: You are posting comments too quickly. Slow down.
3. five minutes later: approvedThree rules showed up:
- Ravi's first comment was held (
unapproved), because he had never commented before. - His second attempt, seconds later, was rejected outright by WordPress's flood protection, which stops anyone posting comments faster than once every 15 seconds. It was not saved at all.
- A few minutes later the same comment was published immediately, because Ravi now has a previously approved comment.
Note that wp_new_comment() returns an error object rather than a comment ID when a comment is refused, so code that saves comments should always check with is_wp_error().
In the dashboard, Comments lists everything, with filters for Pending, Approved, Spam and Trash. Hover over a comment for Approve, Reply, Quick Edit, Spam and Trash. The number in the admin menu bubble shows pending comments.
What visitors see
The theme lists approved comments only:
GET /hello-world/Hi, this is a comment.
To get started with moderating, editing, and deleting comments, please visit the Comments screen in the dashboard.
Commenter avatars come from Gravatar.
Thanks, this helped me a lot.
One more question: does this work on mobile?The example comment and Ravi's two approved comments appear; pending, rejected and spam comments never do.
Per-post settings
Each post and page has its own Discussion panel in the editor sidebar, where you can turn comments (and pingbacks) on or off for that item only. Changing the site-wide default affects new posts; existing posts keep their own setting. To close comments everywhere at once, WP-CLI can update existing posts:
wp option update default_comment_status closed
wp post list --post_type=post --comment_status=open --format=idsSuccess: Updated 'default_comment_status' option.
1The second command lists the posts that still allow comments. You could then close them in the dashboard with Bulk actions → Edit → Comments: Do not allow, or with wp post update.
Dealing with spam
Bots post huge amounts of comment spam: links to dubious sites, often with generic praise. Defences, from easiest:
- Akismet (included with WordPress, needs an API key) or another anti-spam plugin checks every comment against a large database of known spam.
- Keep "previously approved" moderation on, and hold comments with links.
- Add words that often appear in spam to Disallowed Comment Keys (sends matches to trash).
- Close comments on old posts after, say, 30 days; most spam targets old posts.
- If you do not want discussion at all, turn comments off. Many business sites do.
Never approve a comment just because it is flattering; generic praise with a link in the author's name is the classic spam pattern.
Comments and privacy
Comments store the commenter's name, email and IP address. WordPress lists this in its suggested privacy policy text, and Tools → Export Personal Data and Erase Personal Data handle requests from commenters under laws such as the GDPR. Mention comments in your privacy policy if you allow them.
Common mistakes
- Leaving comments open with no moderation or anti-spam, so spam piles up.
- Approving spam that looks friendly.
- Changing the default and expecting old posts to close.
- Not replying: if you invite discussion, answer it.
Exercise
Configure your local site so that comments close automatically on posts older than 14 days, every comment needs manual approval, and only logged-in users can comment. Then check the three options with WP-CLI.
Show one possible answer
In Settings → Discussion, tick Automatically close comments on posts older than 14 days, Comment must be manually approved and Users must be registered and logged in to comment, then save. With WP-CLI: wp option get close_comments_for_old_posts (1), wp option get close_comments_days_old (14), wp option get comment_moderation (1) and wp option get comment_registration (1).
Key points
- Comments are stored in wp_comments with a status: approved, pending (held for moderation), spam or trash.
- Settings → Discussion controls who can comment, when comments need approval, and when old posts close.
- Each post can allow or close comments individually in the editor's Discussion panel.
- Use an anti-spam plugin such as Akismet, and hold links for moderation; or turn comments off if you will not moderate them.