# Let Visitors Report Inappropriate Comments

> Adds a "Report" link to each comment; moderators get an email on the first report and the comment is held for review after three reports.

- Type: PHP
- Runs: Run everywhere
- Category: [Comments](https://wpide.com/library/category/comments/)
- Tags: comments, moderation, community
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/report-comment-link/

## Code

```php
// Reports after which a comment is unpublished until a moderator reviews it.
$wpide_report_threshold = 3;

add_filter( 'comment_text', function ( $text, $comment ) {
    if ( is_admin() || wp_is_json_request() || ! ( $comment instanceof WP_Comment ) || '1' !== (string) $comment->comment_approved || is_feed() ) {
        return $text;
    }

    return $text . sprintf( '<p class="wpide-report"><a href="#" class="wpide-report-comment" data-id="%d" style="font-size:.8em;opacity:.7">Report</a></p>', (int) $comment->comment_ID );
}, 30, 2 );

add_action( 'wp_footer', function () {
    if ( ! is_singular() || ! get_comments_number() ) {
        return;
    }
    ?>
    <script>
    document.addEventListener( 'click', function ( event ) {
        var link = event.target.closest( '.wpide-report-comment' );
        if ( ! link ) {
            return;
        }
        event.preventDefault();
        if ( ! window.confirm( 'Report this comment to the moderators?' ) ) {
            return;
        }
        var data = new FormData();
        data.append( 'action', 'wpide_report_comment' );
        data.append( 'comment_id', link.dataset.id );
        data.append( 'nonce', <?php echo wp_json_encode( wp_create_nonce( 'wpide_report_comment' ) ); ?> );
        fetch( <?php echo wp_json_encode( admin_url( 'admin-ajax.php' ) ); ?>, { method: 'POST', body: data, credentials: 'same-origin' } )
            .then( function () { link.replaceWith( document.createTextNode( 'Thanks, reported.' ) ); } );
    } );
    </script>
    <?php
} );

$wpide_handle_report = function () use ( $wpide_report_threshold ) {
    check_ajax_referer( 'wpide_report_comment', 'nonce' );

    $comment_id = isset( $_POST['comment_id'] ) ? absint( $_POST['comment_id'] ) : 0;
    $comment    = $comment_id ? get_comment( $comment_id ) : null;

    if ( ! $comment || '1' !== (string) $comment->comment_approved ) {
        wp_send_json_error( null, 404 );
    }

    $ip  = isset( $_SERVER['REMOTE_ADDR'] ) ? (string) $_SERVER['REMOTE_ADDR'] : '';
    $key = 'wpide_reported_' . md5( $ip . '|' . $comment_id );

    if ( get_transient( $key ) ) {
        wp_send_json_success(); // Already counted for this visitor.
    }

    set_transient( $key, 1, DAY_IN_SECONDS );
    $reports = (int) get_comment_meta( $comment_id, 'wpide_reports', true ) + 1;
    update_comment_meta( $comment_id, 'wpide_reports', $reports );

    if ( 1 === $reports ) {
        wp_mail(
            get_option( 'admin_email' ),
            'A comment was reported',
            sprintf( "A visitor reported this comment:\n\n%s\n\nReview it: %s", wp_trim_words( wp_strip_all_tags( $comment->comment_content ), 60 ), admin_url( 'comment.php?action=editcomment&c=' . $comment_id ) )
        );
    }

    if ( $reports >= $wpide_report_threshold ) {
        wp_set_comment_status( $comment_id, 'hold' );
    }

    wp_send_json_success();
};

add_action( 'wp_ajax_wpide_report_comment', $wpide_handle_report );
add_action( 'wp_ajax_nopriv_wpide_report_comment', $wpide_handle_report );
```

## Notes

Page caching longer than 12 hours can make the report link fail, because the security token expires.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Let Visitors Report Inappropriate Comments" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
