Сверка изображений каталога с учётной системой
Задача
Изображения товаров приходят в магазин из учётной системы. Они определяют не только вид карточки: если у всех вариантов товара исчезли основные фотографии, родительский товар нужно убрать с витрины. Когда изображения снова появятся, товар должен вернуться автоматически, если именно этот обмен ранее его скрыл.
Самый опасный сценарий — неполный ответ внешнего API. Если принять отсутствие строки в выгрузке за команду удалить файл, временный сбой может снять с витрины множество товаров. При этом бесконечно хранить изображения, действительно удалённые в учёте, тоже нельзя. Требовалась сверка, которая различает подтверждённое удаление, ошибку связи и фотографии, добавленные в магазине вручную.
Роль и объём
В плагине обмена WooCommerce с учётной системой реализовал загрузку изображений и отдельный проход по прежним привязкам, которых больше нет в списке API. Связал результат с видимостью вариативного товара, добавил ограничения на объём изменений, журнал решений и диагностику карточки по SKU. Этот кейс посвящён сохранности каталога при обновлении медиа; обмен заказами и ценами решает тот же плагин, но здесь они не являются главным сценарием.
Ограничения
- Выгрузка изображений может оказаться неполной даже при успешном HTTP-ответе. Её объём нужно сравнивать с ранее принятой выгрузкой.
- Отсутствие изображения в общем списке ещё не доказывает, что оно удалено: адресный запрос может вернуть файл, ошибку или неоднозначный ответ.
- У варианта товара есть основное фото, галерея и дополнительные изображения. Часть файлов могла быть добавлена вручную или использоваться в других записях WordPress.
- Файловое удаление необратимо. Один запуск должен иметь предел по времени, числу проверяемых товаров и числу удаляемых файлов.
Архитектура
Плановый импорт / обновление по SKU
│
▼
API учётной системы: список изображений
├── Проверка структуры ответа
├── Загрузка и привязка изображений к вариациям
└── Сверка прежних привязок
├── Сравнение объёма с предыдущей выгрузкой
├── Выбор кандидатов ограниченной порцией
├── Адресная проверка основных изображений
│ ├── Доступно → сохранить
│ ├── Неизвестно → пропустить
│ └── Отсутствует → проверить право на удаление
├── Снятие привязок; удаление только свободных файлов
└── Журнал решений и отложенных удалений
│
▼
WooCommerce: изображения вариаций и статус товара
├── Нет основного фото ни у одного варианта → скрыть
└── Фото восстановлено → вернуть только скрытое этим обменомОсновной импорт и удаление устаревших привязок выполняют разные части плагина. Сверка использует список API как источник кандидатов, а окончательное решение о снятии изображения принимает после дополнительных проверок.
Реализация
Импорт связывает изображения из API с вариантами товара, собирает главное фото и галерею из разных типов изображений. Перед заменой запоминает прежние ID вложений. После обновления файла, который больше не используется в галерее, проверяет ссылки на него в метаданных и только затем удаляет.
Для отдельной сверки хранится размер последней принятой полной выгрузки: число строк и уникальных товаров. Первый полный проход устанавливает исходный уровень и не выполняет удаление. Если следующий список сократился более чем на 20% по любому из этих показателей, сверка продолжает искать подозрительные записи, но не меняет привязки и файлы. Адресный запуск по SKU не сравнивается с полным каталогом.
Кандидаты выбираются из вариантов, у которых уже есть изображения, но в новом списке отсутствует товар или его основные фотографии. Для каждого кандидата выполняются свежие запросы к двум основным изображениям. Состояния разделены на «доступно», «отсутствует» и «неизвестно». Отсутствием считается только ответ, соответствующий контракту API: HTTP 200 с явно нулевой длиной. Ошибка сети, HTTP 404 и пустой ответ без подтверждённой длины не дают права снять изображение.
При подтверждённом отсутствии обработчик сохраняет изображения, которые ещё указаны в выгрузке, и снимает только привязки файлов, распознанных как созданные этим импортом. Перед физическим удалением повторно проверяются ссылки на вложение в метаданных записей, галерей и категорий. Если запрос к базе не удался или ссылка осталась, файл сохраняется. Для прохода предусмотрены блокировка параллельного запуска, лимиты времени и количества кандидатов и отдельный лимит на удаление файлов. Не поместившиеся в лимит удаления откладываются; при повторе право удалить файл проверяется заново.
Если после снятия изображений ни у одного варианта не осталось основного фото, родительский товар переводится в черновик с отметкой о причине. После восстановления фото плагин публикует только товар с этой отметкой: вручную скрытые товары не возвращаются на витрину по ошибке.
Сбои и диагностика
Журнал фиксирует объём ответа API, срабатывание проверки на резкое сокращение выгрузки, остановку по лимиту времени, число найденных и обработанных кандидатов, причины пропуска, снятые привязки и удалённые файлы. Детали по SKU и ID сохраняются порциями, чтобы длинный список не переполнил поле журнала. Отдельный отчёт по товару сопоставляет данные API с условиями видимости в WooCommerce: наличие товара, основных фото, цены, остатка и нужных свойств.
По этим данным можно отличить проблему внешней выгрузки от отсутствия конкретного изображения, ручного фото или правила видимости товара. Неоднозначный ответ API оставляет привязку на месте и попадает в причины пропуска, а не превращается в удаление.
границы решения
Проверка сокращения выгрузки защищает проход по отсутствующим изображениям. Основной импорт обновляет уже перечисленные в ответе товары до этой проверки; неполный набор изображений внутри одного товара требует отдельной защиты. Порог в 20% обнаруживает крупный провал выгрузки, но сам по себе не доказывает полноту ответа. При удалении используются текущие ссылки WordPress и признаки происхождения файла; операции чтения, снятия привязки и удаления не объединены в одну транзакцию.
Результат
Обновление изображений учитывает разницу между отсутствием файла и ненадёжным ответом API. Массовое сокращение выгрузки останавливает удаляющий проход, адресная проверка защищает отдельные товары, а журнал объясняет каждое принятое или отложенное решение. Видимость родительского товара связана с фото вариантов и восстанавливается только для товаров, скрытых этим механизмом.
Стек
PHP · WordPress · WooCommerce · REST API · MySQL · WP-Cron
Есть похожая задача?
Расскажите о текущей системе и нужных изменениях — обсудим следующий шаг.