Создаем CAPTCHA плагин для вашего WordPress сайта
Благодаря своей популярности, WordPress стал мишенью для спамеров.
Автоматизированные спам-боты ищут в сети сайты, работающие на популярных системах, таких как WordPress, и отправляют на них сотни и тысячи спам комментариев. Без надежной защиты спам становится большой проблемой для сайта.
Хороший способ борьбы со спамом — использование CAPTCHA в формах комментариев на вашем сайте.
В каталоге WordPress плагинов есть много плагинов для интеграции CAPTCHA. Но создавать очередной капча плагин мы не будем, цели этой статьи немного другие:
- Продемонстрировать работу с HTTP API в WordPress.
- Узнать как добавить собственные поля в форму для комментариев, использовать и валидировать их.
Разработка плагина
Перед тем как приступить к разработке плагина, перейдите на сайт reCAPTCHA, зарегистрируйте ваш сайт и получите ваши публичный и секретный ключи для использования API reCAPTCHA.
Подробнее об основах создания плагинов для WordPress вы можете узнать в статьях:
Напишем заголовок плагина:
/* Plugin Name: Add reCAPTCHA to comment form Plugin URI: http://easy-code.ru Description: Add Google's reCAPTCHA to WordPress comment form Version: 0.1 License: GPL2 */
Создайте плагин с тремя свойствами, в которых будут храниться ключи, а также сообщение об ошибке (это сообщение генерируется если форма не заполнена или заполнена не верно).
class Captcha_Comment_Form { /** @type string private key|public key */ private $public_key, $private_key; /** @type string captcha errors */ private static $captcha_error;
Конструктор класса будет добавлять две пары событий и фильтров.
/** class constructor */ public function __construct() { $this->public_key = '7Lcimv8SRFGYKOja-6WXmSllOz8fjYWfHxdsgMwz'; $this->private_key = '7Lcimv8SQSDFTH9dgEOiUANLBIfd85Qr0Kv4NrSdV'; // Добавим капчу в форму для комментариев add_action('comment_form', array($this, 'captcha_display')); // удаляем комментарии не прошедшие проверку add_action('wp_head', array($this, 'delete_failed_captcha_comment')); // проверка капчи add_filter('preprocess_comment', array($this, 'validate_captcha_field')); // редирект при отправке комментария add_filter('comment_post_redirect', array($this, 'redirect_fail_captcha_comment'), 10, 2); }
Капча будет выводится методом captcha_display(). Для того, чтобы форма выводилась в нужное нам место, надо чтобы WordPress вызвал этот метод во время вывода формы для комментариев. В этом поможет системное событие comment_form.
Событие wp_head будет вызывать функцию delete_failed_captcha_comment(), который будет удалять комментарии с неправильной капчей.
Фильтр preprocess_comment вызывает метод validate_captcha_field() для проверки, что CAPTCHA заполнена верно.
Фильтр comment_post_redirect вызовет метод redirect_fail_captcha_comment(), которая добавит необходимые параметры к строке запроса при редиректе.
Метод captcha_display():
/** Output the reCAPTCHA form field. */ public function captcha_display() { if (isset($_GET['captcha']) && $_GET['captcha'] == 'empty') { echo '<strong>ERROR</strong>: CAPTCHA should not be empty'; } elseif (isset($_GET['captcha']) && $_GET['captcha'] == 'failed') { echo '<strong>ERROR</strong>: CAPTCHA response was incorrect'; } echo <<<CAPTCHA_FORM <style type='text/css'> #submit { display: none; } </style> <script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k=<?= $this->public_key; ?>"> </script> <noscript> <iframe src="http://www.google.com/recaptcha/api/noscript?k=<?= $this->public_key; ?>" height="300" width="300" frameborder="0"></iframe> <br> <textarea name="recaptcha_challenge_field" rows="3" cols="40"> </textarea> <input type="hidden" name="recaptcha_response_field" value="manual_challenge"> </noscript> <input name="submit" type="submit" id="submit-alt" tabindex="6" value="Post Comment"/> CAPTCHA_FORM; } /** * Add query string to the comment redirect location * * @param $location string location to redirect to after comment * @param $comment object comment object * * @return string */ function redirect_fail_captcha_comment($location, $comment) { if (!empty(self::$captcha_error)) { $args = array('comment-id' => $comment->comment_ID); if (self::$captcha_error == 'captcha_empty') { $args['captcha'] = 'empty'; } elseif (self::$captcha_error == 'challenge_failed') { $args['captcha'] = 'failed'; } $location = add_query_arg($args, $location); } return $location; }
Также эта функция проверяет был ли передан параметр $_GET[‘captcha’] в функции redirect_fail_captcha_comment() и выводит соответствующее сообщение.
/** * Verify the captcha answer * * @param $commentdata object comment object * * @return object */ public function validate_captcha_field($commentdata) { // if captcha is left empty, set the self::$captcha_error property to indicate so. if (empty($_POST['recaptcha_response_field'])) { self::$captcha_error = 'captcha_empty'; } // if captcha verification fail, set self::$captcha_error to indicate so elseif ($this->recaptcha_response() == 'false') { self::$captcha_error = 'challenge_failed'; } return $commentdata; }
Метод validate_captcha_field(), как понятно по его названию, проверяет правильность заполнения капчи.
Обратите внимание на условие elseif, в нем происходит вызов функции recaptcha_response() для проверки CAPTCHA.
Метод recaptcha_response():
/** * Get the reCAPTCHA API response. * * @return string */ public function recaptcha_response() { // reCAPTCHA challenge post data $challenge = isset($_POST['recaptcha_challenge_field']) ? esc_attr($_POST['recaptcha_challenge_field']) : ''; // reCAPTCHA response post data $response = isset($_POST['recaptcha_response_field']) ? esc_attr($_POST['recaptcha_response_field']) : ''; $remote_ip = $_SERVER["REMOTE_ADDR"]; $post_body = array( 'privatekey' => $this->private_key, 'remoteip' => $remote_ip, 'challenge' => $challenge, 'response' => $response ); return $this->recaptcha_post_request($post_body); }
Разберемся в том, как работает recaptcha_response().
POST запрос отправляется по адресу http://www.google.com/recaptcha/api/verify со следующими параметрами:
- privatekey: ваш секретный ключ.
- remoteip: IP адрес комментатора.
- challenge: значения поля recaptcha_challenge_field в форме для комментариев.
- response: значение поля recaptcha_response_field в форме для комментариев.
IP адрес посетителя хранится в $_SERVER[«REMOTE_ADDR»].
В методе recaptcha_post_request()
происходит работа с HTTP API. Эта функция принимает параметры POST запроса и делает запрос к API капчи и, в случае успеха возвращает true.
/** * Send HTTP POST request and return the response. * * @param $post_body array HTTP POST body * * @return bool */ public function recaptcha_post_request($post_body) { $args = array('body' => $post_body); // отправляем POST запрос на сервер reCaptcha $request = wp_remote_post('https://www.google.com/recaptcha/api/verify', $args); // получаем ответ $response_body = wp_remote_retrieve_body($request); $answers = explode("\n", $response_body); $request_status = trim($answers[0]); return $request_status; }
Любой комментарий, отправленный пользователем, который не прошел проверку, удаляется методом delete_failed_captcha_comment().
/** Delete comment that fail the captcha test. */ function delete_failed_captcha_comment() { if (isset($_GET['comment-id']) && !empty($_GET['comment-id'])) { wp_delete_comment(absint($_GET['comment-id'])); } }
Плагин почти готов. Для его работы нам надо создать объект только что написанного класса:
new Captcha_Comment_Form();
После активации плагина CAPTCHA будет добавлена в форму для комментариев WordPress:
Заключение
В этой статье мы рассмотрели работу с формой комментариев в WordPress. С помощью системы событий и фильтров вы можете делать с комментариями на вашем сайте что угодно!
Для проверки работоспособности плагина скачайте исходники и поместите главный файл плагина в папку wp-content/plugins и замените ключи на свои.
На этом всё 🙂
Плагин работает, но как и другие выводит каптчу после кнопки «Отправить», поэтому даже если не вводить каптчу комментарий все равно добавляется….