Как запретить изменение адреса и стоимости заказа в WooCommerce после оплаты

Сценарий простой: заказ уже оплачен, а менеджер или клиент пытается поменять адрес доставки, состав заказа или сумму. В WooCommerce это часто происходит не из-за одной настройки, а из-за сочетания прав пользователя, статуса заказа и того, как у вас устроена админка. Если это не ограничить, легко получить расхождения между оплатой, складом и документами.

Ниже — рабочий способ закрыть редактирование ключевых полей после оплаты, не ломая обычную обработку заказов до оплаты.

Когда проблема проявляется на практике

Чаще всего жалоба выглядит так: заказ в статусе processing или completed, но в админке его всё ещё можно открыть, поменять адрес, товары или сумму, а затем сохранить. Иногда изменения проходят даже после того, как платёж уже подтверждён. Это особенно заметно, если у вас подключены ручные правки менеджерами, интеграция с CRM или нестандартные роли пользователей.

Если бизнес-процесс требует, чтобы оплаченный заказ был неизменяемым, нужно ограничивать не только интерфейс, но и серверную обработку. Скрыть поля в форме недостаточно: данные можно отправить запросом напрямую.

Диагностика: что именно у вас сейчас разрешено

Перед правкой кода проверьте три вещи:

  • какие статусы у заказов считаются «оплаченными» в вашей схеме;
  • есть ли у менеджеров права на редактирование заказов в админке;
  • не меняет ли заказ сторонний плагин через REST API, CRM или кастомный endpoint.

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

  • billing/shipping адрес;
  • позиции заказа;
  • итоговую сумму или доставку;
  • статус заказа.

Если хотя бы одно из этих действий проходит без ошибок, значит блокировка у вас пока не работает на уровне сохранения данных.

Пошаговое решение: блокируем редактирование после оплаты

Надёжнее всего разделить задачу на две части: запретить изменения в интерфейсе и остановить сохранение на сервере. Ниже пример для functions.php дочерней темы или собственного мини-плагина.

1. Скрываем поля редактирования для оплаченных заказов

Это не защита, а удобство: менеджер сразу видит, что заказ уже закрыт для правок.

add_action( 'admin_head', function () {
    global $post;

    if ( ! $post || 'shop_order' !== $post->post_type ) {
        return;
    }

    $order = wc_get_order( $post->ID );
    if ( ! $order ) {
        return;
    }

    $paid_statuses = array( 'processing', 'completed', 'on-hold' );

    if ( in_array( $order->get_status(), $paid_statuses, true ) ) {
        echo '<style>
            #woocommerce-order-items,
            .woocommerce_order_items_wrapper,
            .order_data_column .address,
            .order_data_column .edit_address {
                pointer-events: none;
                opacity: .65;
            }
        </style>';
    }
} );

Этот приём не блокирует сохранение сам по себе, но снижает риск случайных правок.

2. Запрещаем сохранение адреса и суммы на сервере

Для реальной блокировки используйте фильтр woocommerce_before_order_object_save. Он срабатывает до записи заказа в базу и позволяет сравнить старые и новые значения.

add_action( 'woocommerce_before_order_object_save', function ( $order ) {
    if ( ! $order instanceof WC_Order ) {
        return;
    }

    $paid_statuses = array( 'processing', 'completed' );

    if ( ! in_array( $order->get_status(), $paid_statuses, true ) ) {
        return;
    }

    $order_id = $order->get_id();
    $original  = wc_get_order( $order_id );

    if ( ! $original ) {
        return;
    }

    $changed = false;

    if ( $order->get_billing_address_1() !== $original->get_billing_address_1() ) {
        $changed = true;
    }

    if ( $order->get_shipping_address_1() !== $original->get_shipping_address_1() ) {
        $changed = true;
    }

    if ( (float) $order->get_total() !== (float) $original->get_total() ) {
        $changed = true;
    }

    if ( $changed ) {
        throw new Exception( 'Оплаченный заказ нельзя редактировать.' );
    }
}, 10, 1 );

Такой подход полезен, если у вас есть менеджеры, которые правят заказы вручную, или интеграции, которые пытаются перезаписать поля после оплаты.

3. Если нужно запретить только адрес, а сумму оставить

Иногда бизнес-процесс допускает корректировку доставки, но не позволяет менять стоимость. Тогда лучше проверять только адресные поля и не трогать итог заказа.

add_action( 'woocommerce_before_order_object_save', function ( $order ) {
    if ( ! $order instanceof WC_Order ) {
        return;
    }

    if ( ! in_array( $order->get_status(), array( 'processing', 'completed' ), true ) ) {
        return;
    }

    $original = wc_get_order( $order->get_id() );
    if ( ! $original ) {
        return;
    }

    $address_fields = array(
        'billing_first_name',
        'billing_last_name',
        'billing_address_1',
        'billing_city',
        'billing_postcode',
        'shipping_first_name',
        'shipping_last_name',
        'shipping_address_1',
        'shipping_city',
        'shipping_postcode',
    );

    foreach ( $address_fields as $field ) {
        $getter = 'get_' . $field;
        if ( method_exists( $order, $getter ) && method_exists( $original, $getter ) ) {
            if ( $order->{$getter}() !== $original->{$getter}() ) {
                throw new Exception( 'Адрес оплаченного заказа менять нельзя.' );
            }
        }
    }
}, 10, 1 );

Что выбрать: плагин, код или гибрид

ПодходКогда подходитМинус
КодНужно закрыть конкретные поля и статусыТребует теста после обновлений WooCommerce
Плагин для управления ролямиНужно ограничить только менеджеров без разработкиНе всегда блокирует сохранение на уровне данных
ГибридНужен и контроль интерфейса, и защита от прямого сохраненияЧуть больше поддержки

Если у вас небольшой магазин и правки делает один человек, код обычно проще и прозрачнее. Если заказами занимается отдел продаж, лучше сочетать серверную проверку с ограничением ролей.

Как проверить, что решение сработало

После внедрения не ограничивайтесь визуальной проверкой в админке. Нужны три теста:

  1. Откройте оплаченный заказ и попробуйте изменить адрес вручную через форму.
  2. Попробуйте сохранить заказ после изменения через браузерную консоль или повторной отправкой формы.
  3. Если у вас есть интеграция с CRM, проверьте, не перезаписывает ли она заказ после смены статуса.

Если код работает корректно, WooCommerce должен вернуть ошибку сохранения, а изменения не должны попасть в базу. Для дополнительной проверки сравните данные заказа до и после теста в таблице wp_postmeta или через экран заказа в админке.

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

Слишком широкий список статусов

Если вы включили в блокировку on-hold, но у вас этот статус используется до фактической оплаты, менеджеры потеряют возможность вносить рабочие правки слишком рано. Проверьте, какие статусы реально означают «деньги уже получены».

Проверка только в интерфейсе

Скрыть поля CSS-ом недостаточно. Любой запрос можно отправить повторно. Нужна серверная проверка через хук сохранения заказа.

Конфликт с плагинами доставки или CRM

Если сторонний плагин пересохраняет заказ, он может вызывать исключение. В таком случае проверьте, на каком этапе он меняет данные, и при необходимости ограничьте проверку только ручным редактированием в админке.

Использование неподходящего хука

Иногда пытаются ловить изменения через save_post. Для WooCommerce-заказов это менее удобно, потому что объект заказа может сохраняться не так, как обычная запись WordPress. Для проверки изменений заказа лучше работать с объектом WC_Order.

Безопасность и производительность: что учесть

Не храните логику блокировки в случайном сниппете без контроля версий. Лучше вынести её в маленький mu-plugin или отдельный плагин проекта. Так код не потеряется при смене темы.

Если у вас высокая нагрузка и много заказов, не делайте тяжёлые запросы к базе внутри проверки. Сравнивайте только нужные поля текущего объекта и оригинального заказа. Это дешевле, чем строить дополнительные запросы на каждом сохранении.

И ещё один практический момент: если бизнес допускает изменения после оплаты только через отдельную процедуру, лучше не «разрешать всем и надеяться на дисциплину», а явно описать, кто и как может вносить правки. Тогда код будет соответствовать процессу, а не спорить с ним.

Хотите научиться создавать сайты и зарабатывать на этом от 30 000 рублей в месяц?

Записаться на курс сейчас