Генерация текстов в WordPress через API: плагин с кнопкой в редакторе

Небольшой плагин для WordPress: REST-маршрут вызывает Claude через wp_remote_post, а панель в редакторе блоков вставляет сгенерированный текст в запись.

4 мин · · разработка · автоматизация

Генерация текстов в WordPress через API нейросети пригодится, когда авторам нужен черновик абзаца, описание товара или вариант вступления прямо в редакторе. Ниже — небольшой плагин: серверная часть на PHP вызывает Claude через Zukko, а панель в редакторе блоков (Gutenberg) отправляет запрос и вставляет ответ в запись. Ключ API при этом не попадает в браузер.

Как устроена схема

  1. Автор пишет задание в панели «Генерация текста» в боковой колонке редактора и нажимает кнопку.
  2. JavaScript отправляет запрос на REST-маршрут сайта /wp-json/zukko/v1/generate через wp.apiFetch — он сам подставляет nonce текущего пользователя.
  3. PHP проверяет права (edit_posts) и вызывает https://api.zukko.pro/v1/chat/completions функцией wp_remote_post.
  4. Ответ возвращается в редактор и вставляется в запись новыми блоками.

Почему не звать API прямо из браузера: тогда ключ fetch_... увидит любой, кто откроет инструменты разработчика.

Ключ в wp-config.php

Ключ создайте в кабинете Zukko и добавьте в wp-config.php выше строки «That's all, stop editing!»:

bash
define( 'ZUKKO_API_KEY', 'fetch_...' );

Если wp-config.php лежит в репозитории, берите значение из окружения:

bash
define( 'ZUKKO_API_KEY', getenv( 'ZUKKO_API_KEY' ) ?: '' );

Переменную окружения задают в настройках PHP-FPM, веб-сервера или панели хостинга — способ зависит от хостинга. Для плагина удобно завести отдельный ключ с дневным лимитом в долларах: так ошибка в коде или слишком активный автор не потратят больше лимита.

Серверная часть: REST-маршрут и wp_remote_post

Создайте папку wp-content/plugins/zukko-generator/ и в ней файл zukko-generator.php:

bash
<?php
/**
 * Plugin Name: Zukko Text Generator
 * Description: Генерация текста в редакторе через Zukko API.
 * Version: 1.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

add_action( 'rest_api_init', function () {
    register_rest_route( 'zukko/v1', '/generate', array(
        'methods'             => 'POST',

Главное о wp_remote_post. По умолчанию HTTP API WordPress ждёт ответ всего 5 секунд (параметр timeout в WP_Http::request), а генерация длинного текста идёт дольше. Поэтому timeout поднят до 60. Тело передаём строкой JSON через wp_json_encode и явно ставим Content-Type: application/json. Ошибка сети приходит как WP_Error (проверяем is_wp_error), а ошибка API — как обычный ответ с кодом не 200, поэтому код проверяем отдельно через wp_remote_retrieve_response_code.

sanitize_textarea_field выбран вместо sanitize_text_field, потому что второй вырезает переносы строк, а в задании они бывают полезны.

Панель с кнопкой в редакторе блоков

Рядом создайте generator.js. Код написан без сборки (без JSX), его можно подключать как есть:

bash
(function (wp) {
    const el = wp.element.createElement;
    const { useState } = wp.element;
    const { Button, TextareaControl, Notice } = wp.components;
    const { useDispatch } = wp.data;
    const { PluginDocumentSettingPanel } = wp.editor;

    function ZukkoPanel() {
        const [prompt, setPrompt] = useState('');
        const [busy, setBusy] = useState(false);
        const [error, setError] = useState('');
        const { insertBlocks } = useDispatch('core/block-editor');

        async function generate() {

Что здесь происходит:

  • registerPlugin из пакета wp.plugins и PluginDocumentSettingPanel из wp.editor добавляют панель во вкладку настроек записи — так описано в Block Editor Handbook. В версиях WordPress до 6.6 этот компонент жил в wp.editPost; на старой версии замените wp.editor на wp.editPost.
  • wp.apiFetch автоматически добавляет заголовок X-WP-Nonce и куки текущего пользователя, поэтому permission_callback на сервере видит, кто вызывает маршрут. Ручной поиск nonce на странице не нужен.
  • wp.blocks.pasteHandler превращает текст ответа в блоки, а insertBlocks вставляет их в запись. Если нужен только заголовок или отрывок, используйте editPost({ title: data.text }) из useDispatch('core/editor').

Активируйте плагин в «Плагины», откройте любую запись — панель появится в правой колонке.

Модерация и контроль

Сгенерированный текст — черновик. Плагин ничего не публикует сам: текст попадает в редактор, автор его вычитывает. Это важно и для качества (модель может ошибиться в фактах), и для SEO: страницы, собранные без вычитки, редко полезны читателю.

Что ещё стоит добавить в рабочей версии:

  • Журнал запросов. Сохраняйте пользователя, задание, модель и размер ответа (например, через error_log или отдельную таблицу) — так видно, кто и сколько генерирует.
  • Ограничение прав. Если генерировать должны только редакторы, замените edit_posts на edit_others_posts.
  • Лимиты ключа. Дневной и месячный лимит в долларах задаётся ключу в кабинете — см. лимиты ключей.

Сколько стоит и какую модель выбрать

Модель задаётся строкой 'model' => 'claude-sonnet-5'. Цены в Zukko за 1M токенов (вход/выход): claude-sonnet-5 и claude-opus-5-5 — $0.30 / $0.30, gpt-5.6-sol — $0.30 / $0.30, gpt-5.6-luna — $0.10 / $0.10, glm-5.3-flash — $0.04 / $0.04. Актуальный список — GET https://api.zukko.pro/v1/models или страница «Модели» в кабинете.

Пример: задание с системным промптом — 300 входных токенов, ответ — 2 000 выходных. На claude-sonnet-5: (300 + 2 000) × $0.30 / 1 000 000 = $0.00069 за один текст, сто текстов — $0.069. Какая модель пишет лучше для вашего сайта, проверьте на своих задачах: дайте двум-трём моделям одни и те же 10 заданий и сравните результаты вслепую.

Частые вопросы

Почему запрос обрывается через несколько секунд?

Скорее всего, не указан timeout: по умолчанию wp_remote_post ждёт 5 секунд. Поставьте 60 или больше. Если таймаут обрывает и веб-сервер или PHP (max_execution_time), поднимите и его либо уменьшите max_tokens.

Панель не появляется в редакторе

Проверьте, что плагин активирован и generator.js загрузился (вкладка Network в инструментах разработчика). В консоли браузера будет ошибка, если не хватает зависимости из списка wp_enqueue_script. В классическом редакторе (не блочном) эта панель не работает.

Можно ли генерировать тексты массово, без редактора?

Да: та же функция с wp_remote_post вызывается из WP-CLI-команды или задачи WP-Cron, а результат сохраняется через wp_insert_post со статусом draft. Публикуйте только после вычитки.

Что делать, если ключ утёк?

Удалите его в кабинете, создайте новый и замените значение в wp-config.php. Полный ключ показывается один раз при создании — сохраните его сразу.

zukko

Платите в 25×
меньше

за Claude Code & ChatGPT

Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.