• 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 Customize Standard WordPress Comment Templates in Multi-Language Site Networks

How to Customize Standard WordPress Comment Templates in Multi-Language Site Networks

Understanding WordPress Comment Template Hierarchy

When WordPress renders comments on a post or page, it follows a specific template hierarchy. For single-site installations, the primary template file is comments.php. However, in a multisite network, especially when dealing with different languages, this becomes more nuanced. WordPress looks for templates in a specific order: first in the active theme, then in parent themes, and finally in the core WordPress files. For multisite and multilingual setups, we often need to override these defaults to serve language-specific comment forms and lists.

Leveraging Theme Overrides for Multilingual Comments

The most robust way to customize comment templates for different languages is by creating language-specific template files within your theme. This approach ensures that each language version of your site can have its own distinct comment display and form.

Creating Language-Specific Comment Template Files

Let’s assume you are using a theme that supports internationalization and you have a way to detect the current language (e.g., using a plugin like WPML or Polylang). The standard WordPress function get_comments_template() is responsible for determining which comment template file to load. We can hook into this process to inject our custom logic.

First, identify the language code for the current site or post. If you’re using Polylang, you can get the current language object like this:

// In your theme's functions.php or a custom plugin
add_filter( 'comments_template', 'my_multilingual_comments_template' );

function my_multilingual_comments_template( $file ) {
    // Check if Polylang is active and get the current language
    if ( function_exists( 'pll_current_language' ) ) {
        $current_lang = pll_current_language( 'slug' ); // e.g., 'en', 'fr', 'es'

        // Define a path for language-specific comment templates
        $lang_template_path = get_template_directory() . '/comments/' . $current_lang . '-comments.php';

        // If a language-specific template exists, use it
        if ( file_exists( $lang_template_path ) ) {
            return $lang_template_path;
        }
    }

    // Fallback to the default or a generic template if no language-specific one is found
    // You might want to return a generic 'comments.php' or a specific fallback
    return $file;
}

In this example, we’re looking for files named en-comments.php, fr-comments.php, etc., within a comments/ subdirectory of your active theme. If such a file exists for the current language, it will be loaded instead of the default comments.php.

Structuring Language-Specific Comment Templates

Once you have the filter in place, you need to create the actual template files. For instance, if your current language slug is ‘fr’, you would create wp-content/themes/your-theme/comments/fr-comments.php.

A typical comments.php file contains two main parts: the comment list and the comment form. You’ll want to translate these strings and potentially adjust the structure or fields for each language.

Example: French Comment Template (fr-comments.php)

<?php
/**
 * The template for displaying comments.
 *
 * This file is used to display the comments.
 *
 * @package WordPress
 * @subpackage YourThemeName
 */

// Prevent direct access to the file.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/*
 * If the current post is protected by a password and
 * the visitor has not yet entered the password we will
 * return early without displaying the comments.
 */
if ( post_password_required() ) {
    return;
}
?>

<!-- wp:paragraph -->
<h2 class="comments-title">
    <?php
    $comment_count = get_comments_number();
    if ( 1 === $comment_count ) {
        printf( _x( 'One thought on “%s”', 'comments title', 'your-text-domain' ), get_the_title() );
    } else {
        printf( _n( '%1$s thought on “%2$s”', '%1$s thoughts on “%2$s”', $comment_count, 'your-text-domain' ), number_format_i18n( $comment_count ), get_the_title() );
    }
    ?>
</h2>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ol class="comment-list">
    <?php
    wp_list_comments( array(
        'style'       => 'ol',
        'short_ping'  => true,
        'avatar_size' => 42,
    ) );
    ?>
</ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<div class="comment-navigation">
    <?php previous_comments_link( esc_html__( '← Older Comments', 'your-text-domain' ) ); ?>
    <?php next_comments_link( esc_html__( 'Newer Comments →', 'your-text-domain' ) ); ?>
</div>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<?php
// If comments are closed and there are no comments, let's leave the comment form hidden.
if ( ! comments_open() && get_comments_number() ) :
?>
    <p class="no-comments"><?php esc_html_e( 'Comments are closed.', 'your-text-domain' ); ?></p>
<?php endif; ?>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<?php
comment_form( array(
    'title_reply_before' => '<h3 id="reply-title" class="comment-reply-title">',
    'title_reply_after'  => '</h3>',
    'title_reply'        => esc_html__( 'Leave a Reply', 'your-text-domain' ), // French: 'Laisser une réponse'
    'comment_notes_before' => '<p class="comment-notes"><span id="email-notes">' . esc_html__( 'Your email address will not be published.', 'your-text-domain' ) . '</span> <span class="required">' . esc_html__( 'Required fields are marked', 'your-text-domain' ) . '</span>',
    'comment_notes_after'  => '<span class="form-allowed-tags">' . sprintf( esc_html__( '%s', 'your-text-domain' ), 'You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes: %s.' ) . '</span></p>',
    'fields'             => array(
        'author' => '<p class="comment-form-author"><label for="author">' . esc_html__( 'Name', 'your-text-domain' ) . '</label><span class="required">*</span><input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30" aria-required="true" /></p>',
        'email'  => '<p class="comment-form-email"><label for="email">' . esc_html__( 'Email', 'your-text-domain' ) . '</label><span class="required">*</span><input id="email" name="email" type="email" value="' . esc_attr( $commenter['comment_author_email'] ) . '" size="30" aria-required="true" /></p>',
        'url'    => '<p class="comment-form-url"><label for="url">' . esc_html__( 'Website', 'your-text-domain' ) . '</label><input id="url" name="url" type="url" value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" /></p>',
    ),
    'comment_field'      => '<p class="comment-form-comment"><label for="comment">' . esc_html__( 'Comment', 'your-text-domain' ) . '</label><textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea></p>',
) );
?>
<!-- /wp:paragraph -->

Key points for translation:

  • Text Domain: Ensure your theme has a unique text domain (e.g., your-text-domain) and that all translatable strings are wrapped in WordPress translation functions like esc_html__(), esc_html_e(), _x(), and _n().
  • Comment Count Title: The title displaying the number of comments is translated using _x() and _n().
  • Comment Navigation: Links for older and newer comments are translated.
  • Comment Form Fields: Labels for Name, Email, Website, and the comment textarea itself are translated.
  • Comment Form Titles: The “Leave a Reply” title and introductory notes are translated.

Handling Multisite Network and Subdirectories/Subdomains

In a multisite network, each site can have its own language settings. The filter function we defined earlier using pll_current_language() works well if Polylang is configured to assign a unique language slug to each site in the network. If you are using different themes per site or have a complex multisite setup, you might need to adjust the path to the template file.

For instance, if you need to get the template path relative to the network’s shared theme directory (if applicable) or based on the current site ID, you would modify the path construction:

add_filter( 'comments_template', 'my_multilingual_comments_template_multisite' );

function my_multilingual_comments_template_multisite( $file ) {
    $current_site_id = get_current_blog_id();
    $current_lang = '';

    // Example: Using Polylang's site-specific language detection
    if ( function_exists( 'PLL' ) && PLL()->options->get_option( 'force_lang_in_slug' ) ) {
        // If language is forced in slug, it's usually part of the URL or site settings
        // This might require more complex logic depending on Polylang's network setup
        // For simplicity, let's assume we can get a language slug per site
        $current_lang = get_blog_option( $current_site_id, 'pll_language' ); // This might not be directly available, check Polylang docs
    } elseif ( function_exists( 'pll_current_language' ) ) {
        // Fallback to current request language if site-specific isn't easily found
        $current_lang = pll_current_language( 'slug' );
    }

    if ( ! empty( $current_lang ) ) {
        // Option 1: Theme-specific directory (as before)
        $lang_template_path_theme = get_template_directory() . '/comments/' . $current_lang . '-comments.php';
        if ( file_exists( $lang_template_path_theme ) ) {
            return $lang_template_path_theme;
        }

        // Option 2: Network-wide theme directory (if using a shared theme)
        // Note: This path might vary based on your multisite configuration
        $network_theme_dir = trailingslashit( WP_CONTENT_DIR ) . 'mu-plugins/themes/your-shared-theme/comments/' . $current_lang . '-comments.php';
        if ( file_exists( $network_theme_dir ) ) {
            return $network_theme_dir;
        }
    }

    // Fallback to the default
    return $file;
}

The logic for detecting the language in a multisite environment can be complex and depends heavily on how your multilingual plugin is configured. Always test thoroughly on each site within your network.

Alternative: Using a Single Template with Conditional Logic

For simpler multilingual sites or if you prefer to manage a single comments.php file, you can use conditional logic within that file to display language-specific strings or even modify the form fields. This is less maintainable for significant structural changes but can work for minor text adjustments.

// Inside your theme's comments.php
<?php
// ... (previous code)

// Get current language
$current_lang = '';
if ( function_exists( 'pll_current_language' ) ) {
    $current_lang = pll_current_language( 'slug' );
}

// Dynamically set form titles and text based on language
$comment_form_args = array(
    'title_reply' => ( 'fr' === $current_lang ) ? esc_html__( 'Laisser une réponse', 'your-text-domain' ) : esc_html__( 'Leave a Reply', 'your-text-domain' ),
    'comment_notes_before' => ( 'fr' === $current_lang ) ? '<p class="comment-notes"><span id="email-notes">' . esc_html__( 'Votre adresse e-mail ne sera pas publiée.', 'your-text-domain' ) . '</span> <span class="required">' . esc_html__( 'Les champs obligatoires sont marqués', 'your-text-domain' ) . '</span>' : '<p class="comment-notes"><span id="email-notes">' . esc_html__( 'Your email address will not be published.', 'your-text-domain' ) . '</span> <span class="required">' . esc_html__( 'Required fields are marked', 'your-text-domain' ) . '</span>',
    // ... other arguments
);

comment_form( $comment_form_args );

// ... (rest of the code)
?>

This method relies heavily on the translation functions and the language detection mechanism. While it keeps your theme cleaner by having fewer files, it can make the comments.php file quite lengthy and harder to manage if the differences between languages are substantial.

Best Practices and Considerations

  • Theme Updates: If you’re modifying a parent theme’s comments.php directly, your changes will be lost on theme updates. Always use a child theme or a custom plugin for your modifications.
  • Performance: Ensure your language detection logic is efficient. Avoid unnecessary database queries within the filter.
  • Caching: Be mindful of WordPress caching plugins. Ensure that language-specific comment templates are served correctly and not cached incorrectly. You might need to clear cache after making changes or configure cache exclusion rules.
  • User Experience: Test the comment form and display on different devices and browsers for each language to ensure a consistent and positive user experience.
  • Accessibility: Ensure all translated strings and form elements adhere to accessibility standards (WCAG).

By implementing language-specific comment templates, you can provide a more tailored and user-friendly experience for your international audience, ensuring that comments and discussions on your WordPress multisite network are as effective as possible across all languages.

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