Вебхуки
Вебхук — REST API наоборот: не внешняя программа спрашивает магазин, а магазин сам отправляет HTTP-запрос на заданный адрес, когда что-то произошло. Заказ создан — склад узнаёт об этом через секунду, без постоянных опросов.
Создание в панели
Откройте «WooCommerce → Настройки → Дополнительно → Вебхуки» и нажмите «Добавить вебхук»:
| Поле | Что указать |
|---|---|
| Название | Любое, для себя: «Заказы на склад» |
| Статус | «Активный» |
| Тема | Событие: «Заказ создан» |
| URL доставки | Адрес получателя: https://erp.example.com/woo-webhook.php |
| Секретный ключ | Строка для подписи запросов |
После сохранения каждый новый заказ будет уходить на указанный адрес запросом POST.
Темы
| Тема | Когда отправляется |
|---|---|
order.created | Заказ создан |
order.updated | Заказ изменён, в том числе состояние |
product.updated | Товар изменён |
customer.created | Зарегистрирован покупатель |
coupon.created | Создан купон |
Для каждой сущности есть события created, updated и deleted.
Что приходит
Тело запроса — JSON той же структуры, что и ответ REST API: для темы order.created это заказ целиком. Сведения о событии лежат в заголовках:
| Заголовок | Что в нём |
|---|---|
X-WC-Webhook-Topic | Тема: order.created |
X-WC-Webhook-Signature | Подпись тела запроса |
X-WC-Webhook-Delivery-ID | Номер доставки |
X-WC-Webhook-Source | Адрес магазина |
Получатель
Вебхук принимает другая программа. Вот минимальный получатель на PHP — файл лежит на сервере учётной системы, а не в плагине:
// erp.example.com/woo-webhook.php
$secret = 'your-webhook-secret';
$body = file_get_contents('php://input');
$expected = base64_encode(hash_hmac('sha256', $body, $secret, true));
$actual = $_SERVER['HTTP_X_WC_WEBHOOK_SIGNATURE'] ?? '';
if (!hash_equals($expected, $actual)) {
http_response_code(401);
exit;
}
$order = json_decode($body, true);
file_put_contents(__DIR__ . '/orders.log', $order['id'] . ' ' . $order['total'] . PHP_EOL, FILE_APPEND);
http_response_code(200);Подпись — это HMAC-SHA256 от тела запроса с секретным ключом, закодированный в Base64. Получатель считает её сам и сравнивает с заголовком: совпадение доказывает, что запрос прислал ваш магазин. Оформите заказ — в файле orders.log появится строка с номером и суммой.
Создание в коде
Вебхук — объект WC_Webhook. Файл scripts/create-webhook.php:
// wp-content/plugins/acme-shop/scripts/create-webhook.php
$webhook = new WC_Webhook();
$webhook->set_name('Заказы на склад');
$webhook->set_user_id(1);
$webhook->set_topic('order.created');
$webhook->set_delivery_url('https://erp.example.com/woo-webhook.php');
$webhook->set_secret('your-webhook-secret');
$webhook->set_status('active');
$webhook->save();Запустите файл через wp eval-file — вебхук появится в списке в панели. Пользователь из set_user_id() определяет, с какими правами собираются данные для отправки.
Как идёт доставка
Запрос отправляется не в момент оформления заказа, а чуть позже, фоновой задачей — покупатель не ждёт ответа чужого сервера. Получатель должен ответить кодом из диапазона 200–299. После пяти неудачных доставок подряд WooCommerce отключает вебхук, и его включают заново в панели.
Журнал доставок находится в «WooCommerce → Статус → Журналы», источник webhooks-delivery.
Вебхук или REST API
| Задача | Что выбрать |
|---|---|
| Узнать о событии сразу | Вебхук |
| Получить данные по запросу | REST API |
| Изменить данные в магазине | REST API |
| Сверить всё раз в сутки | REST API с modified_after |
Обычно их сочетают: вебхук сообщает о событии, а раз в сутки интеграция сверяется через REST API на случай потерянных доставок.
Частая ошибка
Получатель не проверяет подпись и обрабатывает всё, что пришло на адрес. Адрес вебхука рано или поздно становится известен, и любой может прислать поддельный «оплаченный заказ». Проверка hash_equals() с секретным ключом обязательна — и считать подпись нужно от исходного тела запроса, а не от разобранного и собранного заново JSON.