Creating New Fields for WordPress Comments

There are cases when it is necessary to add custom fields to the WordPress comment form, for example, a field for entering a phone number, address, rating, mood, and so on. This is where our knowledge of WordPress hooks (events and filters) will come in handy, allowing us to intervene in the standard functionality of the engine and add new fields to comments.

In this article, we will add three new fields to the WordPress comment form:

  • Two text fields: phone number and comment title.
  • And one selection field - radio buttons for rating the current article.

Additionally, we will learn how to save them in the comment meta-fields and display these fields in the admin panel so that they can be viewed and edited.

How to best create new fields?

You can expand the comment form by editing the original theme, creating a child theme, or creating a plugin. Modifying the original theme is easier than creating a child theme, but there is a significant drawback: all efforts will be lost if the theme is updated. However, it is even better to create a plugin, because a customized comment form will work on all themes (except those where the comment form is added non-standardly).

Let's go the route of creating a plugin for WordPress, and it's very easy to do. Let's name the plugin "Extended Comments".

Creating a Plugin to Extend the Comment Form

Let's create a new folder with the name extend-comment in the plugins folder, and inside it, a file extend-comment.php. Now, for WordPress to see the plugin, we need to specify special header comments:

<?php
/**
 * Plugin Name: Extended Comments
 * Description: Adds custom fields to the comment form.
 * Plugin URI: https://wp-kama.com/2396
 * Author: Campusboy
 * Author URI: https://wp-plus.ru/
 *
 * Version: 1.0
 */

We go to the "Plugins" section in the admin panel and see our plugin:

It can already be activated, but at the moment it is "empty" and does not perform any functions yet...

Creating Fields for Unauthenticated Users

We connect to the comment_form_default_fields filter and "extend" the array with the default WordPress fields (author, email, url). In the code below, we replace the code of the default form fields and add a new field "Phone".

add_filter( 'comment_form_default_fields', 'extend_comment_custom_default_fields' );

function extend_comment_custom_default_fields( $fields ) {

	$commenter = wp_get_current_commenter();
	$req_name_email = get_option( 'require_name_email' );

	$fields['author'] = sprintf(
		'<p class="comment-form-author">
			<label for="author">%s</label>%s
			<input id="author" name="author" type="text" value="%s" size="30" tabindex="1"%s />
		</p>',
		__( 'Name' ),
		$req_name_email ? '<span class="required">*</span>' : '',
		esc_attr( $commenter['comment_author'] ),
		$req_name_email ? " aria-required='true'" : ''
	);

	$fields['email'] = sprintf(
		'<p class="comment-form-email">
			<label for="email">%s</label>%s
			<input id="email" name="email" type="text" value="%s" size="30"  tabindex="2"%s />
		</p>',
		__( 'Email' ),
		$req_name_email ? '<span class="required">*</span>' : '',
		esc_attr( $commenter['comment_author_email'] ),
		$req_name_email ? " aria-required='true'" : ''
	);

	$fields['url'] = sprintf(
		'<p class="comment-form-url">
			<label for="url">%s</label>
			<input id="url" name="url" type="text" value="%s" size="30"  tabindex="3" />
		</p>',
		__( 'Website' ),
		esc_attr( $commenter['comment_author_url'] )
	);

	$fields['phone'] = sprintf(
		'<p class="comment-form-phone">
			<label for="phone">%s</label>
			<input id="phone" name="phone" type="text" size="30" tabindex="4" />
		</p>',
		__( 'Phone' )
	);

	return $fields;
}

The code works perfectly, but if you don't need to change the appearance of the default fields, it can be simplified by adding only your field:

add_filter('comment_form_default_fields', 'extend_comment_default_fields');
function extend_comment_default_fields($fields) {

  $fields[ 'phone' ] = '<p class="comment-form-phone">'.
	'<label for="phone">' . __( 'Phone' ) . '</label>'.
	'<input id="phone" name="phone" type="text" size="30"/></p>';

  return $fields;
}

These fields are displayed when the user is not registered. If the user is authenticated, only the comment input field will be displayed.

Creating Fields for All Users

Next, we will add a text field for the comment title and a radio button list for rating the article (article rating in comments).

These fields cannot be added to the default fields, as done above, because it is necessary to allow registered users to enter them. For this, we use the event comment_form_logged_in_after, which is triggered only for registered users. By connecting to it, we will add new fields before the comment input field.

And to show fields for unregistered users, we use the event comment_form_after_fields, which will display our fields below the default fields (author, email, url).

That is, as a result, we need to display fields at the time of one of the events triggering:
comment_form_logged_in_after or comment_form_after_fields.

// Add fields for all users
add_action( 'comment_form_logged_in_after', 'extend_comment_custom_fields' );
add_action( 'comment_form_after_fields', 'extend_comment_custom_fields' );
function extend_comment_custom_fields() {

	echo '<p class="comment-form-title">'.
			  '<label for="title">' . __( 'Comment Title' ) . '</label>'.
			  '<input id="title" name="title" type="text" size="30"/></p>';

	echo '<p class="comment-form-rating">'.
			  '<label for="rating">'. __('Rating') . '<span class="required">*</span></label>
			  <span class="commentratingbox">';

	for( $i=1; $i <= 5; $i++ ){
		echo '
		<label class="commentrating" style="display:inline-block;">
			<input type="radio" name="rating" id="rating" value="'. $i .'"/> '. $i .'   
		</label>';
	}

	echo'</span></p>';
}

To display 5 radio buttons for rating, we run a loop. This part of the code can be customized, for example, instead of 5, specify 10.

Saving Data from Fields in the Frontend

The comment form fields are added, but they are useless until there is a data saving mechanism. To implement this mechanism, we use the comment_post hook. We will only consider saving non-empty data to avoid cluttering the database with empty strings.

To add comment metadata, we use the function add_comment_meta().

add_action( 'comment_post', 'save_extend_comment_meta_data' );
function save_extend_comment_meta_data( $comment_id ){

	if( !empty( $_POST['phone'] ) ){
		$phone = sanitize_text_field( $_POST['phone'] );
		add_comment_meta( $comment_id, 'phone', $phone );
	}

	if( !empty( $_POST['title'] ) ){
		$title = sanitize_text_field( $_POST['title'] );
		add_comment_meta( $comment_id, 'title', $title );
	}

	if( !empty( $_POST['rating'] ) ){
		$rating = intval( $_POST['rating'] );
		add_comment_meta( $comment_id, 'rating', $rating );
	}

}

Please note that for security reasons, we sanitize the fields using sanitize_text_field().

Now, after publishing a comment, the database will contain similar entries:

Added metadata for the comment

Checking the Completion of Required Fields

We made the rating field mandatory. However, currently, a comment is published even if this field is not filled in. We will implement a validation mechanism. For this, we use the filter preprocess_comment and, if the rating was not set, we will display an error message without adding the comment to the database:

// Check if the "Rating" field is filled
add_filter( 'preprocess_comment', 'verify_extend_comment_meta_data' );
function verify_extend_comment_meta_data( $commentdata ) {

	// do nothing if this is a reply to a comment
	if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'replyto-comment' ) {
		return $commentdata;
	}

	if ( empty( $_POST['rating'] ) || ! (int)$_POST['rating'] ) {
		wp_die( __( 'Error: You did not add a rating. Hit the Back button on your Web browser and resubmit your comment with a rating.' ) );
	}

	return $commentdata;
}

Displaying the Content of Metafields in the Frontend

We have figured out adding metadata. Now the question arises: how to get and display comment metadata in the form? To retrieve metadata, we will use the function get_comment_meta().

To change the form code and add the necessary data to it, we can use the filter comment_text.

Two options for displaying the rating

Let's consider 2 options for displaying the rating.

Rating Stars from Custom Images

In the first option, we will display star images, which should be in the form of images in the plugin folder:

add_filter( 'comment_text', 'modify_extend_comment');
function modify_extend_comment( $text ){

  $plugin_url_path = WP_PLUGIN_URL;

  if( $commenttitle = get_comment_meta( get_comment_ID(), 'title', true ) ) {
	$commenttitle = '<strong>' . esc_attr( $commenttitle ) . '</strong><br/>';
	$text = $commenttitle . $text;
  }

  if( $commentrating = get_comment_meta( get_comment_ID(), 'rating', true ) ) {
	$commentrating = '<p class="comment-rating">  <img src="'. $plugin_url_path .
	'/extend-comment/images/'. $commentrating . 'star.gif"/><br/>Rating: <strong>'. $commentrating .' / 5</strong></p>';
	$text = $text . $commentrating;
	return $text;
  } else {
	return $text;
  }
}

In the code, we:

  • Get the link to the folder with comments.
  • Check for the presence of a comment title and, if present, add it before the main comment content.
  • Check for the presence of a rating and, if present, add it after the main comment content.

For example, if a user gives a rating of four, the path to the image will be: http://example.com/wp-content/plugins/extend-comment/images/4star.gif. Naturally, the images should exist...

Rating Stars from Dashicons Icon Font

The second option follows the same algorithm, but here we will use the native WordPress function wp_star_rating(), which will add beautiful star icons by itself:

// Displaying the meta fields content in the front-end
add_filter( 'comment_text', 'modify_extend_comment');
function modify_extend_comment( $text ){
	global $post;

	if( $commenttitle = get_comment_meta( get_comment_ID(), 'title', true ) ) {
		$commenttitle = '<strong>' . esc_attr( $commenttitle ) . '</strong><br/>';
		$text = $commenttitle . $text;
	}

	if( $commentrating = get_comment_meta( get_comment_ID(), 'rating', true ) ) {

		$commentrating = wp_star_rating( array (
			'rating' => $commentrating,
			'echo'=> false
		));

		$text = $text . $commentrating;
	}

	return $text;
}

In the front-end, the wp_star_rating() function does not work, it needs to be included. It is also necessary to include the 'dashicons' font.

Let's check if the post has comments and, if so, include the file with the function and the font:

add_action( 'wp_enqueue_scripts', 'check_count_extend_comments' );
function check_count_extend_comments(){
	global $post;

	if( $post && (int) $post->comment_count > 0 ){
		require_once ABSPATH .'wp-admin/includes/template.php';

		wp_enqueue_style('dashicons');

		$stars_css = '
		.star-rating .star-full:before { content: "\f155"; }
		.star-rating .star-empty:before { content: "\f154"; }
		.star-rating .star {
			color: #0074A2;
			display: inline-block;
			font-family: dashicons;
			font-size: 20px;
			font-style: normal;
			font-weight: 400;
			height: 20px;
			line-height: 1;
			text-align: center;
			text-decoration: inherit;
			vertical-align: top;
			width: 20px;
		}
		';

		wp_add_inline_style( 'dashicons', $stars_css );
	}

}

The 'dashicons' font has a size of 45.3KB without gzip compression and 28.3KB with server-side compression enabled. How much space will your images take? The choice between the methods is up to you.

Displaying Meta Fields in the Admin Panel

At this point, we could finish creating the plugin, but what if we need to change the comment metadata? Therefore, let's continue to refine the plugin and add the ability to modify the meta fields on the comment editing page in the admin panel.

To do this, we will add meta fields to the comment editing page using the add_meta_boxes_comment hook and the add_meta_box() function. In other words, we wait for the add_meta_boxes_comment action (the beginning of rendering default fields) and add new ones to the existing ones using add_meta_box().

<?php
// Add a new meta box to the comment editing page
add_action( 'add_meta_boxes_comment', 'extend_comment_add_meta_box' );
function extend_comment_add_meta_box(){
	add_meta_box( 'title', __( 'Comment Metadata - Extend Comment' ), 'extend_comment_meta_box', 'comment', 'normal', 'high' );
}

// Display our fields
function extend_comment_meta_box( $comment ){
	$phone  = get_comment_meta( $comment->comment_ID, 'phone', true );
	$title  = get_comment_meta( $comment->comment_ID, 'title', true );
	$rating = get_comment_meta( $comment->comment_ID, 'rating', true );

	wp_nonce_field( 'extend_comment_update', 'extend_comment_update', false );
	?>
	<p>
		<label for="phone"><?php _e( 'Phone' ); ?></label>
		<input type="text" name="phone" value="<?php echo esc_attr( $phone ); ?>" class="widefat" />
	</p>
	<p>
		<label for="title"><?php _e( 'Comment Title' ); ?></label>
		<input type="text" name="title" value="<?php echo esc_attr( $title ); ?>" class="widefat" />
	</p>
	<p>
		<label for="rating"><?php _e( 'Rating: ' ); ?></label>
		<span class="commentratingbox">
		<?php
		for( $i=1; $i <= 5; $i++ ){
		  echo '
		  <span class="commentrating">
			<input type="radio" name="rating" id="rating" value="'. $i .'" '. checked( $i, $rating, 0 ) .'/>
		  </span>';
		}
		?>
		</span>
	</p>
	<?php
}

This code is similar to the one that displayed fields in the comment form in the post and performs the following actions:

  • Gets the meta field data.
  • wp_nonce_field() outputs a verification (protective, one-time) hidden field for the form, increasing security.
  • Clears the meta field content using esc_attr() and displays it on the screen. It does not perform any checks. If there is no data, the field will be empty.
  • When outputting radio buttons, it checks which value was selected and marks the html attribute checked='checked' using the checked() function.

Saving Meta Fields in the Admin Panel

At this step, it is necessary to create a mechanism for saving the modified data on the comment editing page. This process is very similar to saving metadata from the comment form in the front-end.

add_action( 'edit_comment', 'extend_comment_edit_meta_data' );
function extend_comment_edit_meta_data( $comment_id ) {
	if( ! isset( $_POST['extend_comment_update'] ) || ! wp_verify_nonce( $_POST['extend_comment_update'], 'extend_comment_update' ) )
	return;

	if( !empty($_POST['phone']) ){
		$phone = sanitize_text_field($_POST['phone']);
		update_comment_meta( $comment_id, 'phone', $phone );
	}
	else
		delete_comment_meta( $comment_id, 'phone');

	if( !empty($_POST['title']) ){
		$title = sanitize_text_field($_POST['title']);
		update_comment_meta( $comment_id, 'title', $title );
	}
	else
		delete_comment_meta( $comment_id, 'title');

	if( !empty($_POST['rating']) ){
		$rating = intval($_POST['rating']);
		update_comment_meta( $comment_id, 'rating', $rating );
	}
	else
		delete_comment_meta( $comment_id, 'rating');

}

Here we connect to the edit_comment hook and do the following:

  • Verify the nonce code, and if the check fails, stop the function execution.
  • Check the submitted data for each field, and if any field is missing, delete the meta field itself so that it does not occupy space in the database. If the field exists, update it and remember to clear it for security.

Plugin Deletion (uninstall)

It is considered good practice to delete data created by the plugin, in this case, our meta fields. After all, if you delete the plugin, the plugin's data will remain unnecessary...

We have already explained how to properly delete a WordPress plugin, so in the root of the plugin, create a file named uninstall.php and add the following code to it:

if( ! defined('WP_UNINSTALL_PLUGIN') ) exit;

global $wpdb;

$wpdb->query(
	"DELETE FROM $wpdb->commentmeta
	WHERE meta_key IN ( 'phone', 'title', 'rating' )"
);

Displaying Average Rating

At the request of the comments, two functions have been added that can be used in your templates (the post object must be present at that moment).

/**
 * Returns the average rating of the post.
 *
 * @return string
 */
get_the_extend_comment_post_rating();

// If there were 3 ratings (4, 4, 3), it will output 3.6666666666666665
echo get_the_extend_comment_post_rating();

/**
 * Returns an HTML block with the average rating in the form of stars for the current post.
 *
 * @see wp_star_rating()
 *
 * @return string
 */
get_the_extend_comment_post_star_rating();

// Let the ratings be the same as in the example above.
echo get_the_extend_comment_post_star_rating();

It will output the HTML code (visually how the stars look was shown above):

<div class="star-rating">
	<span class="screen-reader-text">3,7 rating</span>
	<div class="star star-full" aria-hidden="true"></div>
	<div class="star star-full" aria-hidden="true"></div>
	<div class="star star-full" aria-hidden="true"></div>
	<div class="star star-half" aria-hidden="true"></div>
	<div class="star star-empty" aria-hidden="true"></div>
</div>

Conclusion

In this article, we have covered:

This plugin can be further improved and enhanced - it all depends on the tasks at hand. For now, we have learned how to modify the default WordPress commenting form and make it more attractive to users.

Download: Extend Comment
A sample plugin that allows you to extend the capabilities of the standard comment form in WordPress. The plugin is hosted on GitHub, so you can leave your wishes and suggest improvements there. Or in comments to this article.
Downloaded: 14, size: 0

This article is based on the article "How To Add Custom Fields In A WordPress Comment Form" with author's edits and additions.