WooCommerce REST API: автоматизация обновления статуса заказа после callback платёжной системы

Проблема: некорректное обновление статусов заказов после callback платёжных систем

При интеграции WooCommerce с платёжными шлюзами часто возникает задача автоматически менять статус заказа после получения callback (уведомления) от платёжной системы. Типичные проблемы:

  • Заказы не обновляются из-за ошибок авторизации API.
  • Обновление происходит некорректно, например, статус не соответствует действительности.
  • Отсутствует обработка ошибок, что приводит к потере данных.
  • Повторные вызовы callback вызывают дублирование или конфликт статусов.

Диагностика проблемы

Для начала проверьте логи сервера и WooCommerce. Включите отладку WooCommerce REST API, добавив в wp-config.php:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

После этого найдите файл wp-content/debug.log и ищите ошибки, связанные с REST API и callback.

Проверьте, что ключи REST API имеют права на изменение заказов. В WooCommerce откройте WooCommerce > Settings > Advanced > REST API, проверьте права «Read/Write».

Также проверьте, что callback от платёжной системы корректно отправляет данные и заголовки (например, Content-Type: application/json) и что URL для callback совпадает с ожидаемым.

Пошаговое решение

1. Создаём кастомный endpoint для приёма callback

Добавьте в functions.php вашей темы или в отдельный плагин следующий код для регистрации endpoint:

add_action('rest_api_init', function () {
    register_rest_route('custom/v1', '/payment-callback', array(
        'methods' => 'POST',
        'callback' => 'handle_payment_callback',
        'permission_callback' => '__return_true', // Для безопасности лучше реализовать проверку
    ));
});

2. Обработка callback и обновление статуса заказа

Основная функция для обработки данных и обновления заказа:

function handle_payment_callback(WP_REST_Request $request) {
    $params = $request->get_json_params();

    if (empty($params['order_id']) || empty($params['payment_status'])) {
        return new WP_REST_Response(['error' => 'Missing order_id or payment_status'], 400);
    }

    $order_id = intval($params['order_id']);
    $payment_status = sanitize_text_field($params['payment_status']);

    $order = wc_get_order($order_id);
    if (!$order) {
        return new WP_REST_Response(['error' => 'Order not found'], 404);
    }

    // Проверяем текущий статус, чтобы избежать некорректных переходов
    $current_status = $order->get_status();

    // Пример логики статусов
    if ($payment_status === 'paid' && $current_status !== 'completed') {
        $order->update_status('completed', 'Оплата подтверждена через callback.');
    } elseif ($payment_status === 'failed' && $current_status !== 'cancelled') {
        $order->update_status('cancelled', 'Оплата не прошла.');
    } else {
        // Другие статусы или повторный callback
        return new WP_REST_Response(['message' => 'No status change needed'], 200);
    }

    return new WP_REST_Response(['message' => 'Order status updated'], 200);
}

3. Обработка ошибок и логирование

Для надёжности добавьте логирование всех запросов и ошибок в файл, чтобы можно было отследить инциденты:

function log_payment_callback($data) {
    $log_file = WP_CONTENT_DIR . '/payment-callback.log';
    $entry = date('Y-m-d H:i:s') . ' - ' . json_encode($data) . "\n";
    file_put_contents($log_file, $entry, FILE_APPEND);
}

// Вызов логирования внутри handle_payment_callback
log_payment_callback($params);

4. Защита endpoint

Для безопасности добавьте проверку секретного ключа или подписи от платёжной системы, например, в permission_callback или внутри обработчика:

function check_callback_auth($request) {
    $headers = $request->get_headers();
    if (empty($headers['x-custom-signature'])) {
        return false;
    }
    $signature = $headers['x-custom-signature'][0];
    $secret = 'ваш_секретный_ключ';
    $body = $request->get_body();
    $calculated = hash_hmac('sha256', $body, $secret);
    return hash_equals($calculated, $signature);
}

// В регистрации маршрута
register_rest_route('custom/v1', '/payment-callback', array(
    'methods' => 'POST',
    'callback' => 'handle_payment_callback',
    'permission_callback' => 'check_callback_auth',
));

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

1. Отправьте тестовый POST-запрос на /wp-json/custom/v1/payment-callback с корректным JSON, например:

{
  "order_id": 123,
  "payment_status": "paid"
}

2. Проверьте, что статус заказа действительно изменился в админке WooCommerce.

3. Проверьте лог-файл wp-content/payment-callback.log на предмет записей.

4. Попробуйте отправить запрос с неверным секретом и убедитесь, что доступ закрыт.

Частые ошибки и как исправить

  • 401 Unauthorized — проверьте корректность и права REST API ключей или реализуйте корректную проверку подписи.
  • 400 Bad Request — убедитесь, что JSON корректный и содержит все необходимые поля.
  • Статус не меняется — проверьте логику в коде, не вызывается ли update_status с текущим статусом, или не блокирует ли фильтр смену статуса.
  • Дублирование действий при повторных callback — добавьте проверку текущего статуса и игнорируйте повторные одинаковые статусы.
  • Отсутствие логов — проверьте права на запись в папку wp-content и включен ли режим отладки.

Практические советы по безопасности и производительности

  • Всегда проверяйте подпись или секретный ключ в callback для предотвращения подделки запросов.
  • Используйте nonce или OAuth, если платёжная система поддерживает, для дополнительной защиты.
  • Логируйте только нужные данные, избегайте записи персональных данных клиентов.
  • Используйте транзакции или блокировки, если ваш магазин принимает много одновременных callback – чтобы избежать гонок статусов.
  • Кэширование не применяйте для callback endpoint – он должен обрабатывать каждый запрос в реальном времени.

Сравнение вариантов реализации автоматизации обновления заказов

МетодПлюсыМинусыПример
Использование кастомного REST API endpoint Гибкость, полное управление логикой; легко интегрируется с любыми платёжными системами Требует разработки и поддержки; необходимость защиты endpoint Код из статьи выше
Использование готовых плагинов (например, WooCommerce Payment Gateway) Быстрая настройка; поддержка популярных шлюзов Ограниченная кастомизация, возможны конфликты; не всегда есть нужная логика WooCommerce официальные плагины
Обработка callback через action hooks WooCommerce Интеграция с внутренними событиями WooCommerce Сложнее для кастомных платёжных систем; callback нужно правильно маршрутизировать add_action('woocommerce_payment_complete', 'my_callback_func');

Шаблоны для WP Плагины для WP