I’ll build this as a complete advanced
comments.php for your RX theme: safe comments display, custom callback, pagination, comment form, accessibility, spam-safe output, schema-friendly structure, and developer hooks.Below is a large, advanced, production-ready comments.php for your RX theme. It uses WordPress core functions: wp_list_comments() for listing comments, comment_form() for the comment form, and the_comments_pagination() for comment pagination. These are the correct WordPress template tools for a theme comments file.
Create or replace:
rx-theme/comments.php
with this code:
<?php
/**
* RX Theme Advanced Comments Template
*
* File: comments.php
*
* Features:
* - Safe direct-access protection
* - Password-protected post support
* - Custom comment callback
* - Avatar, author, date, edit link, reply link
* - Pending moderation notice
* - Comment pagination top and bottom
* - Trackback / pingback support
* - Accessible headings and labels
* - Advanced comment form fields
* - Consent checkbox support
* - Schema-friendly comment markup
* - Developer-friendly filters and actions
*
* @package RX_Theme
*/
defined( 'ABSPATH' ) || exit;
/**
* Stop loading comments if the post is password protected.
*/
if ( post_password_required() ) {
return;
}
/**
* Helper: Get RX comment count text.
*/
if ( ! function_exists( 'rx_theme_comments_title_text' ) ) {
function rx_theme_comments_title_text() {
$comment_count = get_comments_number();
if ( '1' === (string) $comment_count ) {
return esc_html__( 'One Comment', 'rx-theme' );
}
return sprintf(
esc_html(
_n(
'%s Comment',
'%s Comments',
$comment_count,
'rx-theme'
)
),
number_format_i18n( $comment_count )
);
}
}
/**
* Helper: Custom RX comment callback.
*
* Used by wp_list_comments().
*/
if ( ! function_exists( 'rx_theme_comment_callback' ) ) {
function rx_theme_comment_callback( $comment, $args, $depth ) {
$GLOBALS['comment'] = $comment;
$comment_id = get_comment_ID();
$comment_author = get_comment_author();
$comment_type = get_comment_type();
$avatar_size = isset( $args['avatar_size'] ) ? absint( $args['avatar_size'] ) : 64;
$is_by_post_author = false;
if ( (int) $comment->user_id > 0 ) {
$post_author_id = (int) get_post_field( 'post_author', get_the_ID() );
$is_by_post_author = ( (int) $comment->user_id === $post_author_id );
}
$comment_classes = array(
'rx-comment',
'rx-comment-type-' . sanitize_html_class( $comment_type ),
);
if ( $is_by_post_author ) {
$comment_classes[] = 'rx-comment-by-post-author';
}
?>
<li <?php comment_class( $comment_classes ); ?> id="comment-<?php echo esc_attr( $comment_id ); ?>" itemprop="comment" itemscope itemtype="https://schema.org/Comment">
<article id="div-comment-<?php echo esc_attr( $comment_id ); ?>" class="rx-comment-body">
<header class="rx-comment-header">
<div class="rx-comment-avatar-wrap">
<?php
if ( get_option( 'show_avatars' ) ) {
echo get_avatar(
$comment,
$avatar_size,
'',
esc_attr( $comment_author ),
array(
'class' => 'rx-comment-avatar',
'loading' => 'lazy',
'force_display' => false,
)
);
}
?>
</div>
<div class="rx-comment-meta">
<div class="rx-comment-author-wrap">
<span class="rx-comment-author" itemprop="author" itemscope itemtype="https://schema.org/Person">
<span itemprop="name">
<?php echo esc_html( $comment_author ); ?>
</span>
</span>
<?php if ( $is_by_post_author ) : ?>
<span class="rx-comment-author-badge">
<?php esc_html_e( 'Author', 'rx-theme' ); ?>
</span>
<?php endif; ?>
</div>
<div class="rx-comment-time-wrap">
<a class="rx-comment-permalink" href="<?php echo esc_url( get_comment_link( $comment ) ); ?>">
<time
class="rx-comment-time"
datetime="<?php comment_time( 'c' ); ?>"
itemprop="datePublished"
>
<?php
printf(
esc_html__( '%1$s at %2$s', 'rx-theme' ),
esc_html( get_comment_date() ),
esc_html( get_comment_time() )
);
?>
</time>
</a>
</div>
</div>
</header>
<?php if ( '0' === (string) $comment->comment_approved ) : ?>
<div class="rx-comment-awaiting-moderation">
<?php esc_html_e( 'Your comment is awaiting moderation.', 'rx-theme' ); ?>
</div>
<?php endif; ?>
<div class="rx-comment-content" itemprop="text">
<?php comment_text(); ?>
</div>
<footer class="rx-comment-footer">
<div class="rx-comment-actions">
<?php
comment_reply_link(
array_merge(
$args,
array(
'add_below' => 'div-comment',
'depth' => $depth,
'max_depth' => $args['max_depth'],
'before' => '<span class="rx-comment-reply">',
'after' => '</span>',
)
)
);
?>
<?php
edit_comment_link(
esc_html__( 'Edit', 'rx-theme' ),
'<span class="rx-comment-edit">',
'</span>'
);
?>
</div>
</footer>
</article>
<?php
}
}
/**
* Helper: Custom pingback / trackback callback.
*/
if ( ! function_exists( 'rx_theme_ping_callback' ) ) {
function rx_theme_ping_callback( $comment, $args, $depth ) {
$GLOBALS['comment'] = $comment;
?>
<li <?php comment_class( 'rx-ping' ); ?> id="comment-<?php comment_ID(); ?>">
<div class="rx-ping-body">
<span class="rx-ping-label">
<?php esc_html_e( 'Pingback:', 'rx-theme' ); ?>
</span>
<?php comment_author_link(); ?>
<?php
edit_comment_link(
esc_html__( 'Edit', 'rx-theme' ),
'<span class="rx-ping-edit">',
'</span>'
);
?>
</div>
<?php
}
}
$rx_comment_count = get_comments_number();
$rx_comments_are_open = comments_open();
$rx_has_comments = have_comments();
$rx_current_post_id = get_the_ID();
$rx_comment_order_class = get_option( 'comment_order' ) === 'desc' ? 'rx-comments-newest-first' : 'rx-comments-oldest-first';
?>
<section
id="comments"
class="rx-comments-area <?php echo esc_attr( $rx_comment_order_class ); ?>"
aria-labelledby="rx-comments-title"
>
<?php do_action( 'rx_theme_before_comments_area' ); ?>
<?php if ( $rx_has_comments ) : ?>
<header class="rx-comments-header">
<h2 id="rx-comments-title" class="rx-comments-title">
<?php echo esc_html( rx_theme_comments_title_text() ); ?>
</h2>
<p class="rx-comments-description">
<?php
printf(
esc_html__( 'Discussion for: %s', 'rx-theme' ),
'<span>' . esc_html( get_the_title() ) . '</span>'
);
?>
</p>
</header>
<?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : ?>
<nav class="rx-comments-navigation rx-comments-navigation-top" aria-label="<?php esc_attr_e( 'Comments navigation', 'rx-theme' ); ?>">
<?php
the_comments_pagination(
array(
'prev_text' => esc_html__( 'Previous Comments', 'rx-theme' ),
'next_text' => esc_html__( 'Next Comments', 'rx-theme' ),
'screen_reader_text' => esc_html__( 'Comments pagination', 'rx-theme' ),
'aria_label' => esc_html__( 'Comments pagination', 'rx-theme' ),
'class' => 'rx-comments-pagination',
)
);
?>
</nav>
<?php endif; ?>
<div class="rx-comments-list-wrap">
<ol class="rx-comments-list">
<?php
wp_list_comments(
apply_filters(
'rx_theme_wp_list_comments_args',
array(
'style' => 'ol',
'type' => 'comment',
'callback' => 'rx_theme_comment_callback',
'avatar_size' => 64,
'short_ping' => false,
'format' => 'html5',
'max_depth' => get_option( 'thread_comments_depth' ),
'reverse_top_level' => null,
'reverse_children' => false,
)
)
);
?>
</ol>
</div>
<?php
$rx_pings = get_comments(
array(
'post_id' => $rx_current_post_id,
'type__in' => array( 'pingback', 'trackback' ),
'status' => 'approve',
)
);
?>
<?php if ( ! empty( $rx_pings ) ) : ?>
<section class="rx-pings-area" aria-labelledby="rx-pings-title">
<h3 id="rx-pings-title" class="rx-pings-title">
<?php esc_html_e( 'Pingbacks and Trackbacks', 'rx-theme' ); ?>
</h3>
<ol class="rx-pings-list">
<?php
wp_list_comments(
array(
'style' => 'ol',
'type' => 'pings',
'callback' => 'rx_theme_ping_callback',
'short_ping' => true,
'format' => 'html5',
),
$rx_pings
);
?>
</ol>
</section>
<?php endif; ?>
<?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : ?>
<nav class="rx-comments-navigation rx-comments-navigation-bottom" aria-label="<?php esc_attr_e( 'Comments navigation', 'rx-theme' ); ?>">
<?php
the_comments_pagination(
array(
'prev_text' => esc_html__( 'Previous Comments', 'rx-theme' ),
'next_text' => esc_html__( 'Next Comments', 'rx-theme' ),
'screen_reader_text' => esc_html__( 'Comments pagination', 'rx-theme' ),
'aria_label' => esc_html__( 'Comments pagination', 'rx-theme' ),
'class' => 'rx-comments-pagination',
)
);
?>
</nav>
<?php endif; ?>
<?php endif; ?>
<?php if ( ! $rx_comments_are_open && $rx_comment_count && post_type_supports( get_post_type(), 'comments' ) ) : ?>
<div class="rx-comments-closed">
<p>
<?php esc_html_e( 'Comments are closed for this post.', 'rx-theme' ); ?>
</p>
</div>
<?php endif; ?>
<?php if ( $rx_comments_are_open ) : ?>
<?php
$rx_commenter = wp_get_current_commenter();
$rx_required = get_option( 'require_name_email' );
$rx_req_attr = $rx_required ? ' required="required"' : '';
$rx_req_mark = $rx_required ? ' <span class="required">*</span>' : '';
$rx_fields = array(
'author' =>
'<p class="comment-form-author rx-comment-form-field rx-comment-form-author">' .
'<label for="author">' .
esc_html__( 'Name', 'rx-theme' ) .
wp_kses_post( $rx_req_mark ) .
'</label>' .
'<input id="author" name="author" type="text" value="' . esc_attr( $rx_commenter['comment_author'] ) . '" size="30" maxlength="245" autocomplete="name"' . $rx_req_attr . ' />' .
'</p>',
'email' =>
'<p class="comment-form-email rx-comment-form-field rx-comment-form-email">' .
'<label for="email">' .
esc_html__( 'Email', 'rx-theme' ) .
wp_kses_post( $rx_req_mark ) .
'</label>' .
'<input id="email" name="email" type="email" value="' . esc_attr( $rx_commenter['comment_author_email'] ) . '" size="30" maxlength="100" autocomplete="email" aria-describedby="email-notes"' . $rx_req_attr . ' />' .
'</p>',
'url' =>
'<p class="comment-form-url rx-comment-form-field rx-comment-form-url">' .
'<label for="url">' .
esc_html__( 'Website', 'rx-theme' ) .
'</label>' .
'<input id="url" name="url" type="url" value="' . esc_attr( $rx_commenter['comment_author_url'] ) . '" size="30" maxlength="200" autocomplete="url" />' .
'</p>',
);
if ( has_action( 'set_comment_cookies', 'wp_set_comment_cookies' ) && get_option( 'show_comments_cookies_opt_in' ) ) {
$rx_fields['cookies'] =
'<p class="comment-form-cookies-consent rx-comment-form-field rx-comment-form-cookies">' .
'<input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes" />' .
'<label for="wp-comment-cookies-consent">' .
esc_html__( 'Save my name, email, and website in this browser for the next time I comment.', 'rx-theme' ) .
'</label>' .
'</p>';
}
$rx_comment_form_args = apply_filters(
'rx_theme_comment_form_args',
array(
'fields' => $rx_fields,
'comment_field' =>
'<p class="comment-form-comment rx-comment-form-field rx-comment-form-comment">' .
'<label for="comment">' .
esc_html__( 'Comment', 'rx-theme' ) .
' <span class="required">*</span>' .
'</label>' .
'<textarea id="comment" name="comment" cols="45" rows="8" maxlength="65525" required="required" aria-required="true" placeholder="' . esc_attr__( 'Write your comment here...', 'rx-theme' ) . '"></textarea>' .
'</p>',
'title_reply' => esc_html__( 'Leave a Comment', 'rx-theme' ),
'title_reply_to' => esc_html__( 'Leave a Reply to %s', 'rx-theme' ),
'cancel_reply_link' => esc_html__( 'Cancel Reply', 'rx-theme' ),
'label_submit' => esc_html__( 'Post Comment', 'rx-theme' ),
'comment_notes_before' =>
'<p id="email-notes" class="comment-notes rx-comment-notes">' .
esc_html__( 'Your email address will not be published. Required fields are marked *', 'rx-theme' ) .
'</p>',
'comment_notes_after' =>
'<p class="rx-comment-after-notes">' .
esc_html__( 'Please keep comments respectful, helpful, and related to the article topic.', 'rx-theme' ) .
'</p>',
'class_container' => 'rx-comment-respond comment-respond',
'class_form' => 'rx-comment-form comment-form',
'class_submit' => 'rx-comment-submit submit',
'id_form' => 'rx-commentform',
'id_submit' => 'rx-submit-comment',
'name_submit' => 'submit',
'format' => 'html5',
'submit_button' =>
'<button name="%1$s" type="submit" id="%2$s" class="%3$s">' .
'%4$s' .
'</button>',
'submit_field' =>
'<p class="form-submit rx-form-submit">%1$s %2$s</p>',
)
);
comment_form( $rx_comment_form_args );
?>
<?php endif; ?>
<?php do_action( 'rx_theme_after_comments_area' ); ?>
</section>
Also add this in your functions.php so threaded replies work correctly:
/**
* RX Theme Comment Reply Script
*/
function rx_theme_enqueue_comment_reply_script() {
if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
wp_enqueue_script( 'comment-reply' );
}
}
add_action( 'wp_enqueue_scripts', 'rx_theme_enqueue_comment_reply_script' );
Optional CSS for good design:
/* RX Theme Advanced Comments */
.rx-comments-area {
margin-top: 48px;
padding-top: 32px;
border-top: 1px solid rgba(0, 0, 0, 0.08);
}
.rx-comments-title {
margin: 0 0 8px;
font-size: 28px;
line-height: 1.25;
}
.rx-comments-description {
margin: 0 0 24px;
color: #666;
}
.rx-comments-list,
.rx-pings-list {
margin: 0;
padding: 0;
list-style: none;
}
.rx-comment {
margin: 0 0 24px;
}
.rx-comment-body {
padding: 20px;
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: 12px;
background: #fff;
}
.rx-comment-header {
display: flex;
gap: 14px;
align-items: flex-start;
margin-bottom: 14px;
}
.rx-comment-avatar {
border-radius: 999px;
}
.rx-comment-author {
font-weight: 700;
}
.rx-comment-author-badge {
display: inline-block;
margin-left: 8px;
padding: 2px 8px;
border-radius: 999px;
font-size: 12px;
font-weight: 700;
background: #f1f5f9;
color: #334155;
}
.rx-comment-time-wrap {
margin-top: 4px;
font-size: 13px;
color: #64748b;
}
.rx-comment-permalink {
color: inherit;
text-decoration: none;
}
.rx-comment-content {
margin-top: 12px;
line-height: 1.75;
}
.rx-comment-content p:last-child {
margin-bottom: 0;
}
.rx-comment-awaiting-moderation {
margin: 12px 0;
padding: 10px 12px;
border-radius: 8px;
background: #fff7ed;
color: #9a3412;
font-size: 14px;
}
.rx-comment-footer {
margin-top: 16px;
}
.rx-comment-actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
font-size: 14px;
}
.rx-comment-actions a {
text-decoration: none;
font-weight: 600;
}
.rx-comments-list .children {
margin: 20px 0 0 32px;
padding: 0;
list-style: none;
}
.rx-comments-navigation {
margin: 24px 0;
}
.rx-comments-pagination .page-numbers {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 36px;
height: 36px;
margin: 0 3px;
padding: 0 10px;
border-radius: 8px;
text-decoration: none;
background: #f8fafc;
}
.rx-comments-pagination .page-numbers.current {
font-weight: 700;
background: #e2e8f0;
}
.rx-pings-area {
margin-top: 32px;
}
.rx-ping {
margin-bottom: 10px;
}
.rx-ping-body {
padding: 12px 14px;
border-radius: 8px;
background: #f8fafc;
}
.rx-comment-respond {
margin-top: 40px;
}
.rx-comment-form-field {
margin-bottom: 18px;
}
.rx-comment-form-field label {
display: block;
margin-bottom: 6px;
font-weight: 700;
}
.rx-comment-form input[type="text"],
.rx-comment-form input[type="email"],
.rx-comment-form input[type="url"],
.rx-comment-form textarea {
width: 100%;
padding: 12px 14px;
border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: 10px;
font-size: 16px;
}
.rx-comment-form textarea {
resize: vertical;
}
.rx-comment-submit {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 12px 22px;
border: 0;
border-radius: 10px;
cursor: pointer;
font-weight: 700;
background: #111827;
color: #fff;
}
.rx-comments-closed {
margin: 24px 0;
padding: 14px 16px;
border-radius: 10px;
background: #f8fafc;
color: #475569;
}
@media (max-width: 600px) {
.rx-comment-header {
gap: 10px;
}
.rx-comments-list .children {
margin-left: 16px;
}
.rx-comment-body {
padding: 16px;
}
}
This comments.php is safe to use directly in your RX theme and gives you a strong advanced foundation for comment display, replies, moderation message, pagination, pingbacks, and form customization.