* @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
* @param bool $force_delete Whether to bypass Trash and force deletion. Default false.
* @return bool True on success, false on failure.
function wp_delete_comment( $comment_id, $force_delete = false ) {
$comment = get_comment( $comment_id );
if ( ! $force_delete && EMPTY_TRASH_DAYS && ! in_array( wp_get_comment_status( $comment ), array( 'trash', 'spam' ), true ) ) {
return wp_trash_comment( $comment_id );
* Fires immediately before a comment is deleted from the database.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The comment to be deleted.
do_action( 'delete_comment', $comment->comment_ID, $comment );
// Move children up a level.
$children = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment->comment_ID ) );
if ( ! empty( $children ) ) {
$wpdb->update( $wpdb->comments, array( 'comment_parent' => $comment->comment_parent ), array( 'comment_parent' => $comment->comment_ID ) );
clean_comment_cache( $children );
$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment->comment_ID ) );
foreach ( $meta_ids as $mid ) {
delete_metadata_by_mid( 'comment', $mid );
if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment->comment_ID ) ) ) {
* Fires immediately after a comment is deleted from the database.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The deleted comment.
do_action( 'deleted_comment', $comment->comment_ID, $comment );
$post_id = $comment->comment_post_ID;
if ( $post_id && '1' === $comment->comment_approved ) {
wp_update_comment_count( $post_id );
clean_comment_cache( $comment->comment_ID );
/** This action is documented in wp-includes/comment.php */
do_action( 'wp_set_comment_status', $comment->comment_ID, 'delete' );
wp_transition_comment_status( 'delete', $comment->comment_approved, $comment );
* Moves a comment to the Trash
* If Trash is disabled, comment is permanently deleted.
* @since 6.9.0 Any child notes are deleted when deleting a note.
* @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
* @return bool True on success, false on failure.
function wp_trash_comment( $comment_id ) {
if ( ! EMPTY_TRASH_DAYS ) {
$comment = get_comment( $comment_id );
$success = wp_delete_comment( $comment_id, true );
// Also delete children of top level 'note' type comments.
if ( $comment && 'note' === $comment->comment_type && 0 === (int) $comment->comment_parent ) {
$children = $comment->get_children(
foreach ( $children as $child_id ) {
if ( ! wp_delete_comment( $child_id, true ) ) {
$comment = get_comment( $comment_id );
* Fires immediately before a comment is sent to the Trash.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The comment to be trashed.
do_action( 'trash_comment', $comment->comment_ID, $comment );
if ( wp_set_comment_status( $comment, 'trash' ) ) {
delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
* Fires immediately after a comment is sent to Trash.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The trashed comment.
do_action( 'trashed_comment', $comment->comment_ID, $comment );
// For top level 'note' type comments, also trash children.
if ( 'note' === $comment->comment_type && 0 === (int) $comment->comment_parent ) {
$children = $comment->get_children(
foreach ( $children as $child_id ) {
if ( ! wp_trash_comment( $child_id ) ) {
* Removes a comment from the Trash
* @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
* @return bool True on success, false on failure.
function wp_untrash_comment( $comment_id ) {
$comment = get_comment( $comment_id );
* Fires immediately before a comment is restored from the Trash.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The comment to be untrashed.
do_action( 'untrash_comment', $comment->comment_ID, $comment );
$status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
if ( empty( $status ) ) {
if ( wp_set_comment_status( $comment, $status ) ) {
delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
* Fires immediately after a comment is restored from the Trash.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The untrashed comment.
do_action( 'untrashed_comment', $comment->comment_ID, $comment );
* Marks a comment as Spam.
* @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
* @return bool True on success, false on failure.
function wp_spam_comment( $comment_id ) {
$comment = get_comment( $comment_id );
* Fires immediately before a comment is marked as Spam.
* @since 4.9.0 Added the `$comment` parameter.
* @param int $comment_id The comment ID.
* @param WP_Comment $comment The comment to be marked as spam.
do_action( 'spam_comment', $comment->comment_ID, $comment );
if ( wp_set_comment_status( $comment, 'spam' ) ) {
delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
add_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', $comment->comment_approved );
add_comment_meta( $comment->comment_ID, '_wp_trash_meta_time', time() );
* Fires immediately after a comment is marked as Spam.
* @since 4.9.0 Added the `$comment` parameter.
* @param int $comment_id The comment ID.
* @param WP_Comment $comment The comment marked as spam.
do_action( 'spammed_comment', $comment->comment_ID, $comment );
* Removes a comment from the Spam.
* @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
* @return bool True on success, false on failure.
function wp_unspam_comment( $comment_id ) {
$comment = get_comment( $comment_id );
* Fires immediately before a comment is unmarked as Spam.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The comment to be unmarked as spam.
do_action( 'unspam_comment', $comment->comment_ID, $comment );
$status = (string) get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true );
if ( empty( $status ) ) {
if ( wp_set_comment_status( $comment, $status ) ) {
delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_status' );
delete_comment_meta( $comment->comment_ID, '_wp_trash_meta_time' );
* Fires immediately after a comment is unmarked as Spam.
* @since 4.9.0 Added the `$comment` parameter.
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment The comment unmarked as spam.
do_action( 'unspammed_comment', $comment->comment_ID, $comment );
* Retrieves the status of a comment by comment ID.
* @param int|WP_Comment $comment_id Comment ID or WP_Comment object
* @return string|false Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
function wp_get_comment_status( $comment_id ) {
$comment = get_comment( $comment_id );
$approved = $comment->comment_approved;
if ( null === $approved ) {
} elseif ( '1' === $approved ) {
} elseif ( '0' === $approved ) {
} elseif ( 'spam' === $approved ) {
} elseif ( 'trash' === $approved ) {
* Calls hooks for when a comment status transition occurs.
* Calls hooks for comment status transitions. If the new comment status is not the same
* as the previous comment status, then two hooks will be ran, the first is
* {@see 'transition_comment_status'} with new status, old status, and comment data.
* The next action called is {@see 'comment_$old_status_to_$new_status'}. It has
* The final action will run whether or not the comment statuses are the same.
* The action is named {@see 'comment_$new_status_$comment->comment_type'}.
* @param string $new_status New comment status.
* @param string $old_status Previous comment status.
* @param WP_Comment $comment Comment object.
function wp_transition_comment_status( $new_status, $old_status, $comment ) {
* Translate raw statuses to human-readable formats for the hooks.
* This is not a complete list of comment status, it's only the ones
* that need to be renamed.
$comment_statuses = array(
'hold' => 'unapproved', // wp_set_comment_status() uses "hold".
'approve' => 'approved', // wp_set_comment_status() uses "approve".
if ( isset( $comment_statuses[ $new_status ] ) ) {
$new_status = $comment_statuses[ $new_status ];
if ( isset( $comment_statuses[ $old_status ] ) ) {
$old_status = $comment_statuses[ $old_status ];
if ( $new_status !== $old_status ) {
* Fires when the comment status is in transition.
* @param string $new_status The new comment status.
* @param string $old_status The old comment status.
* @param WP_Comment $comment Comment object.
do_action( 'transition_comment_status', $new_status, $old_status, $comment );
* Fires when the comment status is in transition from one specific status to another.
* The dynamic portions of the hook name, `$old_status`, and `$new_status`,
* refer to the old and new comment statuses, respectively.
* Possible hook names include:
* - `comment_unapproved_to_approved`
* - `comment_spam_to_approved`
* - `comment_approved_to_unapproved`
* - `comment_spam_to_unapproved`
* - `comment_unapproved_to_spam`
* - `comment_approved_to_spam`
* @param WP_Comment $comment Comment object.
do_action( "comment_{$old_status}_to_{$new_status}", $comment );
* Fires when the status of a specific comment type is in transition.
* The dynamic portions of the hook name, `$new_status`, and `$comment->comment_type`,
* refer to the new comment status, and the type of comment, respectively.
* Typical comment types include 'comment', 'pingback', or 'trackback'.
* Possible hook names include:
* - `comment_approved_comment`
* - `comment_approved_pingback`
* - `comment_approved_trackback`
* - `comment_unapproved_comment`
* - `comment_unapproved_pingback`
* - `comment_unapproved_trackback`
* - `comment_spam_comment`
* - `comment_spam_pingback`
* - `comment_spam_trackback`
* @param string $comment_id The comment ID as a numeric string.
* @param WP_Comment $comment Comment object.
do_action( "comment_{$new_status}_{$comment->comment_type}", $comment->comment_ID, $comment );
* Clears the lastcommentmodified cached value when a comment status is changed.
* Deletes the lastcommentmodified cache key when a comment enters or leaves
* @param string $new_status The new comment status.
* @param string $old_status The old comment status.
function _clear_modified_cache_on_transition_comment_status( $new_status, $old_status ) {
if ( 'approved' === $new_status || 'approved' === $old_status ) {
foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
$data[] = "lastcommentmodified:$timezone";
wp_cache_delete_multiple( $data, 'timeinfo' );
* Gets current commenter's name, email, and URL.
* Expects cookies content to already be sanitized. User of this function might
* wish to recheck the returned array for validity.
* @see sanitize_comment_cookies() Use to sanitize cookies
* An array of current commenter variables.
* @type string $comment_author The name of the current commenter, or an empty string.
* @type string $comment_author_email The email address of the current commenter, or an empty string.
* @type string $comment_author_url The URL address of the current commenter, or an empty string.
function wp_get_current_commenter() {
// Cookies should already be sanitized.
if ( isset( $_COOKIE[ 'comment_author_' . COOKIEHASH ] ) ) {
$comment_author = $_COOKIE[ 'comment_author_' . COOKIEHASH ];
$comment_author_email = '';
if ( isset( $_COOKIE[ 'comment_author_email_' . COOKIEHASH ] ) ) {
$comment_author_email = $_COOKIE[ 'comment_author_email_' . COOKIEHASH ];