How to Build Standard WordPress Comment Templates in Multi-Language Site Networks
Understanding WordPress Comment Template Hierarchy
When developing for WordPress, especially for multi-language sites, understanding how templates are loaded is paramount. The comment template, primarily handled by comments.php, is no exception. WordPress follows a specific hierarchy to find the correct template file. For comments, it first looks for comments-{$post_type}.php, then comments.php in the active theme’s directory. If neither is found, it falls back to the default WordPress comments template.
For multi-language sites, particularly those using a plugin like WPML or Polylang, the challenge arises in serving localized comment templates. Simply having a single comments.php won’t suffice if you need distinct comment structures or even just localized strings within the comment form and display for different languages.
Leveraging Theme Structure for Localization
The most robust approach for multi-language comment templates is to integrate localization directly into your theme’s file structure and template loading logic. This involves creating language-specific template files and conditionally loading them based on the current language context.
Creating Language-Specific Comment Templates
Let’s assume you’re using a theme named “MyTheme” and you need to support English (‘en_US’) and German (‘de_DE’). You can create specific comment template files within your theme directory. The naming convention can be arbitrary, but a clear pattern is essential. A common practice is to prefix them with the language code.
Inside your theme’s root directory (wp-content/themes/MyTheme/), you would create files like:
comments-en_US.phpcomments-de_DE.php
You would also maintain a generic comments.php as a fallback or for languages not explicitly handled.
Conditional Template Loading with PHP
The core of serving the correct template lies in conditionally loading the appropriate file. This is typically done within your theme’s index.php, single.php, or any template file that calls comments_template(). The comments_template() function accepts an optional argument, $file, which allows you to specify a custom template file to load.
We can hook into the comments_template filter to dynamically alter the file path based on the current language.
Implementing the Filter in functions.php
Add the following code to your theme’s functions.php file. This code checks the current language and appends the appropriate suffix to the default comment template name.
/**
* Dynamically load language-specific comment templates.
*
* @param string $file The default comment template file path.
* @return string The modified comment template file path.
*/
function mytheme_load_localized_comment_template( $file ) {
// Get the current language code.
// This assumes you are using a plugin like WPML or Polylang.
// Adjust the function call based on your specific multilingual plugin.
$current_language = '';
if ( defined( 'ICL_LANGUAGE_CODE' ) ) { // WPML
$current_language = ICL_LANGUAGE_CODE;
} elseif ( function_exists( 'pll_current_language' ) ) { // Polylang
$current_language = pll_current_language( 'locale' ); // Use locale for better matching (e.g., en_US)
if ( empty( $current_language ) ) {
$current_language = pll_current_language( 'slug' ); // Fallback to slug if locale is not set
}
}
// If a language is detected and a specific template exists, use it.
if ( ! empty( $current_language ) ) {
$theme_dir = get_template_directory();
$localized_template = trailingslashit( $theme_dir ) . 'comments-' . $current_language . '.php';
if ( file_exists( $localized_template ) ) {
return $localized_template;
}
}
// Fallback to the default comments.php if no specific template is found or no language is detected.
return $file;
}
add_filter( 'comments_template', 'mytheme_load_localized_comment_template' );
Explanation:
- The function
mytheme_load_localized_comment_templateis hooked into thecomments_templatefilter. - It first attempts to detect the current language code. The example includes checks for WPML (
ICL_LANGUAGE_CODE) and Polylang (pll_current_language()). You might need to adapt this part based on the specific multilingual plugin you are using. Polylang’spll_current_language('locale')is preferred as it often provides a more precise match (e.g.,en_US) compared to just the language slug (e.g.,en). - If a language code is found, it constructs the path to a potential language-specific comment template (e.g.,
/wp-content/themes/MyTheme/comments-de_DE.php). - It checks if this file actually exists using
file_exists(). - If the file exists, its path is returned, and WordPress will load it.
- If no language is detected or the specific template file doesn’t exist, the original path (usually
comments.php) is returned, ensuring a fallback mechanism.
Structuring Language-Specific Comment Content
Once you have your language-specific template files (e.g., comments-en_US.php, comments-de_DE.php), you need to populate them with localized content. This includes:
- Localized strings for “Leave a Reply”, “Comments are closed”, “Comment”, “Post Comment”, etc.
- Potentially different HTML structures or styling for comments in different languages, though this is less common.
The best practice for localizing strings within PHP files is to use WordPress’s internationalization functions, such as __(), _e(), and _n(). These functions mark strings for translation and allow them to be compiled into translation files (.po and .mo). Make sure your theme has a text domain defined and that you’ve generated the necessary translation files.
Example: comments-de_DE.php
Here’s a simplified example of what comments-de_DE.php might look like, assuming your theme’s text domain is “mytheme”:
<?php
/**
* The template for displaying comments.
*
* @package MyTheme
*/
if ( post_password_required() ) {
return;
}
?>
<div id="comments" class="comments-area">
<?php // You can start listing comments here. ?>
<?php if ( have_comments() ) : ?>
<h2 class="comments-title">
<?php
printf( _nx( 'Ein Kommentar zu “%1$s”', '%1$s Kommentare zu “%2$s”', get_comments_number(), 'comments title', 'mytheme' ),
number_format_i18n( get_comments_number() ), get_the_title() );
?>
</h2>
<ol class="comment-list">
<?php
wp_list_comments( array(
'style' => 'ol',
'short_ping' => true,
'avatar_size' => 56,
) );
?>
</ol><!-- .comment-list -->
<?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : ?>
<nav id="comment-nav-below" class="navigation comment-navigation" role="navigation">
<h1 class="screen-reader-text"><?php _e( 'Comment navigation', 'mytheme' ); ?></h1>
<div class="nav-previous"><?php previous_comments_link( __( '← Older Comments', 'mytheme' ) ); ?></div>
<div class="nav-next"><?php next_comments_link( __( 'Newer Comments →', 'mytheme' ) ); ?></div>
</nav><!-- #comment-nav-below -->
<?php endif; // End check for comment navigation ?>
<?php endif; // End if have_comments() ?>
<?php
// If comments are closed and there is still some comment, let's leave a note.
if ( ! comments_open() && get_comments_number() && post_type_supports( get_post_type(), 'comments' ) ) :
?>
<p class="no-comments"><?php _e( 'Comments are closed.', 'mytheme' ); ?></p>
<?php endif; ?>
<?php
comment_form( array(
'title_reply' => __( 'Hinterlassen Sie eine Antwort', 'mytheme' ),
'title_reply_to' => __( 'Antworten Sie an %s', 'mytheme' ),
'comment_notes_before' => '<p class="comment-notes">' . __( 'Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert.', 'mytheme' ) . '</p>',
'comment_notes_after' => '',
'fields' => array(
'author' => '<p class="comment-form-author">' .
'<label for="author">' . __( 'Name', 'mytheme' ) . '</label><span class="required">*</span>' .
'<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . ' /></p>',
'email' => '<p class="comment-form-email">' .
'<label for="email">' . __( 'Email', 'mytheme' ) . '</label><span class="required">*</span>' .
'<input id="email" name="email" type="text" value="' . esc_attr( $commenter['comment_author_email'] ) . '" size="30"' . $aria_req . ' /></p>',
'url' => '<p class="comment-form-url">' .
'<label for="url">' . __( 'Website', 'mytheme' ) . '</label>' .
'<input id="url" name="url" type="text" value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" /></p>',
),
'comment_field' => '<p class="comment-form-comment">' .
'<label for="comment">' . __( 'Kommentar', 'mytheme' ) . '</label><br />' .
'<textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea>' .
'</p>',
) );
?>
</div><!-- #comments -->
In this German example:
- The comment count title uses German phrasing: “Ein Kommentar zu…” or “Kommentare zu…”.
- Navigation links are translated: “Older Comments” becomes “Ältere Kommentare”.
- The comment form fields and labels are in German.
- The
comment_form()function is customized to provide German text for the reply title, notes, and field labels.
Handling Different Comment Form Structures
While less common, you might need to alter the structure of the comment form itself for different languages. For instance, you might want to reorder fields, add or remove specific input fields, or change the submit button text. The comment_form() function in WordPress is highly customizable via its array of arguments.
You can modify the fields argument within your language-specific template files to achieve this. For example, in comments-de_DE.php, you could rearrange the order of author, email, and URL fields, or even remove the URL field if desired.
Customizing comment_form() Arguments
The comment_form() function accepts an array of arguments. You can pass different arrays to this function within your language-specific templates. For example, to remove the website field for German users:
// Inside comments-de_DE.php
$args = array(
'title_reply' => __( 'Hinterlassen Sie eine Antwort', 'mytheme' ),
'comment_notes_before' => '<p class="comment-notes">' . __( 'Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert.', 'mytheme' ) . '</p>',
'fields' => array(
'author' => '<p class="comment-form-author">' .
'<label for="author">' . __( 'Name', 'mytheme' ) . '</label><span class="required">*</span>' .
'<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . ' /></p>',
'email' => '<p class="comment-form-email">' .
'<label for="email">' . __( 'Email', 'mytheme' ) . '</label><span class="required">*</span>' .
'<input id="email" name="email" type="text" value="' . esc_attr( $commenter['comment_author_email'] ) . '" size="30"' . $aria_req . ' /></p>',
// 'url' field is omitted here
),
'comment_field' => '<p class="comment-form-comment">' .
'<label for="comment">' . __( 'Kommentar', 'mytheme' ) . '</label><br />' .
'<textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea>' .
'</p>',
);
comment_form( $args );
Considerations for Site Networks (Multisite)
In a WordPress Multisite installation, each site within the network can have its own theme or a different theme activated. If your multi-language strategy involves having different languages on different sub-sites (e.g., site1.com/en/ and site1.com/de/), the approach described above still holds. The comments_template() filter will be applied on a per-site basis.
However, if you are using a single theme across all sites in the network and relying solely on a multilingual plugin for language switching, the functions.php filter method is sufficient. The key is that the multilingual plugin correctly identifies the current language context for each request.
Theme Compatibility and Plugin Integration
Ensure your chosen multilingual plugin (WPML, Polylang, etc.) is compatible with your theme and that its language detection functions are correctly implemented in your functions.php. Test thoroughly on each sub-site if you are using Multisite.
For advanced scenarios, you might consider using theme options or customizer settings to allow users to select comment template variations per language, but this adds significant complexity. The file-based approach with conditional loading is generally the most maintainable for standard WordPress theme development.