Плагин для WordPress

И так, ранее я писал про классификацию сообщеий. Теперь неплохо дыло бы использовать его на практике. Заодно не плохо было бы разобраться как написать пдлагин для 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 страницы. Заходим в Токсичность и указываем адрес до сервиса и через запятую перечисляем категории, которые будем блокировать.

Настройка плагина

В меню проверки можем написать текст и посмотреть как оно работает.

Проверка сообщения

А в списке сообщений можем посмотреть историю.

История обработки

Исходный код можно взять из гита.

Поделиться

Оставьте комментарий