WordPress как на ладони
WordCamp Saint Petersburg 2018 wordpress jino

Создаем новые поля для комментариев WordPress

Встречаются задачи, когда нужно добавить произвольные поля в форму комментариев WordPress, например поле для ввода телефона, адреса, оценки, настроения и так далее. Тут-то нам и пригодятся знания о хуках в WordPress (событиях и фильтрах), которые позволят вмешаться в стандартный функционал движка и добавить новые поля в комментарии.

В этой статье мы добавим три новых поля в форму комментария WordPress:

  • два текстовых поля: номер телефона и название комментария.
  • и одно поле выбора - радио-кнопки для оценки текущей статьи.

А также, научимся сохранять их в метаполя комментария и выведем эти поля в админке, чтобы их можно было видеть и редактировать.

Как лучше создавать новые поля?

Расширить форму комментария можно, отредактировав оригинальную тему, создав дочернюю тему или создав плагин. Модифицировать оригинальную тему проще, чем создавать дочернюю, но тут есть серьезный недостаток: все усилия будут утеряны, если тему обновить. Но еще лучше создать плагин, потому что так настраиваемая форма комментариев будет работать на всех темах (за исключением тех, в которых форма комментариев добавляется нестандартно).

Пойдем по пути создания плагина для WordPress, к тому же делается это очень просто. Назовём плагин "Расширенные комментарии".

Создание плагина для расширения формы комментариев

Создадим в папке с плагинами новую папку с именем extend-comment, а внутри неё файл extend-comment.php. Теперь, чтобы WordPress увидел плагин, ему нужно указать специальные комментарии-заголовки:

<?php
/*
Plugin Name: Расширенные комментарии
Version: 1.0
Plugin URI: https://wp-kama.ru/?p=8342
Description: Плагин, добавляющий произвольные поля в форму комментариев.
Author: Campusboy
Author URI: https://wp-plus.ru/
*/

Заходим в раздел админки "Плагины" и видим наш плагин:

Его уже можно активировать, но на данный момент он "пустой" и никаких функций пока не выполняет...

Создание полей для неавторизованных пользователей

Подключимся к фильтру comment_form_default_fields и "дополним" массив с дефолтными полями WordPress (автор, email, url). В коде ниже мы заменяем код дефолтных полей формы и добавляем новое поле "Телефон".

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

	$commenter = wp_get_current_commenter();
	$req = get_option( 'require_name_email' );
	$aria_req = ( $req ? " aria-required='true'" : '' );

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

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

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

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

  return $fields;
}

Код прекрасно работает, но если не нужно изменять вид дефолтных полей, то его можно упростить, а именно, добавить только своё поле:

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;
}

Данные поля отображаются, когда пользователь не зарегистрирован. Если пользователь авторизован, то ему отобразиться только поле ввода комментария.

Создание полей для всех пользователей

На следующем шаге мы добавим текстовое поле для заголовка комментария и список радио-кнопок для оценки статьи (рейтинг статьи в комментариях).

Эти поля не могут быть добавлены к полям по умолчанию, как сделано выше, потому что нужно дать возможно вводить их и зарегистрированным пользователям. Для этого используем событие comment_form_logged_in_after, которое срабатывает только для зарегистрированных пользователей. Подключившись к нему, мы добавим новые поля до поля ввода комментария.

Добавление комментария авторизованным пользователем

А чтобы показать поля для незарегистрированных пользователей, используем событие comment_form_after_fields, которое отобразит наши поля ниже полей по умолчанию (автор, email, url).

Добавление комментария неавторизованным пользователем

Т.е. в результате нужно вывести поля в момент срабатывания одного из событий:
comment_form_logged_in_after или comment_form_after_fields.

// Добавляем поля для всех пользователей
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>';
}

Чтобы отобразить 5 радио-кнопок для рейтинга, запускаем цикл. Этот участок кода можно изменить под себя, к примеру вместо 5 указать 10.

Сохранение данных из полей во фронт-энде

Поля для формы комментариев добавлены, но они бесполезны, пока нет алгоритма сохранения данных. Чтобы реализовать этот механизм, используем хук comment_post. Предусмотрим сохранение только непустых данных, чтобы не загромождать базу данных пустыми строками.

Для добавления метаданных комментария используем функцию 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 );
	}

}

Обратите внимание, что для защиты мы очищаем поля через sanitize_text_field().

Теперь, после публикации комментария в базе появятся подобные строчки:

Добавленные метаданные для комментария

Проверка заполнения обязательных полей

Поле рейтинга мы сделали обязательным. Но сейчас комментарий публикуется, даже если это поле не заполнено. Реализуем механизм проверки. Для этого используем фильтр preprocess_comment и, если рейтинг не был выставлен, отобразим текст об ошибке, не добавляя комментарий в базу данных:

// Проверяем, заполнено ли поле "Рейтинг"
add_filter( 'preprocess_comment', 'verify_extend_comment_meta_data' );
function verify_extend_comment_meta_data( $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;
}

Отображение содержимого метаполей во фронт-энде

С добавлением метаданных разобрались. Теперь возникает вопрос: как получить и отобразить метаданные комментария в форме? Для получения метаданных будем использовать функцию get_comment_meta().

Изменить код формы и добавить туда нужные данные можно через фильтр comment_text.

Два варианта вывода рейтинга

Рассмотрим 2 варианта, как можно было бы отобразить рейтинг.

Звёзды рейтинга из собственных картинок

В первом варианте мы будет отображать изображения звёзд, которые должны быть в виде картинок в папке плагина:

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;
  }
}

В коде мы:

  • Получаем ссылку на папку с комментариями.

  • Проверяем наличие заголовка комментария и, если есть, добавляем его перед основным содержимым комментария.

  • Проверяем наличие рейтинга и, если есть, добавляем его после основного содержимого комментария.

Если, к примеру, пользователь поставил четверку, то путь к картинке будет: http://site.ru/wp-content/plugins/extend-comment/images/4star.gif. Естественно, картинки должны существовать...

Звёзды рейтинга из иконочного шрифта Dashicons

Второй вариант по алгоритму такой же, но тут будем использовать родную функцию WordPress wp_star_rating(), которая сама добавит красивые иконки звёзд:

// Отображение содержимого метаполей во фронт-энде
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;
}

Во фронт-энде функция wp_star_rating() не работает, её надо подключить. Также нужно подключить шрифты 'dashicons'.

Проверим, есть ли у записи комментарии и, если есть, подключим файл с функцией и шрифт:

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

	if( isset($post) && (int)$post->comment_count > 0 ){
		require_once ABSPATH .'wp-admin/includes/template.php';
		add_action('wp_enqueue_scripts', function(){
			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 );
	}

}

Шрифт 'dashicons' имеет объем в 45,3Кб без gzip сжатия и 28.3Кб с включенным на сервере сжатием. А сколько будут занимать места ваши картинки? Какой из способов выбрать - решать вам.

Вывод метаполей в админке

На этом создание плагина можно было бы закончить, но что если надо будет изменить метаданные комментария? Поэтому продолжим дорабатывать плагин и добавим возможность изменять метаполя на странице редактирования комментариев.

Для этого добавим метаполя на страницу редактирования комментария с помощью хука add_meta_boxes_comment и функции add_meta_box(). Другими словами, мы ждем действие add_meta_boxes_comment (начало отрисовки дефолтных полей) и с помощью add_meta_box() добавляем новые к имеющимся.

<?php
// Добавляем новый метабокс на страницу редактирования комментария
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' );
}

// Отображаем наши поля
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
}

Этот код похож на тот, который выводил поля в форме комментаривания в посте, и выполняет следующие действия:

  • Получает данные метаполей.

  • wp_nonce_field() выводит проверочное (защитное, одноразовое) скрытое поле для формы, повышая безопасность.

  • Очищает содержимое метаполей с помощью esc_attr() и выводит на экран. Ничего не проверяет. Если данных нет, то поле будет пустое.

  • При выводе радио-кнопок проверяет, какое значение было выбрано и помечает html атрибутом checked='checked' с помощью функции checked().

Сохранение метаполей в админке

На этом шаге необходимо создать механизм сохранения измененных данных на странице редактирования комментария. Это очень похоже на процесс сохранения метаданных из формы комментариев во фронд-энде.

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');

}

Здесь мы подключимся к хуку edit_comment и делаем следующее:

  • Проверим nonce-код и если проверка не пройдет - остановим выполнение функции.

  • Проверим переданные данные по каждому полю и если у какого-то поля его нет - удалим само метаполе, чтобы не занимало место в базе данных. Если поле есть обновляем его и незабываем очищать для безопасности.

Удаление плагина

Наш собственный плагин, расширяющий функционал формы комментирования готов!

Единственное, правилом хорошего тона считается удаление данных, создаваемые плагином, в данном случае - наших метаполей. Ведь если удалить плагин, то данные плагина останутся никому не нужными...

Мы уже рассказывали, как правильно удалить плагин WordPress, потому в корне плагина создадим файл uninstall.php и пропишем в него:

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

global $wpdb; 

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

Вывод среднего рейтинга

По просьбам в комментариях были добавлены две функции, которые можно использовать в своих шаблонах (объект поста должен присутствовать на тот момент).

/**
 * Возвращает средний рейтинг поста.
 *
 * @return string
 */
get_the_extend_comment_post_rating();

// Если было 3 оценки (4, 4, 3) , то выведет 3.6666666666666665
echo get_the_extend_comment_post_rating();

/**
 * Возвращает HTML блок со средним рейтингом в виде звездочек для текущего поста.
 *
 * @see wp_star_rating()
 *
 * @return string
 */
get_the_extend_comment_post_star_rating();

// Пусть оценки те же, что в примере выше.
echo get_the_extend_comment_post_star_rating();

// Выведет html код
<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>

// Визуально как выглядят звёзды было показано выше.

Подведем итоги

В этой статье мы разобрались:

Данный плагин можно еще улучшать и дорабатывать - всё зависит от поставленных задач. Ну а пока мы научились изменять дефолтную форму комментирования WordPress и сделали её более привлекательной для пользователя.

Скачать: Extend Comment
Плагин размещён на GitHub, поэтому можете оставлять свои пожелания и предлагать улучшения там. Или в комментариях к этой статье.
Скачано: 294, размер: 16KB

Статья создана на базе статьи "How To Add Custom Fields In A WordPress Comment Form" с авторскими правками и дополнениями.

campusboy 2728youtube.com/c/wpplus
Активный пользователь wp-kama.ru. WordPress-разработчик. Разработка сайтов и лендингов. Доработка существующих проектов. Сопровождение ресурсов.
Редакторы: Kama 5192
Создаем новые поля для комментариев WordPress 18 комментов
Полезные 1 Вопросы 1 Все
  • popay7 cайт: clubwp.ru

    Скачал ваш архив. Поставил, в админке работает, а вот на сайте под комментариями вместо звезд Fatal error: Call to undefined function wp_star_rating() in \wp-content\plugins\extend-comment\extend-comment.php on line 91

    После одобрения комментария ошибка исчезает, но звезды не отображаются.

    А и на самом сайте стили не срабатывают и в форме комментария остаются круглеши вместо звезд.

    1
    • campusboy2728 cайт: www.youtube.com/c/wpplus

      Сейчас вернулся к коду, чтобы доработать некоторые моменты по просьбам трудящихся. На 10 темах пытался воспроизвести такой баг, но не вышло. Интересно, что там у тебя было в то время - загадка. Попробую подключать файл с функцией прям перед её вызовом, там уж железно не должно такого бага возникнуть.

      1
      Ответить15 дней назад #
  • @ Андрей

    Не подскажите, как вывести в comments.php где-нибудь к стилям комментария к рейтингом <li id="li-comment-"> что-то типа class="comments_1", если балл 1 округленный или comments_2, если оценка примерно 2. Хочется выделять красным фоном негативные 4
    Спасибо!

    • @ Андрей

      Нашёл, всё оказалось проще некуда - echo get_comment_meta($comment->comment_ID, 'rating', true ) и подставляй куда хочешь. Спасибо за плагин!

      2
  • @ Вячаслав

    Здравствуйте. /Вот вчера читал Ваш пост касающийся создание полей в комментариях. И там был пример как их можно сортировать.
    Вот в упор найти не могу. Подкиньте ссылку если не сложно)))

  • Леонид

    Расширить форму комментария можно"

    1. Здравствуйте Тимур! В процессе изучения функционала CMS WordPress обратил внимание на скудные и ограниченные функции установленной в ней по умолчанию системы комментариев.

    2. Учитывая, что для создаваемого сайта комментарии значимы не меньше самого контента, необходимо, чтобы возможность комментирования была не только проста и удобна, но и элементарно функциональна, для чего должны быть следующие обычные функции:

    1) цитирование части как самого комментируемого контента, так и его комментариев способом его выделения и нажатия курсивом на соответствующую функциональную кнопку «Цитирование», чтобы выделенный для цитирования текст автоматически заключался в нужные теги;
    2) выделение текста жирным, курсивом, подчёркиванием;
    3) выделение цвета текста и фона;
    4) нумерация комментариев с указанием: номера, даты и времени оставленного комментария;
    5) прикрепления к комментарию ссылки, изображения, файла (txt, doc, docx, pdf, xls);
    6) редактирования комментария на период до опубликования ответа на него или следующего за ним комментария;
    7) предварительного просмотра составленного комментария;
    8) подписки на комментарии и автоматическое отправление их на электронную почту подписавшегося;
    9) скрытия длинных комментариев со ссылкой «Читать дальше», как это реализовано в комментариях видеохостинга YouTube и социальной сети "Вконтакте".

    3. Просмотрел немало плагинов с такими функциями: WP Russian Quicktags, Comment Toolbar, Еpoch, Yoast Comment Hacks, Truncate Comments, wpDiscuz, Comment Images (русская версия), Subscribe to Comments, TinyMCEComments, Filosofo Comments Preview (русская версия), Jetpack, Simple Comment Editing, плагин комментариев для WordPress Александра Каратаева, но ни у одного из них нет в одном плагине (или хотя бы в двух) всех вышеперечисленных функций!

    3.1. Неужели нет такого универсального плагина с обычными и распространёнными функциями комментирования и придётся устанавливать несколько плагинов?

    4. Может, есть такие темы (шаблоны), чтобы в них были все необходимые функции комментирования? Если кто знает, подскажите, пожалуйста.

    5. В Вашей форме комментариев на этой странице почему то не срабатывает функция предварительного просмотра и нет перехода по ссылке при нажатии на неё левой кнопкой "мышки"!

    2
    Ответить4 месяца назад #
    • Kama5192

      Комментирование дело не простое... Есть плагины платные, монстры. Вообще даже не знаю как ответить на ваш вопрос. На этом сайте комменты я дорабатывал вручную. Все вышеуказанные пункты есть, но работают они не отдельно, а как часть темы, что-то от туда, что-то от сюда и все это собирается в систему комментирвоания. Которая надо признать все равно далека от идеала...

      Ответить4 месяца назад #
  • Yura

    Как выводить произвольное поле только на конкретной записи или на опрделенных типах записей?

    Ответить3 месяца назад #
    • campusboy2728 cайт: www.youtube.com/c/wpplus

      С помощью условных тегов можно подобное провернуть. Весь их список тут.

      Как выводить произвольное поле только на конкретной записи?

      С помощью условного тега is_single() проверяете, та ли запись и отображаете поле.

      Как выводить произвольное поле только на определенных типах записей?

      По такому же принципу.

      1
      Ответить3 месяца назад #
  • @ Олег

    Супер, если бы еще запилить вывод суммарного рейтинга.

    1
    Ответить2 месяца назад #
    • Максим

      Супер, если бы еще запилить вывод суммарного рейтинга.

      Действительно. Подскажите, как можно сделать вывод суммарного рейтинга, например, вверху страницы?

      Ответить15 дней назад #
      • campusboy2728 cайт: www.youtube.com/c/wpplus

        Здравствуй. Судя по вопросу, тебе не подсказать надо, а сразу сделать готовое. Дополнил статью новым разделом и обновил код плагина. Качай, тестируй.

        2
        Ответить15 дней назад #
    • campusboy2728 cайт: www.youtube.com/c/wpplus

      Добавлено.

      3
      Ответить15 дней назад #
  • @ Кирилл

    Текущий подход так же затрагивает комментарии в Woocomerce.
    Поля с помощью хука woocommerce_review_before_comment_meta не удалось добавить
    Подскажите куда рыть

    Ответитьмесяц назад #

Здравствуйте, !

Ваш комментарий
Предпросмотр