Если остатки в магазине ведутся не только в WooCommerce, а приходят из 1С, складской системы или просто из выгрузки поставщика, ручное обновление быстро становится источником ошибок. Типичный сценарий: файл с остатками уже есть, но после импорта часть товаров не обновилась, у вариаций остались старые значения, а у некоторых позиций остаток вообще стал отрицательным после продажи.
Ниже разберём рабочую схему: как принимать CSV-отчёт, сопоставлять товары по артикулу, обновлять остатки без лишних действий и проверять, что синхронизация действительно сработала.
Когда проблема проявляется на практике
Чаще всего сбой выглядит не как одна явная ошибка, а как набор мелких несоответствий:
- товар в админке показывает старый остаток, хотя в CSV уже другое значение;
- вариации обновляются не все, потому что импорт сопоставляет только родительский товар;
- после импорта у части товаров включается статус
outofstock, хотя остаток больше нуля; - артикулы в файле и в магазине записаны по-разному: пробелы, регистр, лишние символы;
- импорт проходит, но в логах нет понятного сообщения, какие строки были пропущены.
Что проверить до настройки импорта
Сначала стоит убедиться, что у вас есть стабильный ключ сопоставления. Для WooCommerce это обычно SKU. Если артикул не заполнен или не уникален, автоматическая синхронизация будет давать случайные пропуски. Также проверьте, что в CSV остаток хранится в одном поле и без форматирования вроде 1 200 или 1,200, если импортёр ожидает целое число.
Какой способ выбрать: плагин, код или гибрид
Для большинства магазинов есть три реалистичных варианта. Если нужен быстрый запуск без разработки, подойдёт импорт через штатный CSV-импорт WooCommerce или через специализированный импортёр. Если файл приходит регулярно и структура стабильна, надёжнее сделать небольшой обработчик на PHP и запускать его по расписанию. Гибридный вариант удобен, когда импортёр уже есть, но нужно доработать сопоставление или очистку данных перед обновлением.
| Подход | Когда уместен | Плюсы | Минусы |
|---|---|---|---|
| Штатный CSV-импорт WooCommerce | Разовые или редкие обновления | Не требует кода, понятен администратору | Слабее контроль над логикой сопоставления |
| Импортёр с настройкой полей | Регулярные выгрузки от поставщика | Можно настроить карту полей и расписание | Зависит от конкретного плагина и его формата |
| Собственный PHP-скрипт | Нужна точная логика обновления | Полный контроль над SKU, статусами и логами | Требует поддержки и аккуратной проверки |
Пошаговое решение: обновляем остатки по CSV через код
Если файл приходит в предсказуемом формате, проще всего написать обработчик, который читает CSV, ищет товар по артикулу и обновляет остаток через стандартные функции WooCommerce. Такой подход полезен, когда нужно исключить ручной импорт и не зависеть от интерфейса плагина.
Пример структуры CSV
Пусть файл выглядит так:
sku,stock,status
TSHIRT-001,12,instock
TSHIRT-002,0,outofstock
TSHIRT-003,5,instockЗдесь sku — артикул, stock — количество, status — статус наличия. Если статус не нужен, его можно вычислять по остатку.
Пример импорта в WooCommerce
<?php
add_action( 'admin_post_wpdo_import_stock_csv', 'wpdo_import_stock_csv' );
function wpdo_import_stock_csv() {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_die( 'Недостаточно прав.' );
}
check_admin_referer( 'wpdo_import_stock_csv' );
if ( empty( $_FILES['stock_csv']['tmp_name'] ) ) {
wp_die( 'CSV-файл не загружен.' );
}
$file = fopen( $_FILES['stock_csv']['tmp_name'], 'r' );
if ( ! $file ) {
wp_die( 'Не удалось открыть CSV.' );
}
$header = fgetcsv( $file, 0, ',' );
if ( ! $header ) {
wp_die( 'Пустой CSV.' );
}
$map = array_flip( $header );
$updated = 0;
$skipped = 0;
while ( $row = fgetcsv( $file, 0, ',' ) ) {
$sku = isset( $row[ $map['sku'] ] ) ? trim( $row[ $map['sku'] ] ) : '';
$stock = isset( $row[ $map['stock'] ] ) ? (int) $row[ $map['stock'] ] : null;
$status = isset( $row[ $map['status'] ] ) ? trim( $row[ $map['status'] ] ) : '';
if ( '' === $sku || null === $stock ) {
$skipped++;
continue;
}
$product_id = wc_get_product_id_by_sku( $sku );
if ( ! $product_id ) {
$skipped++;
continue;
}
$product = wc_get_product( $product_id );
if ( ! $product ) {
$skipped++;
continue;
}
$product->set_manage_stock( true );
$product->set_stock_quantity( $stock );
if ( in_array( $status, array( 'instock', 'outofstock', 'onbackorder' ), true ) ) {
$product->set_stock_status( $status );
} else {
$product->set_stock_status( $stock > 0 ? 'instock' : 'outofstock' );
}
$product->save();
$updated++;
}
fclose( $file );
wp_safe_redirect( add_query_arg( array(
'updated' => $updated,
'skipped' => $skipped,
), admin_url( 'tools.php' ) ) );
exit;
}Этот код лучше использовать как основу для внутреннего инструмента, а не как публичную форму. Он намеренно завязан на права manage_woocommerce и nonce-проверку, чтобы случайно не открыть импорт всем подряд.
Как не сломать вариации
У вариативных товаров артикул часто хранится именно у вариации, а не у родителя. Это нормально: wc_get_product_id_by_sku() вернёт ID той записи, где SKU действительно задан. Проблема возникает, если в CSV указан артикул родительского товара, а остаток нужно менять у конкретной вариации. В таком случае сначала нужно договориться о формате файла: либо SKU на уровне вариации, либо отдельная колонка с ID вариации.
Если нужен импорт без кода
Когда разработка не входит в план, используйте импортёр, который умеет сопоставлять поля CSV с полями товара WooCommerce. Важно не просто загрузить файл, а проверить три вещи:
- какое поле используется для поиска товара — SKU, ID или название;
- обновляется ли остаток у вариаций отдельно;
- есть ли режим пропуска строк с пустым значением, а не перезапись нулями.
Если импортёр поддерживает предварительный просмотр, не пропускайте этот шаг. Именно там обычно видно, что колонка с остатком распознана как текст, а не как число.
Проверка результата после внедрения
После первого запуска не ограничивайтесь визуальной проверкой в админке. Лучше проверить синхронизацию по нескольким уровням:
- Откройте товар в админке и убедитесь, что остаток изменился.
- Проверьте карточку товара на витрине: статус наличия должен совпадать с остатком.
- Если включён кэш, очистите его и проверьте страницу в режиме инкогнито.
- Для вариативного товара откройте конкретную вариацию и сравните её SKU и остаток с CSV.
- Посмотрите, не появились ли в логах пропущенные строки или ошибки прав доступа.
Если у вас есть доступ к базе данных, можно дополнительно проверить метаполя товара, но для обычной диагностики достаточно админки и фронтенда. Главное — убедиться, что обновление не только прошло, но и отразилось в каталоге и в корзине.
Частые ошибки и как их исправить
SKU не найден
Обычно это означает, что в CSV есть лишние пробелы, другой регистр или артикул записан не в том поле. Сначала нормализуйте данные: trim(), удаление неразрывных пробелов, единый формат SKU. Если артикулы в магазине уже дублируются, сначала исправьте их, иначе импорт будет обновлять не тот товар.
Остаток обновился, но статус не сменился
Так бывает, если импорт меняет только число, но не вызывает set_stock_status(). В WooCommerce лучше обновлять и количество, и статус одновременно. Если остаток стал нулевым, товар должен перейти в outofstock, иначе покупатель увидит его как доступный.
Импорт ломает вариации
Причина обычно в том, что файл составлен под простые товары, а в магазине есть вариативные. Для вариаций нужен отдельный контроль: либо импорт по SKU вариации, либо отдельная логика поиска дочерних товаров. Не пытайтесь одним и тем же правилом обновлять все типы товаров без проверки.
После импорта цифры в админке верные, а на сайте старые
Это уже похоже на кэширование. Очистите кэш страницы товара, объектный кэш, если он используется, и проверьте, не отдаёт ли CDN старую версию. Для магазинов с частыми обновлениями остатков это критично: витрина должна показывать актуальное наличие, а не вчерашний снимок.
Практические советы по безопасности и производительности
Импорт остатков — операция, которая может затронуть сотни или тысячи товаров. Поэтому не стоит запускать её через открытый URL без ограничений. Лучше использовать административный экран, проверку прав и nonce. Если файл большой, разбивайте импорт на порции, иначе можно упереться в лимиты времени выполнения PHP.
Для регулярной синхронизации полезно вести лог: дата запуска, количество обновлённых строк, количество пропусков, список SKU, которые не нашли товар. Это экономит время при разборе инцидентов и помогает быстро понять, где сломалась цепочка: в выгрузке, в сопоставлении или в самом WooCommerce.
Если нужен более удобный редактор правил импорта или дополнительные блоки для описания товара, можно посмотреть в сторону решений WPShop, например Clearfy Pro для чистки и оптимизации сайта: https://wpshop.ru/plugins/clearfy. Но для самой синхронизации остатков всё равно важнее корректная структура данных и проверяемая логика обновления.
Что считать успешным результатом
Решение можно считать рабочим, если после импорта выполняются все три условия: SKU находятся без ручной правки, остатки совпадают с CSV, а статус наличия на витрине меняется без задержки после очистки кэша. Если хотя бы один из этих пунктов не выполняется, проблему нужно искать в сопоставлении полей, типе товара или кэшировании, а не в самом CSV.