И так, ранее я писал про классификацию сообщеий. Теперь неплохо дыло бы использовать его на практике. Заодно не плохо было бы разобраться как написать пдлагин для WordPress. В данном случае это будет плагин в тени, т.е. он будет проверять сообщения комментариев без участия пользователя.
Скелет
Для начала не плохо было бы понять с чего начать. Я достаточно долго блуждал по интернету в поисках информации. Когда впервые что-то берешь в руки и не знаешь что с этим делом начинаешь искать хоть какую-то вводную статью. Нашел я пару статей, но они не для моей версии (на текущий момент 5.8.2). Хотелось что-то свежее.
В результате поисков я нашел пару интересных и полезные статей. Но мне повезло еще в одном: генератор скелета. Чтобы со всем этим добром не ковыряться ребята выложили форму, в которой можно просто сгенерировать шаблон. Думаю с формой можно разобраться. Там все просто.
Подготовка
Вот мы сгенерировали скелет, скачали, распаковали в wp/wp-content/plugins/classify-comments-wp-plugin (в моем случае). Что дальше? А дальше нужно начинать писать, так как в нем уже все готово.
Для начала открываем основной файл (в моем случае classify-comment.php) и правим заголовок:
/**
* The plugin bootstrap file
*
* This file is read by WordPress to generate the plugin information in the plugin
* admin area. This file also includes all of the dependencies used by the plugin,
* registers the activation and deactivation functions, and defines a function
* that starts the plugin.
*
* @since 1.0.0
* @package Classify_Comment
*
* @wordpress-plugin
* Plugin Name: Classify Comment
* Plugin URI: https://ymnuktech.ru
* Description: Classify comments for toxic messages
* Version: 1.0.0
* Author: Alexandr Fedoryuk
* Author URI: https://ymnuktech.ru
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: classify-comment
* Domain Path: /languages
*/
Эти комментарии нужны чтобы WordPress показал информацию о плагине: кто написал, ссылки, адреса и т.д. Теперь нужно немного подредактировать скелет, так как мне лично не нравится, что я должен дублировать некоторую информацию. Для этого я создал файл includes/class-classify-comment-ext.php и добавил следующее:
class Classify_Comment_Ext
{
public const table_classify_comments = "classify_comments";
public const table_classify_comments_option = "classify_comments_option";
public $address;
public $cats;
public function __constructor()
{
}
/**
* Проверяет переданное сообщение и возвращает его категорию
* @param string $msg - Сообщение
* @return string - возвращает категорию
*/
protected function verifyMessage($msg, $moreInfo = null)
{
$this->loadOptions();
$data = array(
'text' => $msg
);
$payload = json_encode($data);
$ch = curl_init($this->address . "/api/v1/fisher");
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
# Return response instead of printing.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
# Send request.
$result = curl_exec($ch);
curl_close($ch);
$result = json_decode($result);
global $wpdb;
$q = $wpdb->prepare(
"
INSERT INTO `" . $wpdb->prefix . Classify_Comment_Ext::table_classify_comments . "`
(`comment_content`, `cat`, `comment_post_ID`, `comment_author`, `comment_author_email`, `comment_author_url`, `comment_author_IP`, `comment_agent`, `user_ID`)
VALUES
(%s, %s, %d, %s, %s, %s, %s, %s, %d)",
$msg,
$result->data,
!is_null($moreInfo) ? $moreInfo['comment_post_ID'] : null,
!is_null($moreInfo) ? $moreInfo['comment_author'] : null,
!is_null($moreInfo) ? $moreInfo['comment_author_email'] : null,
!is_null($moreInfo) ? $moreInfo['comment_author_url'] : null,
!is_null($moreInfo) ? $moreInfo['comment_author_IP'] : null,
!is_null($moreInfo) ? $moreInfo['comment_agent'] : null,
!is_null($moreInfo) ? $moreInfo['user_ID'] : null
);
$wpdb->query($q);
if ($result->result) return $result->data;
return null;
}
/**
* Проверка по списку блокировки категории
* @param string Категория для проверки
* @param boolean Если попадает в указанную категорию в настройках, то возвращает true
*/
protected function validateCats($msg, $moreInfo = null)
{
$cat = $this->verifyMessage($msg, $moreInfo);
// error_log($cat);
if (count($this->cats) === 0) return false;
foreach ($this->cats as $val) {
if ($val == $cat) return true;
}
return false;
}
protected function loadOptions()
{
global $wpdb;
$res = $wpdb->get_results("
SELECT value FROM {$wpdb->prefix}classify_comments_option WHERE name = 'address'");
$this->address = $res[0]->value;
$res = $wpdb->get_results("
SELECT value FROM {$wpdb->prefix}classify_comments_option WHERE name = 'cats'");
$cats = array();
if (isset($res) && count($res) > 0 && !is_null($res[0]->value)) {
$res = explode(",", $res[0]->value);
if (count($res) > 0) {
foreach ($res as $val) {
$val = trim($val);
if (strlen($val) > 0) {
array_push($cats, $val);
}
}
}
}
$this->cats = array_unique($cats);
}
}
После, для классов Classify_Comment_Admin и Classify_Comment_Public я добавил extends Classify_Comment_Ext. Далее чтобы это заработало (иначе упадет в ошибку) в классе includes/class-classify-comment.php в функцию load_dependencies() добавляем строчку:
require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-classify-comment-ext.php';
На этом подготовка закончена.
Реализация админки
Первым делом можно создать меню для админки. Для этого добавляем функцию admin_generate_menu():
public function admin_generate_menu()
{
// Добавляем основной раздел меню
add_menu_page('Добро пожаловать в модуль классификации комментариев', 'Токсичность', 'manage_options', 'options_toxic_comments', array(&$this, 'admin_options'));;
// Добавляем дополнительный раздел
add_submenu_page('options_toxic_comments', 'Управление содержимом', 'Проверка', 'manage_options', 'toxic_test', array(&$this, 'admin_comment_test'));
add_submenu_page('options_toxic_comments', 'Управление содержимом', 'Список сообщений', 'manage_options', 'toxic_list', array(&$this, 'admin_comment_list'));
}
В функции define_admin_hooks() регистрируем наше меню:
$this->loader->add_action('admin_menu', $plugin_admin, 'admin_generate_menu');
Теперь для страниц напишем 3 функции в классе админки:
/**
* Настройка параметров плагина
*/
public function admin_options()
{
global $wpdb;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Обновляем данные настроек
$q = $wpdb->prepare("
INSERT INTO {$wpdb->prefix}classify_comments_option (name, value)
VALUES ('address' ,%s)
ON DUPLICATE KEY UPDATE value = %s", $_POST['address'], $_POST['address']);
$wpdb->query($q);
$q = $wpdb->prepare("
INSERT INTO {$wpdb->prefix}classify_comments_option (name, value)
VALUES ('cats'
, %s)
ON DUPLICATE KEY UPDATE value = %s", $_POST['cats'], $_POST['cats']);
$wpdb->query($q);
}
$this->loadOptions();
$options = array(
'address' => $this->address,
'cats' => $this->cats
);
require_once('partials/classify-comment-admin-options.php');
}
/**
* Список проверенных сообщений
*/
public function admin_comment_list()
{
global $wpdb;
$res = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}classify_comments ORDER BY date_filtered DESC LIMIT 500");
require_once('partials/classify-comment-admin-list.php');
}
/**
* Проверка работы сервиса
*/
public function admin_comment_test()
{
$result = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$result = $this->verifyMessage($_POST['message']);
}
require_once('partials/classify-comment-admin-test.php');
}
В директории partials размещаем наши файлы представления для отображения информации. classify-comment-admin-list.php:
<?php
/**
* Provide a admin area view for the plugin
*
* This file is used to markup the admin-facing aspects of the plugin.
*
* @since 1.0.0
*
* @package Classify_Comment
* @subpackage Classify_Comment/admin/partials
*/
?>
<!-- This file should primarily consist of HTML with a little bit of PHP. -->
<div class="classify-comments-content">
<h1>Список обработанных комментариев</h1>
<table>
<tr>
<th>Автор</th>
<th>E-Mail</th>
<th>URL</th>
<th>IP</th>
<th>Комментарий</th>
<th>Агент</th>
<th>Категория</th>
<th>Дата фильтрации</th>
</tr>
<?php foreach ($res as $row) { ?>
<tr>
<td><?php echo $row->comment_author; ?></td>
<td><?php echo $row->comment_author_email; ?></td>
<td><?php echo $row->comment_author_url; ?></td>
<td><?php echo $row->comment_author_IP; ?></td>
<td><?php echo $row->comment_content; ?></td>
<td><?php echo $row->comment_agent; ?></td>
<td><?php echo $row->cat; ?></td>
<td><?php echo $row->date_filtered; ?></td>
</tr>
<?php } ?>
</table>
<p>Всего показано строк: <?php echo count($res); ?>
</div>
classify-comment-admin-options.php:
<?php
/**
* Provide a admin area view for the plugin
*
* This file is used to markup the admin-facing aspects of the plugin.
*
* @since 1.0.0
*
* @package Classify_Comment
* @subpackage Classify_Comment/admin/partials
*/
?>
<!-- This file should primarily consist of HTML with a little bit of PHP. -->
<div class="classify-comments-content">
<h1>Настройки Токсичности</h1>
<form method="POST">
<p>
<label>Адрес обработчика</label>
<input name="address" value="<?php echo $options['address']; ?>">
</p>
<p>
<label>Категории для блокировки (через запятую)</label>
<input name="cats" value="<?php echo implode(", ", $options['cats']); ?>">
</p>
<input type="submit" value="Сохранить">
</form>
</div>
classify-comment-admin-test.php:
<?php
/**
* Provide a admin area view for the plugin
*
* This file is used to markup the admin-facing aspects of the plugin.
*
* @since 1.0.0
*
* @package Classify_Comment
* @subpackage Classify_Comment/admin/partials
*/
?>
<form method="POST">
<p>
<label>Введите сообщение для проверки</label>
<input type="text" name="message" value="<?php echo $message; ?>">
</p>
<input type="submit" value="Проверить">
</form>
<?php if (isset($result) && !is_null($result)) { ?>
<div class="result">
<p>
Результат: <?php echo $result; ?>
</p>
</div>
<?php } ?>
С админкой закончили.
Основной функционал
Теперь не плохо было бы реализовать саму фильтрацию. В классе Classify_Comment_Public добавим функцию:
/**
* Проверяем комментарий на токсичность. Если это будет группа из списка настроек, то вернем результат 'spam' чтобы заблокировать.
*/
public function pre_filter_comment($approved, $commentdata)
{
if ($approved === 'spam') return $approved;
if ($this->validateCats($commentdata['comment_content'], $commentdata) === true) return 'spam';
return $approved;
}
А в функцию define_public_hooks() добавим хук:
$this->loader->add_filter('pre_comment_approved', $plugin_public, 'pre_filter_comment', 10, 2);
Тут все просто, потому как основной функционал уже реализован в классе Classify_Comment_Ext.
Последний штрих
Еще нужно реализовать маленькую функцию удаления плагина. В файле uninstall.php запишем следующее:
if (!defined('WP_UNINSTALL_PLUGIN')) {
global $wpdb;
wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}classify_comments");
wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}.classify_comments_option");
exit;
}
Теперь все готово и можно активировать плагин.
Что получилось
В админке должно появиться 3 страницы. Заходим в Токсичность и указываем адрес до сервиса и через запятую перечисляем категории, которые будем блокировать.
В меню проверки можем написать текст и посмотреть как оно работает.
А в списке сообщений можем посмотреть историю.
Исходный код можно взять из гита.