2026年5月20日
2026年5月20日
WordPressのコメント表示をカスタマイズする方法|wp_list_commentsのコールバックとcomment_form
WordPress のコメント欄は、クラシックテーマでは comments.php テンプレートと、コメントの一覧を出す wp_list_comments()、入力欄を出す comment_form() で作られています。wp_list_comments() にコールバック関数を渡すと、コメント1件ごとの HTML を自由に組み立てられます。この記事の関数と引数は、2026年11月時点で developer.wordpress.org の関数リファレンスと WordPress のソースコード(wp-includes/comment-template.php、class-walker-comment.php)で確認したものです。
ブロックテーマ(Twenty Twenty-Two 以降の標準テーマなど)では comments.php は使われず、サイトエディターの「コメント」ブロックで表示を組み立てます。この記事はクラシックテーマ向けです。テーマのファイルを直接書き換えると更新で消えるので、子テーマで作業してください。
comments.php の基本形
単一の投稿のテンプレート(single.php など)で comments_template() を呼ぶと、テーマの comments.php が読み込まれます。次は、コールバック関数を使う場合の基本形です。
<?php
// comments.php
// パスワード保護された投稿で、パスワードがまだ入力されていなければ何も出さない
if ( post_password_required() ) {
return;
}
?>
<div id="comments" class="comments-area">
<?php if ( have_comments() ) : ?>
<h2 class="comments-title">
<?php comments_number( 'コメントはまだありません', '1件のコメント', '%件のコメント' ); ?>
</h2>
<ol class="comment-list">
<?php
wp_list_comments(
array(
'style' => 'ol',
'callback' => 'mytheme_comment',
'avatar_size' => 48,
)
);
?>
</ol>
<?php
the_comments_pagination(
array(
'prev_text' => '前のコメント',
'next_text' => '次のコメント',
)
);
?>
<?php endif; ?>
<?php if ( ! comments_open() && get_comments_number() ) : ?>
<p class="no-comments">この投稿へのコメントは受け付けていません。</p>
<?php endif; ?>
<?php comment_form( mytheme_comment_form_args() ); ?>
</div>
comments_number()の3つの引数は、コメントが0件・1件・2件以上のときの文言です。%が件数に置き換わります。the_comments_pagination()は、「設定 → ディスカッション」でコメントをページに分ける設定にしているときだけリンクを出します。1ページあたりの件数も同じ画面で決めます。comment_form()は、コメントを受け付けていない投稿では何も出しません。
コメント1件ごとの HTML をコールバックで作る
wp_list_comments() の callback に渡した関数は、コメント1件ごとに ( $comment, $args, $depth ) の3つの引数で呼ばれます。開始タグ(<li> など)はこの関数で出しますが、閉じタグは書きません。子のコメント(返信)を出し終わった後に、WordPress が </li> を付けます。
<?php
// functions.php
function mytheme_comment( $comment, $args, $depth ) {
$tag = ( 'div' === $args['style'] ) ? 'div' : 'li';
// ピンバック・トラックバックは簡単な1行にする
if ( in_array( $comment->comment_type, array( 'pingback', 'trackback' ), true ) ) {
?>
<<?php echo $tag; ?> id="comment-<?php comment_ID(); ?>" <?php comment_class( 'pingback', $comment ); ?>>
<div class="comment-body">ピンバック: <?php comment_author_link( $comment ); ?></div>
<?php
return;
}
$post = get_post( $comment->comment_post_ID );
$is_post_author = $post && $comment->user_id && (int) $comment->user_id === (int) $post->post_author;
$parent_class = empty( $args['has_children'] ) ? '' : 'parent';
?>
<<?php echo $tag; ?> id="comment-<?php comment_ID(); ?>" <?php comment_class( $parent_class, $comment ); ?>>
<article id="div-comment-<?php comment_ID(); ?>" class="comment-body">
<header class="comment-meta">
<div class="comment-author vcard">
<?php
if ( 0 !== (int) $args['avatar_size'] ) {
echo get_avatar( $comment, $args['avatar_size'] );
}
?>
<span class="fn"><?php comment_author_link( $comment ); ?></span>
<?php if ( $is_post_author ) : ?>
<span class="post-author-badge">投稿者</span>
<?php endif; ?>
</div>
<a class="comment-date" href="<?php echo esc_url( get_comment_link( $comment ) ); ?>">
<time datetime="<?php comment_time( 'c' ); ?>">
<?php comment_date( 'Y年n月j日', $comment ); ?> <?php comment_time( 'H:i' ); ?>
</time>
</a>
<?php if ( '0' === $comment->comment_approved ) : ?>
<p class="comment-awaiting-moderation">このコメントは承認待ちです。</p>
<?php endif; ?>
</header>
<div class="comment-content">
<?php comment_text(); ?>
</div>
<?php
comment_reply_link(
array_merge(
$args,
array(
'add_below' => 'div-comment',
'depth' => $depth,
'max_depth' => $args['max_depth'],
'before' => '<div class="reply">',
'after' => '</div>',
)
)
);
?>
</article>
<?php
// </li> は書かない(WordPress が付ける)
}
コードのポイントは次のとおりです。
- 返信リンク:
comment_reply_link()のadd_belowと、本文を囲む要素のid(div-comment-コメントID)の前半をそろえます。返信をクリックしたときに、入力欄がこの要素の下へ移動します。max_depthは「設定 → ディスカッション」のスレッド(入れ子)形式のコメントの設定で決めた階層の深さで、その深さに達したコメントには返信リンクが出ません。 - 投稿者の目印: 投稿者本人がログインして書いたコメントには、
comment_class()がbypostauthorというクラスを自動で付けます。見た目を変えるだけなら CSS で.bypostauthor > .comment-body { … }のように指定できます。上の例では、文字の目印も出すために、コメントのユーザー ID と投稿の作者 ID を整数にそろえて比べています(データベースから読んだ値は文字列なので、そのまま===で比べると一致しません)。 - 承認待ち:
comment_approvedは文字列の'0'で、承認待ちのコメントは書いた本人のブラウザーにだけ表示されます。 - アバター:
avatar_sizeに0を指定するとアバターを出さないようにしています。「設定 → ディスカッション」でアバターの表示を止めている場合は、get_avatar()は何も返しません。
返信用のスクリプトを読み込む
返信リンクをクリックしたときに入力欄をそのコメントの下へ動かすには、WordPress に含まれている comment-reply スクリプトを読み込みます。クラシックテーマでは、テーマ側で読み込む必要があります。
<?php
// functions.php
add_action( 'wp_enqueue_scripts', function () {
if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
wp_enqueue_script( 'comment-reply' );
}
} );
読み込まれていない場合でも返信はできますが、ページが再読み込みされ、入力欄はページの下のままになります。
コメントフォームの文言を変える
comment_form() に配列で引数を渡すと、見出しやボタンの文言を変えられます。comments.php で使った mytheme_comment_form_args() の例です。
<?php
// functions.php
function mytheme_comment_form_args() {
return array(
'title_reply' => 'コメントを書く',
'title_reply_to' => '%s さんへの返信', // %s は返信先の名前
'cancel_reply_link' => '返信をやめる',
'label_submit' => 'コメントを送信',
'comment_notes_before' => '<p class="comment-notes">メールアドレスは公開されません。</p>',
'comment_field' => '<p class="comment-form-comment"><label for="comment">コメント</label><textarea id="comment" name="comment" cols="45" rows="6" maxlength="65525" required></textarea></p>',
);
}
// 「サイト」の入力欄を消す
add_filter( 'comment_form_default_fields', function ( $fields ) {
unset( $fields['url'] );
return $fields;
} );
- 名前とメールアドレスの欄は、
fieldsで丸ごと置き換えるより、上のようにcomment_form_default_fieldsフィルターで必要なものだけを消したり変えたりするほうが安全です。標準の欄には、前に入力した名前やメールアドレスを入れておくvalueや、必須かどうかの表示が組み込まれているためです。 - 入力欄の
name属性(author、email、url、comment)は変えないでください。WordPress はこの名前で値を受け取ります。 - 「次回のコメントで使用するためブラウザーに自分の名前、メールアドレス、サイトを保存する。」のチェックボックスは、「設定 → ディスカッション」で表示する設定にしているときに出ます。
fieldsを渡した場合も、この欄が無ければ WordPress が付け足します。
入力欄を追加して、その値を保存・表示する方法は「WordPressのコメントフォームをカスタマイズする方法」で説明しています。
表示を確かめる
- コメントを受け付けている投稿で、ログアウトした状態とログインした状態の両方からコメントを書き、一覧と承認待ちの表示を確認します。
- 返信リンクをクリックし、入力欄がそのコメントの下に移動するか、「返信をやめる」で元に戻るかを確かめます。
- 投稿者のアカウントでコメントし、目印が出るかを確かめます。
- 「設定 → ディスカッション」でコメントをページに分ける設定にし、ページ送りのリンクが出るかを確かめます。
関連する記事
comments.phpの全体の構成と、コメント欄の表示条件は「WordPressのコメントテンプレート(comments.php)をカスタマイズする方法」でも説明しています。- スパムコメントへの対策は「WordPressのコメントスパム対策」を参考にしてください。