Типичный сценарий: заказ уже создаётся в WooCommerce, но в 1С или CRM нужно передавать не только статус, а ещё и служебные метки — например, source, manager_id, payment_flag, external_note. Проблема в том, что стандартный REST API WooCommerce не всегда удобно использовать для таких полей «как есть»: часть данных не попадает в ответ, часть теряется при обновлении, а часть лучше хранить отдельно, чтобы не ломать логику магазина.
Ниже — рабочая схема: где хранить метки, как отдать их в REST API, как обновлять без перезаписи лишних полей и как проверить, что синхронизация действительно работает.
Когда проблема проявляется на практике
Обычно всё выглядит так:
- интеграция получает заказ через
/wp-json/wc/v3/orders, но не видит нужные служебные поля; - при обновлении заказа из CRM часть меток пропадает;
- вебхук от платёжной системы приходит раньше, чем внешний сервис успевает записать свои данные;
- в заказе появляются дублирующиеся мета-ключи, и в интерфейсе админки видно одно значение, а в API — другое.
Если у вас уже есть кастомные поля в заказах, это не значит, что они автоматически безопасны для обмена. Для интеграций важны три вещи: стабильный ключ, предсказуемый формат и явное правило обновления.
Диагностика: что проверить до правок кода
Сначала стоит понять, где именно теряются данные. Это экономит время и помогает не чинить не ту сторону интеграции.
Проверьте, как поле хранится в базе
Для заказа WooCommerce использует метаданные поста. Если поле записано через update_post_meta() или через CRUD-объект заказа, оно может быть доступно по-разному в зависимости от того, как именно вы его читаете.
Быстрая проверка через WP-CLI:
wp post meta list 123 --format=tableГде 123 — ID заказа. Если нужного ключа нет, проблема не в REST API, а в том, что поле вообще не сохраняется.
Проверьте ответ REST API
Посмотрите, есть ли метка в стандартном ответе:
curl -u ck_xxx:cs_xxx https://example.com/wp-json/wc/v3/orders/123Если поле не возвращается, его нужно явно добавить в ответ через фильтр или зарегистрировать как meta field с показом в REST.
Проверьте, кто перезаписывает значение
Частая ситуация: одно значение пишет сайт, другое — CRM, третье — webhook. В итоге последнее обновление затирает всё остальное. Для таких полей лучше заранее определить владельца данных: кто создаёт, кто обновляет, кто только читает.
Как хранить метки заказа без конфликтов
Для интеграций обычно подходят два подхода:
| Подход | Когда использовать | Минус |
|---|---|---|
| Метаполя заказа | Нужно хранить данные вместе с заказом и передавать их в API | Нужно явно управлять выводом и обновлением |
| Отдельная таблица/сервис | Данных много, есть сложная история изменений | Сложнее поддержка и синхронизация |
| Только внешняя CRM | WooCommerce не должен быть источником этих данных | В админке магазина метки не видны без доп. логики |
Если задача — просто передавать несколько служебных меток, метаполя заказа обычно достаточно. Главное — не смешивать пользовательские заметки, технические флаги и данные внешней системы в одном ключе.
Пошаговое решение: добавить метки в REST API заказа
Ниже пример, который добавляет кастомное поле в ответ WooCommerce REST API и позволяет безопасно обновлять его через стандартный endpoint заказа.
1. Зарегистрируйте мета-поле для REST
add_action( 'init', function() {
register_post_meta( 'shop_order', '_external_source', array(
'type' => 'string',
'single' => true,
'show_in_rest' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => function() {
return current_user_can( 'edit_shop_orders' );
},
) );
} );Такой вариант удобен, если внешний сервис должен читать и обновлять значение через REST, а не через отдельный кастомный endpoint.
2. Добавьте поле в ответ заказа, если нужен свой формат
Иногда стандартного представления meta недостаточно. Например, CRM ждёт не массив метаданных, а плоское поле source. Тогда можно расширить ответ заказа через фильтр WooCommerce.
add_filter( 'woocommerce_rest_prepare_shop_order_object', function( $response, $order, $request ) {
$data = $response->get_data();
$data['external_source'] = $order->get_meta( '_external_source', true );
$response->set_data( $data );
return $response;
}, 10, 3 );Это не создаёт отдельный endpoint и не ломает стандартный API. Но важно помнить: если вы добавляете поле в ответ, нужно отдельно продумать его обновление.
3. Разрешите обновление только нужных ключей
Чтобы внешняя система не перезаписывала лишнее, лучше принимать только конкретные поля и только от доверенного источника. Если интеграция идёт через стандартный REST API с авторизацией, можно ограничить список обновляемых ключей.
add_action( 'woocommerce_rest_insert_shop_order_object', function( $order, $request, $creating ) {
if ( ! $request->has_param( 'external_source' ) ) {
return;
}
$value = sanitize_text_field( $request->get_param( 'external_source' ) );
$order->update_meta_data( '_external_source', $value );
$order->save();
}, 10, 3 );Здесь важно не сохранять заказ в каждом месте подряд. Если вы уже работаете с объектом $order, лучше обновить мета и сохранить один раз.
Если синхронизация идёт из CRM: как не потерять данные при обратном обновлении
Обратная синхронизация часто ломается из-за того, что CRM отправляет только часть полей. Если вы делаете PUT или POST на заказ, не отправляйте пустые значения для полей, которые не хотите менять.
Практически это означает:
- не передавать ключ, если значение не изменилось;
- не использовать пустую строку как «нет данных», если для вас это невалидное состояние;
- на стороне WordPress проверять, пришёл ли параметр вообще, а не только его значение.
Пример обновления через REST из внешнего сервиса:
curl -X PUT https://example.com/wp-json/wc/v3/orders/123 \
-u ck_xxx:cs_xxx \
-H 'Content-Type: application/json' \
-d '{
"external_source": "crm",
"status": "processing"
}'Если CRM не умеет работать с кастомными полями WooCommerce напрямую, часто проще сделать небольшой промежуточный endpoint в WordPress, который принимает только нужные метки и валидирует их отдельно.
Проверка результата после внедрения
После правок не ограничивайтесь тем, что «ошибок нет». Проверьте цепочку целиком.
- Создайте тестовый заказ в WooCommerce.
- Запишите в него метку через админку, код или внешний запрос.
- Получите заказ через
/wp-json/wc/v3/orders/<id>и проверьте наличие поля. - Обновите только одно значение из CRM и убедитесь, что остальные метки не изменились.
- Проверьте запись в базе через
wp post meta get <id> _external_source.
Если поле видно в API, но не сохраняется после обновления, почти всегда проблема в том, что обновляющий запрос не проходит через тот же слой, где вы добавили обработчик. Например, вы расширили ответ заказа, но не добавили обработку входящих данных.
Частые ошибки и как их исправить
Поле есть в базе, но не видно в REST
Причина обычно в том, что мета не зарегистрирована с show_in_rest, либо вы смотрите не тот endpoint. Для WooCommerce заказов важно понимать разницу между стандартным WordPress REST и WooCommerce REST API.
Метка затирается при каждом обновлении заказа
Это происходит, когда внешний сервис отправляет полный объект заказа, но часть полей пустая. Исправление простое: обновляйте только те ключи, которые реально менялись, и не пишите пустые значения без необходимости.
Дубли ключей в метаданных
Если один и тот же ключ создаётся несколько раз без single => true или без аккуратной записи через CRUD, в API можно увидеть неожиданное поведение. Для служебных меток почти всегда нужен один ключ — одно значение.
Ошибки авторизации при записи
Если внешний сервис не может обновить заказ, проверьте права пользователя API-ключа. Для WooCommerce это обычно уровень доступа к заказам, а не только к чтению каталога.
Чек-лист перед запуском в продакшн
- метка хранится в одном понятном ключе, без дубликатов;
- поле зарегистрировано для REST или явно добавлено в ответ;
- обновление принимает только нужные параметры;
- пустые значения не затирают существующие данные;
- проверены права пользователя API;
- есть тестовый заказ для повторной проверки после деплоя;
- в логах видно, какой сервис и когда менял метку.
Безопасность и производительность
Если синхронизация идёт часто, не делайте тяжёлую обработку прямо в REST-хуке. Сначала сохраните данные, а внешнюю отправку в CRM или 1С вынесите в отдельную задачу или очередь. Это снижает шанс таймаута и не блокирует создание заказа.
Для безопасности:
- не отдавайте технические метки всем подряд, если они содержат внутренние идентификаторы;
- проверяйте права доступа в
auth_callbackили перед сохранением; - не храните секреты интеграции в метаполях заказа;
- логируйте только то, что нужно для отладки, без персональных данных.
Если у вас много служебных полей и часть из них нужна только для админки, имеет смысл скрыть их из публичного ответа и показывать только в нужном интерфейсе. Это уменьшает риск случайной утечки и делает API понятнее для интеграций.