• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » How to Build Standard WordPress Comment Templates for Premium Gutenberg-First Themes

How to Build Standard WordPress Comment Templates for Premium Gutenberg-First Themes

Understanding WordPress Comment Template Hierarchy

When WordPress renders comments on a post or page, it follows a specific template hierarchy. For standard comment display, the primary file is comments.php. However, if this file is not present, WordPress falls back to index.php or other parent theme files. For Gutenberg-first themes, which often rely heavily on block-based rendering, explicitly defining a comments.php file is crucial for consistent comment display, especially when users might disable Gutenberg for comment sections or when using custom comment layouts.

Creating a Basic comments.php File

A minimal comments.php file needs to check if there are any comments to display and then loop through them. It also needs to include the comment form. Here’s a foundational structure:

// Prevent direct access
if ( ! post_password_required() ) {
     $comments_args  = array(
        'title_reply' => 'Leave a Reply',
        'title_reply_to' => 'Reply to %s',
        'cancel_reply_link' => 'Cancel reply',
        'label_submit' => 'Post Comment',
    );
    comment_form(  $comments_args  );
}

if ( have_comments() ) { // Check if there are comments
    // Comment list
    the_title( '<h2 class="comments-title">', '</h2>' );
    wp_list_comments( 
        'style' => 'ol',
        'short_ping' => true
     );

    // Pagination if needed
    if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) {
        the_comments_pagination( 
            'prev_text' => '&larr; Previous',
            'next_text' => 'Next &rarr;'
         );
    }
}

// Display comments closed notice if applicable
if ( ! comments_open() && get_comments_number() && ! // Check if comments are closed but there are existing comments
    // This is commented out because we usually want to show the form even if closed, to allow admin comments.
    // echo '<p class="no-comments">' . __( 'Comments are closed.' ) . '</p>';
}

Customizing the Comment Form

The comment_form() function is highly customizable. You can modify labels, add custom fields, and control the form’s structure. For a Gutenberg-first theme, you might want to ensure the form aligns with your block editor’s styling. You can pass an array of arguments to comment_form() to achieve this.

Here’s an example of how to add a custom field (e.g., a website URL, though WordPress has a default one) and modify the submit button’s class:

 $comments_args  = array(
    'title_reply' => 'Join the Conversation',
    'title_reply_before' => '<h3 id="reply-title" class="comment-reply-title">',
    'title_reply_after' => '</h3>',
    'cancel_reply_link' => 'Cancel Reply',
    'label_submit' => 'Send My Comment',
    'submit_button' => '<input name="submit" type="submit" id="submit" class="submit button button-primary" value="%1$s" />',
    'comment_field' => '<p class="comment-form-comment"><textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea></p>',
    'fields' => 
        'author' => '<p class="comment-form-author"><input id="author" name="author" type="text" value="' . esc_attr( get_comment_author_link() ) . '" size="30"' . ( current_user_can( 'comment_author_email' ) ? '' : 'required="required"' ) . '></p>',
        'email' => '<p class="comment-form-email"><input id="email" name="email" type="email" value="' . esc_attr( get_comment_author_email() ) . '" size="30"' . ( current_user_can( 'comment_author_email' ) ? '' : 'required="required"' ) . '></p>',
        'url' => '<p class="comment-form-url"><input id="url" name="url" type="url" value="' . esc_attr( get_comment_author_url() ) . '" size="30" /></p>',
    
);

comment_form(  $comments_args  );

Styling Comments with CSS

The output of wp_list_comments() and comment_form() generates HTML that you can style using CSS. For a Gutenberg-first theme, you’ll want to ensure these styles are consistent with your block editor’s visual language. Enqueue a dedicated stylesheet for your theme’s comments in your functions.php file.

// In functions.php
function my_theme_enqueue_comment_styles() {
    if ( is_singular() && ( comments_open() || get_comments_number() ) ) {
        wp_enqueue_style(
            'my-theme-comments',
            get_template_directory_uri() . '/css/comments.css',
            array(),
            '1.0'
        );
    }
}
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_comment_styles' );

Then, in your css/comments.css file, you can target elements like:

.comments-title {
    font-size: 1.8em;
    margin-bottom: 1em;
    border-bottom: 1px solid #eee;
    padding-bottom: 0.5em;
}

.comment-list {
    list-style: none;
    padding-left: 0;
    margin-bottom: 2em;
}

.comment-list li {
    margin-bottom: 1.5em;
    padding-bottom: 1.5em;
    border-bottom: 1px solid #eee;
}

.comment-list .avatar {
    float: left;
    margin-right: 15px;
    border-radius: 50%;
}

.comment-author {
    font-weight: bold;
    margin-bottom: 0.5em;
}

.comment-meta {
    font-size: 0.9em;
    color: #777;
    margin-bottom: 0.5em;
}

.comment-content {
    clear: both;
    line-height: 1.6;
}

.comment-reply-link {
    display: inline-block;
    margin-top: 0.5em;
    padding: 5px 10px;
    background-color: #f0f0f0;
    border-radius: 3px;
    text-decoration: none;
    color: #333;
}

/* Comment Form Styling */
.comment-form {
    margin-top: 2em;
    padding: 2em;
    background-color: #f9f9f9;
    border: 1px solid #eee;
    border-radius: 5px;
}

.comment-form label {
    display: block;
    margin-bottom: 0.5em;
    font-weight: bold;
}

.comment-form input[type="text"],
.comment-form input[type="email"],
.comment-form input[type="url"],
.comment-form textarea {
    width: 100%;
    padding: 10px;
    margin-bottom: 1em;
    border: 1px solid #ccc;
    border-radius: 3px;
    box-sizing: border-box; /* Important for consistent sizing */
}

.comment-form .submit {
    background-color: #0073aa;
    color: #fff;
    border: none;
    padding: 10px 20px;
    cursor: pointer;
    border-radius: 3px;
}

.comment-form .submit:hover {
    background-color: #005177;
}

.comment-form p.comment-form-cookies-consent {
    margin-top: 1em;
    font-size: 0.9em;
    color: #555;
}

Advanced: Customizing wp_list_comments() Callback

For complete control over how each comment is displayed, you can define a custom callback function for wp_list_comments(). This is where you can integrate custom HTML structures, conditionally display elements, or even use block-like rendering for individual comments.

First, define your callback function in functions.php:

function my_theme_comment_callback(  $comment,  $args,  $depth ) {
     $GLOBALS['comment'] =  $comment;
     $tag = (  $args['style'] === 'ol' ) ? 'li' : 'div';
     $classes = '';
    if (  $comment->comment_approved == '0' ) {
         $classes .= ' pending-comment';
    }
     $classes .= ' comment';
     $classes .= ' depth-' .  $depth;
     $classes .= ' comment-author-' . get_comment_author();
     $classes .= ' comment-by-post-author'; // Add class if comment author is post author
    if (  $comment->user_id ===  $comment->post_author ) {
         $classes .= ' post-author-comment';
    }
    ?>
    <?php if (  $comment->comment_approved == '0' ) : ?>
        <em><?php _e( 'Your comment is awaiting moderation.' ); ?></em><br />
    <?php endif; ?>
    <?php switch (  $comment->comment_type ) :
        case '' :
    ?>
    <?php if ( (  $comment->user_id ) && (  $comment->user_id ==  $comment->post_author ) ) : ?>
        <li id="comment-<?php comment_ID(); ?>" class="<?php echo  $classes; ?>">
    <?php else : ?>
        <li id="comment-<?php comment_ID(); ?>" class="<?php echo  $classes; ?>">
    <?php endif; ?>

        <div class="comment-author-vcard">
            <?php echo get_avatar( $comment, 50 ); ?>
            <?php printf( '<cite class="fn">%s</cite>', get_comment_author_link() ); ?>
        </div><!-- .comment-author-vcard -->

        <div class="comment-meta commentmetadata">
            <a href="<?php echo esc_url( get_comment_link() ); ?>">
                <time datetime="<?php comment_date('c'); ?>">
                    <?php printf( '%1$s at %2$s', get_comment_date(), get_comment_time() ); ?>
                </time>
            </a>
            <?php edit_comment_link( __( '(Edit)' ), '  ', '' ); ?>
        </div><!-- .comment-meta -->

        <div class="comment-body">
            <?php comment_text(); ?>
            <div class="reply">
                <?php comment_reply_link( array_merge( $args, array( 'add_below' => 'comment', 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
            </div><!-- .reply -->
        </div><!-- .comment-body -->

    <?php break;
        case 'pingback' :
        case 'trackback' :
    ?>
        <li id="comment-<?php comment_ID(); ?>" class="<?php echo  $classes; ?>">
            <?php _e( 'Trackback:' ); ?> <?php comment_author_link(); ?>
    <?php
        break;
    endswitch;
    ?>
    <?php if (  $tag === 'div' ) : ?>
        <div></div>
    <?php endif;
}

Then, in your comments.php file, you’ll call wp_list_comments() with your custom callback:

if ( have_comments() ) {
    the_title( '<h2 class="comments-title">', '</h2>' );
    <?php // Use the custom callback
    wp_list_comments( 
        'style' => 'ol',
        'callback' => 'my_theme_comment_callback'
     );
    ?>

    // Pagination
    if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) {
        the_comments_pagination( 
            'prev_text' => '&larr; Previous',
            'next_text' => 'Next &rarr;'
         );
    }
}

comment_form(); // Using default arguments here for brevity, but can pass $comments_args as before

Integrating with Gutenberg

While Gutenberg excels at content creation, comment sections are traditionally handled by PHP templates. For a truly Gutenberg-first theme, consider how comments interact with your block system. You might:

  • Use a “Comments” block in your theme’s single post template to dynamically insert the comment section. This block would essentially render the content of your comments.php file.
  • Provide a “Comment Form” block that allows users to customize the form’s appearance and fields within the Site Editor.
  • Ensure your CSS for comments is compatible with the editor’s preview, so styles applied in comments.css are visible in the Gutenberg editor.

By providing a robust comments.php and leveraging custom callbacks and CSS, you can ensure a consistent and well-styled comment experience that complements your Gutenberg-first theme’s design.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Go Goroutines vs. Node.js Event Loop: Scaling I/O-Bound Microservices Under High Load
  • Elixir Phoenix vs. Go Gin: Concurrency Models and Fault Tolerance Under Peak Request Volume
  • Python Celery vs. Go Channels: Distributed Task Queue Overhead and Memory Reliability
  • Scala Pekko vs. Go Goroutines: Actor Model vs. CSP for Event-Driven Reactive Systems
  • Java Loom Virtual Threads vs. Go Goroutines: Under-the-Hood Scheduler and Thread Overhead Comparison

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (584)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (806)
  • PHP (5)
  • PHP Development (21)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (19)
  • Ruby on Rails (1)
  • Security & Compliance (543)
  • SEO & Growth (491)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (7)
  • WordPress Theme Development (357)

Recent Posts

  • Go Goroutines vs. Node.js Event Loop: Scaling I/O-Bound Microservices Under High Load
  • Elixir Phoenix vs. Go Gin: Concurrency Models and Fault Tolerance Under Peak Request Volume
  • Python Celery vs. Go Channels: Distributed Task Queue Overhead and Memory Reliability

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (806)
  • Debugging & Troubleshooting (584)
  • Security & Compliance (543)
  • SEO & Growth (491)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala