WordPress’s comment_form() function renders the complete comment submission form — including the name, email, website, and comment fields, as well as the submit button, honeypot, and nonce. Unlike many WordPress output functions, comment_form() is highly configurable through its $args parameter: you can change labels, placeholders, the submit button text, the form HTML, and the order of fields. Additional customisation via action/filter hooks allows adding entirely new fields (a rating input, a checkbox), removing existing ones, wrapping the form in custom HTML, or changing the default field HTML structure. This is the correct approach for building a design-system-compliant comment form without overriding the entire function.
Problem: A review blog needs the comment form to: (1) remove the URL/website field, (2) add a star rating select field that appears before the comment textarea, (3) customise all field labels and placeholders to match the site's voice, and (4) add a GDPR consent checkbox before the submit button.
Solution: Pass a custom $args array to comment_form() to redefine fields. Use the comment_form_field_comment filter to prepend the rating field, and the comment_form_submit_field filter to add the GDPR checkbox.
<?php
// ── 1. Call comment_form() with customised args ───────────────────────
function render_review_comment_form(): void {
$commenter = wp_get_current_commenter();
$args = [
// ─ Customise fields ──────────────────────────────────────────
'fields' => [
'author' => sprintf(
'<p class="comment-form-author"><label for="author">%s</label>'
. '<input id="author" name="author" type="text" value="%s" size="30" required placeholder="%s"></p>',
esc_html__( 'Name *', 'textdomain' ),
esc_attr( $commenter['comment_author'] ),
esc_attr__( 'Your name', 'textdomain' )
),
'email' => sprintf(
'<p class="comment-form-email"><label for="email">%s</label>'
. '<input id="email" name="email" type="email" value="%s" size="30" required placeholder="%s"></p>',
esc_html__( 'Email * (not published)', 'textdomain' ),
esc_attr( $commenter['comment_author_email'] ),
esc_attr__( 'your@email.com', 'textdomain' )
),
// Omitting 'url' key removes the website field entirely
],
// ─ Customise textarea ─────────────────────────────────────────
'comment_field' => '<p class="comment-form-comment">'
. '<label for="comment">' . esc_html__( 'Your Review *', 'textdomain' ) . '</label>'
. '<textarea id="comment" name="comment" cols="45" rows="6" required '
. 'placeholder="' . esc_attr__( 'Share your experience…', 'textdomain' ) . '"></textarea>'
. '</p>',
// ─ Submit button ──────────────────────────────────────────────
'label_submit' => __( 'Submit Review', 'textdomain' ),
'submit_button' => '<input name="%1$s" type="submit" id="%2$s" class="%3$s button button-primary" value="%4$s">',
// ─ Wrapper elements ───────────────────────────────────────────
'comment_notes_before' => '',
'comment_notes_after' => '',
'title_reply' => __( 'Leave a Review', 'textdomain' ),
'title_reply_before' => '<h3 id="reply-title" class="comment-reply-title">',
'title_reply_after' => '</h3>',
];
comment_form( $args );
}
// ── 2. Prepend star rating field before the comment textarea ─────────
add_filter( 'comment_form_field_comment', function ( string $field ): string {
$rating_field = '<p class="comment-form-rating">'
. '<label for="rating">' . esc_html__( 'Rating *', 'textdomain' ) . '</label>'
. '<select id="rating" name="rating" required>'
. '<option value="">' . esc_html__( '— Select rating —', 'textdomain' ) . '</option>'
. '<option value="5">★★★★★ — Excellent</option>'
. '<option value="4">★★★★ — Good</option>'
. '<option value="3">★★★ — Average</option>'
. '<option value="2">★★ — Poor</option>'
. '<option value="1">★ — Terrible</option>'
. '</select></p>';
return $rating_field . $field; // prepend before textarea
} );
// ── 3. Add GDPR checkbox before submit button ─────────────────────────
add_filter( 'comment_form_submit_field', function ( string $submit_field ): string {
$gdpr = '<p class="comment-form-gdpr">'
. '<label>'
. '<input type="checkbox" name="gdpr_consent" value="1" required> '
. esc_html__( 'I agree that my data is stored in accordance with the privacy policy.', 'textdomain' )
. '</label></p>';
return $gdpr . $submit_field;
} );
// ── 4. Save the rating as comment meta ────────────────────────────────
add_action( 'comment_post', function ( int $comment_id ) {
$rating = isset( $_POST['rating'] ) ? absint( $_POST['rating'] ) : 0;
if ( $rating >= 1 && $rating <= 5 ) {
add_comment_meta( $comment_id, 'rating', $rating, true );
}
} );
NOTE: The comment_form_field_comment filter fires specifically for the comment textarea field, making it the easiest place to inject content immediately before the textarea. To add content after the textarea (but before the submit button), use comment_form_submit_field. To add content at the very end of the form (after the submit button), use the comment_form action hook with the $post_id argument. Custom fields submitted with the comment form (like the rating) must be saved manually — WordPress only persists the built-in fields automatically. Always validate and sanitise custom comment form data in the comment_post or preprocess_comment hook before saving.